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. |
|
| 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. |
|
| 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. |
|
| 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`). |
|
| 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. |
|
| 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. |
|
| 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())
|
return fmt.Errorf("%w: conflicting transaction %s is already on chain", ErrInvalidAttribute, conflicts.Hash.StringLE())
|
||||||
}
|
}
|
||||||
case transaction.NotaryAssistedT:
|
case transaction.NotaryAssistedT:
|
||||||
if !bc.config.P2PSigExtensions {
|
if !bc.isHardforkEnabled(&transaction.NotaryAssistedActivation, bc.BlockHeight()) {
|
||||||
return fmt.Errorf("%w: NotaryAssisted attribute was found, but P2PSigExtensions are disabled", ErrInvalidAttribute)
|
return fmt.Errorf("%w: NotaryAssisted attribute was found, but %s is not active yet", ErrInvalidAttribute, transaction.NotaryAssistedActivation)
|
||||||
}
|
}
|
||||||
if !tx.HasSigner(nativehashes.Notary) {
|
if !tx.HasSigner(nativehashes.Notary) {
|
||||||
return fmt.Errorf("%w: NotaryAssisted attribute was found, but transaction is not signed by the Notary native contract", ErrInvalidAttribute)
|
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) {
|
t.Run("Disabled", func(t *testing.T) {
|
||||||
bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
|
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
|
c.ReservedAttributes = false
|
||||||
})
|
})
|
||||||
eBad := neotest.NewExecutor(t, bcBad, validatorBad, committeeBad)
|
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)
|
eBad.SignTx(t, tx, 1_0000_0000, eBad.Committee)
|
||||||
err := bcBad.VerifyTx(tx)
|
err := bcBad.VerifyTx(tx)
|
||||||
require.Error(t, err)
|
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) {
|
t.Run("Enabled, insufficient network fee", func(t *testing.T) {
|
||||||
tx := getNotaryAssistedTx(e, 1, 0)
|
tx := getNotaryAssistedTx(e, 1, 0)
|
||||||
|
|
|
@ -72,9 +72,9 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts {
|
||||||
cs.Ledger = ledger
|
cs.Ledger = ledger
|
||||||
cs.Contracts = append(cs.Contracts, ledger)
|
cs.Contracts = append(cs.Contracts, ledger)
|
||||||
|
|
||||||
gas := newGAS(int64(cfg.InitialGASSupply), cfg.P2PSigExtensions)
|
gas := newGAS(int64(cfg.InitialGASSupply))
|
||||||
neo := newNEO(cfg)
|
neo := newNEO(cfg)
|
||||||
policy := newPolicy(cfg.P2PSigExtensions)
|
policy := newPolicy()
|
||||||
neo.GAS = gas
|
neo.GAS = gas
|
||||||
neo.Policy = policy
|
neo.Policy = policy
|
||||||
gas.NEO = neo
|
gas.NEO = neo
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
|
|
||||||
func TestDeployGetUpdateDestroyContract(t *testing.T) {
|
func TestDeployGetUpdateDestroyContract(t *testing.T) {
|
||||||
mgmt := newManagement()
|
mgmt := newManagement()
|
||||||
mgmt.Policy = newPolicy(false)
|
mgmt.Policy = newPolicy()
|
||||||
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
||||||
ic := &interop.Context{DAO: d}
|
ic := &interop.Context{DAO: d}
|
||||||
err := mgmt.Initialize(ic, nil, nil)
|
err := mgmt.Initialize(ic, nil, nil)
|
||||||
|
@ -95,7 +95,7 @@ func TestManagement_Initialize(t *testing.T) {
|
||||||
|
|
||||||
func TestManagement_GetNEP17Contracts(t *testing.T) {
|
func TestManagement_GetNEP17Contracts(t *testing.T) {
|
||||||
mgmt := newManagement()
|
mgmt := newManagement()
|
||||||
mgmt.Policy = newPolicy(false)
|
mgmt.Policy = newPolicy()
|
||||||
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
d := dao.NewSimple(storage.NewMemoryStore(), false)
|
||||||
err := mgmt.Initialize(&interop.Context{DAO: d}, nil, nil)
|
err := mgmt.Initialize(&interop.Context{DAO: d}, nil, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -22,8 +22,7 @@ type GAS struct {
|
||||||
NEO *NEO
|
NEO *NEO
|
||||||
Policy *Policy
|
Policy *Policy
|
||||||
|
|
||||||
initialSupply int64
|
initialSupply int64
|
||||||
p2pSigExtensionsEnabled bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const gasContractID = -6
|
const gasContractID = -6
|
||||||
|
@ -32,10 +31,9 @@ const gasContractID = -6
|
||||||
const GASFactor = NEOTotalSupply
|
const GASFactor = NEOTotalSupply
|
||||||
|
|
||||||
// newGAS returns GAS native contract.
|
// newGAS returns GAS native contract.
|
||||||
func newGAS(init int64, p2pSigExtensionsEnabled bool) *GAS {
|
func newGAS(init int64) *GAS {
|
||||||
g := &GAS{
|
g := &GAS{
|
||||||
initialSupply: init,
|
initialSupply: init,
|
||||||
p2pSigExtensionsEnabled: p2pSigExtensionsEnabled,
|
|
||||||
}
|
}
|
||||||
defer g.BuildHFSpecificMD(g.ActiveIn())
|
defer g.BuildHFSpecificMD(g.ActiveIn())
|
||||||
|
|
||||||
|
@ -122,14 +120,12 @@ func (g *GAS) OnPersist(ic *interop.Context) error {
|
||||||
var netFee int64
|
var netFee int64
|
||||||
for _, tx := range ic.Block.Transactions {
|
for _, tx := range ic.Block.Transactions {
|
||||||
netFee += tx.NetworkFee
|
netFee += tx.NetworkFee
|
||||||
if g.p2pSigExtensionsEnabled {
|
// Reward for NotaryAssisted attribute will be minted to designated notary nodes
|
||||||
// Reward for NotaryAssisted attribute will be minted to designated notary nodes
|
// by Notary contract.
|
||||||
// by Notary contract.
|
attrs := tx.GetAttributes(transaction.NotaryAssistedT)
|
||||||
attrs := tx.GetAttributes(transaction.NotaryAssistedT)
|
if len(attrs) != 0 {
|
||||||
if len(attrs) != 0 {
|
na := attrs[0].Value.(*transaction.NotaryAssisted)
|
||||||
na := attrs[0].Value.(*transaction.NotaryAssisted)
|
netFee -= (int64(na.NKeys) + 1) * g.Policy.GetAttributeFeeInternal(ic.DAO, transaction.NotaryAssistedT)
|
||||||
netFee -= (int64(na.NKeys) + 1) * g.Policy.GetAttributeFeeInternal(ic.DAO, transaction.NotaryAssistedT)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.mint(ic, primary, big.NewInt(int64(netFee)), false)
|
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.
|
// under assumption that hardforks from Aspidochelone to Echidna (included) are enabled.
|
||||||
echidnaCSS = map[string]string{
|
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.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.NoError(t, err)
|
||||||
require.Equal(t, 1, len(aer))
|
require.Equal(t, 1, len(aer))
|
||||||
expected = expected[:0]
|
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{
|
expected = append(expected, state.NotificationEvent{
|
||||||
ScriptHash: nativehashes.ContractManagement,
|
ScriptHash: nativehashes.ContractManagement,
|
||||||
Name: "Deploy",
|
Name: "Deploy",
|
||||||
|
|
|
@ -63,9 +63,6 @@ var (
|
||||||
type Policy struct {
|
type Policy struct {
|
||||||
interop.ContractMD
|
interop.ContractMD
|
||||||
NEO *NEO
|
NEO *NEO
|
||||||
|
|
||||||
// p2pSigExtensionsEnabled defines whether the P2P signature extensions logic is relevant.
|
|
||||||
p2pSigExtensionsEnabled bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PolicyCache struct {
|
type PolicyCache struct {
|
||||||
|
@ -100,11 +97,8 @@ func copyPolicyCache(src, dst *PolicyCache) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// newPolicy returns Policy native contract.
|
// newPolicy returns Policy native contract.
|
||||||
func newPolicy(p2pSigExtensionsEnabled bool) *Policy {
|
func newPolicy() *Policy {
|
||||||
p := &Policy{
|
p := &Policy{ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID)}
|
||||||
ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID),
|
|
||||||
p2pSigExtensionsEnabled: p2pSigExtensionsEnabled,
|
|
||||||
}
|
|
||||||
defer p.BuildHFSpecificMD(p.ActiveIn())
|
defer p.BuildHFSpecificMD(p.ActiveIn())
|
||||||
|
|
||||||
desc := newDescriptor("getFeePerByte", smartcontract.IntegerType)
|
desc := newDescriptor("getFeePerByte", smartcontract.IntegerType)
|
||||||
|
@ -136,13 +130,24 @@ func newPolicy(p2pSigExtensionsEnabled bool) *Policy {
|
||||||
|
|
||||||
desc = newDescriptor("getAttributeFee", smartcontract.IntegerType,
|
desc = newDescriptor("getAttributeFee", smartcontract.IntegerType,
|
||||||
manifest.NewParameter("attributeType", 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)
|
p.AddMethod(md, desc)
|
||||||
|
|
||||||
desc = newDescriptor("setAttributeFee", smartcontract.VoidType,
|
desc = newDescriptor("setAttributeFee", smartcontract.VoidType,
|
||||||
manifest.NewParameter("attributeType", smartcontract.IntegerType),
|
manifest.NewParameter("attributeType", smartcontract.IntegerType),
|
||||||
manifest.NewParameter("value", 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)
|
p.AddMethod(md, desc)
|
||||||
|
|
||||||
desc = newDescriptor("setFeePerByte", smartcontract.VoidType,
|
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.
|
// Initialize initializes Policy native contract and implements the Contract interface.
|
||||||
func (p *Policy) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error {
|
func (p *Policy) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error {
|
||||||
if hf != p.ActiveIn() {
|
if hf == p.ActiveIn() {
|
||||||
return nil
|
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)
|
cache := &PolicyCache{
|
||||||
setIntWithKey(p.ID, ic.DAO, execFeeFactorKey, defaultExecFeeFactor)
|
execFeeFactor: defaultExecFeeFactor,
|
||||||
setIntWithKey(p.ID, ic.DAO, storagePriceKey, DefaultStoragePrice)
|
feePerByte: defaultFeePerByte,
|
||||||
|
maxVerificationGas: defaultMaxVerificationGas,
|
||||||
cache := &PolicyCache{
|
storagePrice: DefaultStoragePrice,
|
||||||
execFeeFactor: defaultExecFeeFactor,
|
attributeFee: map[transaction.AttrType]uint32{},
|
||||||
feePerByte: defaultFeePerByte,
|
blockedAccounts: make([]util.Uint160, 0),
|
||||||
maxVerificationGas: defaultMaxVerificationGas,
|
}
|
||||||
storagePrice: DefaultStoragePrice,
|
ic.DAO.SetCache(p.ID, cache)
|
||||||
attributeFee: map[transaction.AttrType]uint32{},
|
|
||||||
blockedAccounts: make([]util.Uint160, 0),
|
|
||||||
}
|
}
|
||||||
if p.p2pSigExtensionsEnabled {
|
if hf != nil && *hf == transaction.NotaryAssistedActivation {
|
||||||
setIntWithKey(p.ID, ic.DAO, []byte{attributeFeePrefix, byte(transaction.NotaryAssistedT)}, defaultNotaryAssistedFee)
|
setIntWithKey(p.ID, ic.DAO, []byte{attributeFeePrefix, byte(transaction.NotaryAssistedT)}, defaultNotaryAssistedFee)
|
||||||
|
|
||||||
|
cache := ic.DAO.GetRWCache(p.ID).(*PolicyCache)
|
||||||
cache.attributeFee[transaction.NotaryAssistedT] = defaultNotaryAssistedFee
|
cache.attributeFee[transaction.NotaryAssistedT] = defaultNotaryAssistedFee
|
||||||
}
|
}
|
||||||
ic.DAO.SetCache(p.ID, cache)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -363,9 +368,18 @@ func (p *Policy) setStoragePrice(ic *interop.Context, args []stackitem.Item) sta
|
||||||
return stackitem.Null{}
|
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]))
|
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))
|
panic(fmt.Errorf("invalid attribute type: %d", t))
|
||||||
}
|
}
|
||||||
return stackitem.NewBigInteger(big.NewInt(p.GetAttributeFeeInternal(ic.DAO, 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)
|
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]))
|
t := transaction.AttrType(toUint8(args[0]))
|
||||||
value := toUint32(args[1])
|
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))
|
panic(fmt.Errorf("invalid attribute type: %d", t))
|
||||||
}
|
}
|
||||||
if value > maxAttributeFee {
|
if value > maxAttributeFee {
|
||||||
|
|
|
@ -4,9 +4,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"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/interop"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
"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/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"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -65,3 +68,51 @@ func TestPolicy_BlockedAccounts(t *testing.T) {
|
||||||
require.Equal(t, expectedErr, err.Error())
|
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
|
package transaction
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"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.
|
// NotaryAssisted represents attribute for notary service transactions.
|
||||||
type NotaryAssisted struct {
|
type NotaryAssisted struct {
|
||||||
NKeys uint8 `json:"nkeys"`
|
NKeys uint8 `json:"nkeys"`
|
||||||
|
|
Loading…
Reference in a new issue