mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-28 19:31:34 +00:00
core: move NotaryAssisted attribute out of P2PSigExtensions
Move it under Domovoi hardfork. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
parent
b735f2e924
commit
1c3644f9a5
10 changed files with 140 additions and 52 deletions
|
@ -341,7 +341,7 @@ protocol-related settings described in the table below.
|
|||
| MaxValidUntilBlockIncrement | `uint32` | `5760` | Upper height increment limit for transaction's ValidUntilBlock field value relative to the current blockchain height, exceeding which a transaction will fail validation. It is set to estimated daily number of blocks with 15s interval by default. |
|
||||
| MemPoolSize | `int` | `50000` | Size of the node's memory pool where transactions are stored before they are added to block. |
|
||||
| P2PNotaryRequestPayloadPoolSize | `int` | `1000` | Size of the node's P2P Notary request payloads memory pool where P2P Notary requests are stored before main or fallback transaction is completed and added to the chain.<br>This option is valid only if `P2PSigExtensions` are enabled. | Not supported by the C# node, thus may affect heterogeneous networks functionality. |
|
||||
| P2PSigExtensions | `bool` | `false` | Enables following additional Notary service related logic:<br>• Transaction attribute `NotaryAssisted`<br>• Network payload of the `P2PNotaryRequest` type<br>• Notary node module | Not supported by the C# node, thus may affect heterogeneous networks functionality. |
|
||||
| P2PSigExtensions | `bool` | `false` | Enables following additional Notary service related logic:<br>• Network payload of the `P2PNotaryRequest` type<br>• Notary node module | Not supported by the C# node, thus may affect heterogeneous networks functionality. |
|
||||
| P2PStateExchangeExtensions | `bool` | `false` | Enables the following P2P MPT state data exchange logic: <br>• `StateSyncInterval` protocol setting <br>• P2P commands `GetMPTDataCMD` and `MPTDataCMD` | Not supported by the C# node, thus may affect heterogeneous networks functionality. Can be supported either on MPT-complete node (`KeepOnlyLatestState`=`false`) or on light GC-enabled node (`RemoveUntraceableBlocks=true`) in which case `KeepOnlyLatestState` setting doesn't change the behavior, an appropriate set of MPTs is always stored (see `RemoveUntraceableBlocks`). |
|
||||
| ReservedAttributes | `bool` | `false` | Allows to have reserved attributes range for experimental or private purposes. |
|
||||
| SeedList | `[]string` | [] | List of initial nodes addresses used to establish connectivity. |
|
||||
|
|
|
@ -2697,8 +2697,8 @@ func (bc *Blockchain) verifyTxAttributes(d *dao.Simple, tx *transaction.Transact
|
|||
return fmt.Errorf("%w: conflicting transaction %s is already on chain", ErrInvalidAttribute, conflicts.Hash.StringLE())
|
||||
}
|
||||
case transaction.NotaryAssistedT:
|
||||
if !bc.config.P2PSigExtensions {
|
||||
return fmt.Errorf("%w: NotaryAssisted attribute was found, but P2PSigExtensions are disabled", ErrInvalidAttribute)
|
||||
if !bc.isHardforkEnabled(&transaction.NotaryAssistedActivation, bc.BlockHeight()) {
|
||||
return fmt.Errorf("%w: NotaryAssisted attribute was found, but %s is not active yet", ErrInvalidAttribute, transaction.NotaryAssistedActivation)
|
||||
}
|
||||
if !tx.HasSigner(nativehashes.Notary) {
|
||||
return fmt.Errorf("%w: NotaryAssisted attribute was found, but transaction is not signed by the Notary native contract", ErrInvalidAttribute)
|
||||
|
|
|
@ -2057,7 +2057,12 @@ func TestBlockchain_VerifyTx(t *testing.T) {
|
|||
}
|
||||
t.Run("Disabled", func(t *testing.T) {
|
||||
bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
|
||||
c.P2PSigExtensions = false
|
||||
c.P2PSigExtensions = true
|
||||
c.Hardforks = map[string]uint32{
|
||||
config.HFAspidochelone.String(): 0,
|
||||
config.HFBasilisk.String(): 0,
|
||||
config.HFCockatrice.String(): 0,
|
||||
}
|
||||
c.ReservedAttributes = false
|
||||
})
|
||||
eBad := neotest.NewExecutor(t, bcBad, validatorBad, committeeBad)
|
||||
|
@ -2069,7 +2074,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
|
|||
eBad.SignTx(t, tx, 1_0000_0000, eBad.Committee)
|
||||
err := bcBad.VerifyTx(tx)
|
||||
require.Error(t, err)
|
||||
require.True(t, strings.Contains(err.Error(), "invalid attribute: NotaryAssisted attribute was found, but P2PSigExtensions are disabled"))
|
||||
require.True(t, strings.Contains(err.Error(), "invalid attribute: NotaryAssisted attribute was found, but Echidna is not active yet"))
|
||||
})
|
||||
t.Run("Enabled, insufficient network fee", func(t *testing.T) {
|
||||
tx := getNotaryAssistedTx(e, 1, 0)
|
||||
|
|
|
@ -72,9 +72,9 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts {
|
|||
cs.Ledger = ledger
|
||||
cs.Contracts = append(cs.Contracts, ledger)
|
||||
|
||||
gas := newGAS(int64(cfg.InitialGASSupply), cfg.P2PSigExtensions)
|
||||
gas := newGAS(int64(cfg.InitialGASSupply))
|
||||
neo := newNEO(cfg)
|
||||
policy := newPolicy(cfg.P2PSigExtensions)
|
||||
policy := newPolicy()
|
||||
neo.GAS = gas
|
||||
neo.Policy = policy
|
||||
gas.NEO = neo
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
|
||||
func TestDeployGetUpdateDestroyContract(t *testing.T) {
|
||||
mgmt := newManagement()
|
||||
mgmt.Policy = newPolicy(false)
|
||||
mgmt.Policy = newPolicy()
|
||||
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
||||
ic := &interop.Context{DAO: d}
|
||||
err := mgmt.Initialize(ic, nil, nil)
|
||||
|
@ -95,7 +95,7 @@ func TestManagement_Initialize(t *testing.T) {
|
|||
|
||||
func TestManagement_GetNEP17Contracts(t *testing.T) {
|
||||
mgmt := newManagement()
|
||||
mgmt.Policy = newPolicy(false)
|
||||
mgmt.Policy = newPolicy()
|
||||
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
||||
err := mgmt.Initialize(&interop.Context{DAO: d}, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -22,8 +22,7 @@ type GAS struct {
|
|||
NEO *NEO
|
||||
Policy *Policy
|
||||
|
||||
initialSupply int64
|
||||
p2pSigExtensionsEnabled bool
|
||||
initialSupply int64
|
||||
}
|
||||
|
||||
const gasContractID = -6
|
||||
|
@ -32,10 +31,9 @@ const gasContractID = -6
|
|||
const GASFactor = NEOTotalSupply
|
||||
|
||||
// newGAS returns GAS native contract.
|
||||
func newGAS(init int64, p2pSigExtensionsEnabled bool) *GAS {
|
||||
func newGAS(init int64) *GAS {
|
||||
g := &GAS{
|
||||
initialSupply: init,
|
||||
p2pSigExtensionsEnabled: p2pSigExtensionsEnabled,
|
||||
initialSupply: init,
|
||||
}
|
||||
defer g.BuildHFSpecificMD(g.ActiveIn())
|
||||
|
||||
|
@ -122,14 +120,12 @@ func (g *GAS) OnPersist(ic *interop.Context) error {
|
|||
var netFee int64
|
||||
for _, tx := range ic.Block.Transactions {
|
||||
netFee += tx.NetworkFee
|
||||
if g.p2pSigExtensionsEnabled {
|
||||
// Reward for NotaryAssisted attribute will be minted to designated notary nodes
|
||||
// by Notary contract.
|
||||
attrs := tx.GetAttributes(transaction.NotaryAssistedT)
|
||||
if len(attrs) != 0 {
|
||||
na := attrs[0].Value.(*transaction.NotaryAssisted)
|
||||
netFee -= (int64(na.NKeys) + 1) * g.Policy.GetAttributeFeeInternal(ic.DAO, transaction.NotaryAssistedT)
|
||||
}
|
||||
// Reward for NotaryAssisted attribute will be minted to designated notary nodes
|
||||
// by Notary contract.
|
||||
attrs := tx.GetAttributes(transaction.NotaryAssistedT)
|
||||
if len(attrs) != 0 {
|
||||
na := attrs[0].Value.(*transaction.NotaryAssisted)
|
||||
netFee -= (int64(na.NKeys) + 1) * g.Policy.GetAttributeFeeInternal(ic.DAO, transaction.NotaryAssistedT)
|
||||
}
|
||||
}
|
||||
g.mint(ic, primary, big.NewInt(int64(netFee)), false)
|
||||
|
|
|
@ -58,6 +58,7 @@ var (
|
|||
// under assumption that hardforks from Aspidochelone to Echidna (included) are enabled.
|
||||
echidnaCSS = map[string]string{
|
||||
nativenames.Notary: `{"id":-10,"hash":"0xc1e14f19c3e60d0b9244d06dd7ba9b113135ec3b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"Notary","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"addr","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"expirationOf","offset":7,"parameters":[{"name":"addr","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"getMaxNotValidBeforeDelta","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"lockDepositUntil","offset":21,"parameters":[{"name":"address","type":"Hash160"},{"name":"till","type":"Integer"}],"returntype":"Boolean","safe":false},{"name":"onNEP17Payment","offset":28,"parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"setMaxNotValidBeforeDelta","offset":35,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"verify","offset":42,"parameters":[{"name":"signature","type":"Signature"}],"returntype":"Boolean","safe":true},{"name":"withdraw","offset":49,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
nativenames.Policy: `{"id":-7,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"PolicyContract","abi":{"methods":[{"name":"blockAccount","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false},{"name":"getAttributeFee","offset":7,"parameters":[{"name":"attributeType","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"getExecFeeFactor","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"getFeePerByte","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"getStoragePrice","offset":28,"parameters":[],"returntype":"Integer","safe":true},{"name":"isBlocked","offset":35,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":true},{"name":"setAttributeFee","offset":42,"parameters":[{"name":"attributeType","type":"Integer"},{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setExecFeeFactor","offset":49,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setFeePerByte","offset":56,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setStoragePrice","offset":63,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"unblockAccount","offset":70,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -255,6 +256,13 @@ func TestManagement_NativeDeployUpdateNotifications(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(aer))
|
||||
expected = expected[:0]
|
||||
expected = append(expected, state.NotificationEvent{
|
||||
ScriptHash: nativehashes.ContractManagement,
|
||||
Name: "Update",
|
||||
Item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(nativehashes.PolicyContract),
|
||||
}),
|
||||
})
|
||||
expected = append(expected, state.NotificationEvent{
|
||||
ScriptHash: nativehashes.ContractManagement,
|
||||
Name: "Deploy",
|
||||
|
|
|
@ -63,9 +63,6 @@ var (
|
|||
type Policy struct {
|
||||
interop.ContractMD
|
||||
NEO *NEO
|
||||
|
||||
// p2pSigExtensionsEnabled defines whether the P2P signature extensions logic is relevant.
|
||||
p2pSigExtensionsEnabled bool
|
||||
}
|
||||
|
||||
type PolicyCache struct {
|
||||
|
@ -100,11 +97,8 @@ func copyPolicyCache(src, dst *PolicyCache) {
|
|||
}
|
||||
|
||||
// newPolicy returns Policy native contract.
|
||||
func newPolicy(p2pSigExtensionsEnabled bool) *Policy {
|
||||
p := &Policy{
|
||||
ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID),
|
||||
p2pSigExtensionsEnabled: p2pSigExtensionsEnabled,
|
||||
}
|
||||
func newPolicy() *Policy {
|
||||
p := &Policy{ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID)}
|
||||
defer p.BuildHFSpecificMD(p.ActiveIn())
|
||||
|
||||
desc := newDescriptor("getFeePerByte", smartcontract.IntegerType)
|
||||
|
@ -136,13 +130,24 @@ func newPolicy(p2pSigExtensionsEnabled bool) *Policy {
|
|||
|
||||
desc = newDescriptor("getAttributeFee", smartcontract.IntegerType,
|
||||
manifest.NewParameter("attributeType", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.getAttributeFee, 1<<15, callflag.ReadStates)
|
||||
md = newMethodAndPrice(p.getAttributeFeeV0, 1<<15, callflag.ReadStates, config.HFDefault, transaction.NotaryAssistedActivation)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getAttributeFee", smartcontract.IntegerType,
|
||||
manifest.NewParameter("attributeType", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.getAttributeFeeV1, 1<<15, callflag.ReadStates, transaction.NotaryAssistedActivation)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setAttributeFee", smartcontract.VoidType,
|
||||
manifest.NewParameter("attributeType", smartcontract.IntegerType),
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setAttributeFee, 1<<15, callflag.States)
|
||||
md = newMethodAndPrice(p.setAttributeFeeV0, 1<<15, callflag.States, config.HFDefault, transaction.NotaryAssistedActivation)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setAttributeFee", smartcontract.VoidType,
|
||||
manifest.NewParameter("attributeType", smartcontract.IntegerType),
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setAttributeFeeV1, 1<<15, callflag.States, transaction.NotaryAssistedActivation)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setFeePerByte", smartcontract.VoidType,
|
||||
|
@ -170,27 +175,27 @@ func (p *Policy) Metadata() *interop.ContractMD {
|
|||
|
||||
// Initialize initializes Policy native contract and implements the Contract interface.
|
||||
func (p *Policy) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error {
|
||||
if hf != p.ActiveIn() {
|
||||
return nil
|
||||
}
|
||||
if hf == p.ActiveIn() {
|
||||
setIntWithKey(p.ID, ic.DAO, feePerByteKey, defaultFeePerByte)
|
||||
setIntWithKey(p.ID, ic.DAO, execFeeFactorKey, defaultExecFeeFactor)
|
||||
setIntWithKey(p.ID, ic.DAO, storagePriceKey, DefaultStoragePrice)
|
||||
|
||||
setIntWithKey(p.ID, ic.DAO, feePerByteKey, defaultFeePerByte)
|
||||
setIntWithKey(p.ID, ic.DAO, execFeeFactorKey, defaultExecFeeFactor)
|
||||
setIntWithKey(p.ID, ic.DAO, storagePriceKey, DefaultStoragePrice)
|
||||
|
||||
cache := &PolicyCache{
|
||||
execFeeFactor: defaultExecFeeFactor,
|
||||
feePerByte: defaultFeePerByte,
|
||||
maxVerificationGas: defaultMaxVerificationGas,
|
||||
storagePrice: DefaultStoragePrice,
|
||||
attributeFee: map[transaction.AttrType]uint32{},
|
||||
blockedAccounts: make([]util.Uint160, 0),
|
||||
cache := &PolicyCache{
|
||||
execFeeFactor: defaultExecFeeFactor,
|
||||
feePerByte: defaultFeePerByte,
|
||||
maxVerificationGas: defaultMaxVerificationGas,
|
||||
storagePrice: DefaultStoragePrice,
|
||||
attributeFee: map[transaction.AttrType]uint32{},
|
||||
blockedAccounts: make([]util.Uint160, 0),
|
||||
}
|
||||
ic.DAO.SetCache(p.ID, cache)
|
||||
}
|
||||
if p.p2pSigExtensionsEnabled {
|
||||
if hf != nil && *hf == transaction.NotaryAssistedActivation {
|
||||
setIntWithKey(p.ID, ic.DAO, []byte{attributeFeePrefix, byte(transaction.NotaryAssistedT)}, defaultNotaryAssistedFee)
|
||||
|
||||
cache := ic.DAO.GetRWCache(p.ID).(*PolicyCache)
|
||||
cache.attributeFee[transaction.NotaryAssistedT] = defaultNotaryAssistedFee
|
||||
}
|
||||
ic.DAO.SetCache(p.ID, cache)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -363,9 +368,18 @@ func (p *Policy) setStoragePrice(ic *interop.Context, args []stackitem.Item) sta
|
|||
return stackitem.Null{}
|
||||
}
|
||||
|
||||
func (p *Policy) getAttributeFee(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
func (p *Policy) getAttributeFeeV0(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
return p.getAttributeFeeGeneric(ic, args, false)
|
||||
}
|
||||
|
||||
func (p *Policy) getAttributeFeeV1(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
return p.getAttributeFeeGeneric(ic, args, true)
|
||||
}
|
||||
|
||||
func (p *Policy) getAttributeFeeGeneric(ic *interop.Context, args []stackitem.Item, allowNotaryAssisted bool) stackitem.Item {
|
||||
t := transaction.AttrType(toUint8(args[0]))
|
||||
if !transaction.IsValidAttrType(ic.Chain.GetConfig().ReservedAttributes, t) {
|
||||
if !transaction.IsValidAttrType(ic.Chain.GetConfig().ReservedAttributes, t) ||
|
||||
(!allowNotaryAssisted && t == transaction.NotaryAssistedT) {
|
||||
panic(fmt.Errorf("invalid attribute type: %d", t))
|
||||
}
|
||||
return stackitem.NewBigInteger(big.NewInt(p.GetAttributeFeeInternal(ic.DAO, t)))
|
||||
|
@ -382,10 +396,19 @@ func (p *Policy) GetAttributeFeeInternal(d *dao.Simple, t transaction.AttrType)
|
|||
return int64(v)
|
||||
}
|
||||
|
||||
func (p *Policy) setAttributeFee(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
func (p *Policy) setAttributeFeeV0(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
return p.setAttributeFeeGeneric(ic, args, false)
|
||||
}
|
||||
|
||||
func (p *Policy) setAttributeFeeV1(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
return p.setAttributeFeeGeneric(ic, args, true)
|
||||
}
|
||||
|
||||
func (p *Policy) setAttributeFeeGeneric(ic *interop.Context, args []stackitem.Item, allowNotaryAssisted bool) stackitem.Item {
|
||||
t := transaction.AttrType(toUint8(args[0]))
|
||||
value := toUint32(args[1])
|
||||
if !transaction.IsValidAttrType(ic.Chain.GetConfig().ReservedAttributes, t) {
|
||||
if !transaction.IsValidAttrType(ic.Chain.GetConfig().ReservedAttributes, t) ||
|
||||
(!allowNotaryAssisted && t == transaction.NotaryAssistedT) {
|
||||
panic(fmt.Errorf("invalid attribute type: %d", t))
|
||||
}
|
||||
if value > maxAttributeFee {
|
||||
|
|
|
@ -4,9 +4,12 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -65,3 +68,51 @@ func TestPolicy_BlockedAccounts(t *testing.T) {
|
|||
require.Equal(t, expectedErr, err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicy_GetNotaryFeePerKey(t *testing.T) {
|
||||
const echidnaHeight = 4
|
||||
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
|
||||
c.Hardforks = map[string]uint32{
|
||||
config.HFEchidna.String(): echidnaHeight,
|
||||
}
|
||||
})
|
||||
e := neotest.NewExecutor(t, bc, acc, acc)
|
||||
p := e.CommitteeInvoker(nativehashes.PolicyContract)
|
||||
|
||||
// Invoke before Echidna should fail.
|
||||
p.InvokeFail(t, "invalid attribute type: 34", "getAttributeFee", int64(transaction.NotaryAssistedT))
|
||||
|
||||
for e.Chain.BlockHeight() < echidnaHeight-1 {
|
||||
e.AddNewBlock(t)
|
||||
}
|
||||
|
||||
// Invoke at Echidna should return the default value.
|
||||
p.Invoke(t, 1000_0000, "getAttributeFee", int64(transaction.NotaryAssistedT))
|
||||
|
||||
// Invoke after Echidna should return the default value.
|
||||
p.Invoke(t, 1000_0000, "getAttributeFee", int64(transaction.NotaryAssistedT))
|
||||
}
|
||||
|
||||
func TestPolicy_SetNotaryFeePerKey(t *testing.T) {
|
||||
const echidnaHeight = 4
|
||||
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
|
||||
c.Hardforks = map[string]uint32{
|
||||
config.HFEchidna.String(): echidnaHeight,
|
||||
}
|
||||
})
|
||||
e := neotest.NewExecutor(t, bc, acc, acc)
|
||||
p := e.CommitteeInvoker(nativehashes.PolicyContract)
|
||||
|
||||
// Invoke before Echidna should fail.
|
||||
p.InvokeFail(t, "invalid attribute type: 34", "setAttributeFee", int64(transaction.NotaryAssistedT), 500_0000)
|
||||
|
||||
for e.Chain.BlockHeight() < echidnaHeight-1 {
|
||||
e.AddNewBlock(t)
|
||||
}
|
||||
|
||||
// Invoke at Echidna should return the default value.
|
||||
p.Invoke(t, nil, "setAttributeFee", int64(transaction.NotaryAssistedT), 500_0000)
|
||||
|
||||
// Invoke after Echidna should return the default value.
|
||||
p.Invoke(t, nil, "setAttributeFee", int64(transaction.NotaryAssistedT), 510_0000)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
)
|
||||
|
||||
// NotaryAssistedActivation stores the hardfork of NotaryAssisted transaction attribute
|
||||
// activation.
|
||||
var NotaryAssistedActivation = config.HFEchidna
|
||||
|
||||
// NotaryAssisted represents attribute for notary service transactions.
|
||||
type NotaryAssisted struct {
|
||||
NKeys uint8 `json:"nkeys"`
|
||||
|
|
Loading…
Reference in a new issue