forked from TrueCloudLab/neoneo-go
Merge pull request #2848 from nspcc-dev/tune-management-callflags-for-aspidochelone
Tune management callflags for aspidochelone
This commit is contained in:
commit
5fb9e1353d
3 changed files with 61 additions and 11 deletions
|
@ -341,7 +341,7 @@ protocol-related settings described in the table below.
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| CommitteeHistory | map[uint32]int | none | Number of committee members after the given height, for example `{0: 1, 20: 4}` sets up a chain with one committee member since the genesis and then changes the setting to 4 committee members at the height of 20. `StandbyCommittee` committee setting must have the number of keys equal or exceeding the highest value in this option. Blocks numbers where the change happens must be divisible by the old and by the new values simultaneously. If not set, committee size is derived from the `StandbyCommittee` setting and never changes. |
|
| CommitteeHistory | map[uint32]int | none | Number of committee members after the given height, for example `{0: 1, 20: 4}` sets up a chain with one committee member since the genesis and then changes the setting to 4 committee members at the height of 20. `StandbyCommittee` committee setting must have the number of keys equal or exceeding the highest value in this option. Blocks numbers where the change happens must be divisible by the old and by the new values simultaneously. If not set, committee size is derived from the `StandbyCommittee` setting and never changes. |
|
||||||
| GarbageCollectionPeriod | `uint32` | 10000 | Controls MPT garbage collection interval (in blocks) for configurations with `RemoveUntraceableBlocks` enabled and `KeepOnlyLatestState` disabled. In this mode the node stores a number of MPT trees (corresponding to `MaxTraceableBlocks` and `StateSyncInterval`), but the DB needs to be clean from old entries from time to time. Doing it too often will cause too much processing overhead, doing it too rarely will leave more useless data in the DB. This setting is deprecated in favor of the same setting in the ApplicationConfiguration and will be removed in future node versions. If both settings are used, ApplicationConfiguration is prioritized over this one. |
|
| GarbageCollectionPeriod | `uint32` | 10000 | Controls MPT garbage collection interval (in blocks) for configurations with `RemoveUntraceableBlocks` enabled and `KeepOnlyLatestState` disabled. In this mode the node stores a number of MPT trees (corresponding to `MaxTraceableBlocks` and `StateSyncInterval`), but the DB needs to be clean from old entries from time to time. Doing it too often will cause too much processing overhead, doing it too rarely will leave more useless data in the DB. This setting is deprecated in favor of the same setting in the ApplicationConfiguration and will be removed in future node versions. If both settings are used, ApplicationConfiguration is prioritized over this one. |
|
||||||
| Hardforks | `map[string]uint32` | [] | The set of incompatible changes that affect node behaviour starting from the specified height. The default value is an empty set which should be interpreted as "each known hard-fork is applied from the zero blockchain height". The list of valid hard-fork names:<br>• `Aspidochelone` represents hard-fork introduced in [#2469](https://github.com/nspcc-dev/neo-go/pull/2469) (ported from the [reference](https://github.com/neo-project/neo/pull/2712)). It adjusts the prices of `System.Contract.CreateStandardAccount` and `System.Contract.CreateMultisigAccount` interops so that the resulting prices are in accordance with `sha256` method of native `CryptoLib` contract. `Aspidochelone` is also includes [#2519](https://github.com/nspcc-dev/neo-go/pull/2519) (ported from the [reference](https://github.com/neo-project/neo/pull/2749)). It adjusts the price of `System.Runtime.GetRandom` interop and fixes its vulnerability. |
|
| Hardforks | `map[string]uint32` | [] | The set of incompatible changes that affect node behaviour starting from the specified height. The default value is an empty set which should be interpreted as "each known hard-fork is applied from the zero blockchain height". The list of valid hard-fork names:<br>• `Aspidochelone` represents hard-fork introduced in [#2469](https://github.com/nspcc-dev/neo-go/pull/2469) (ported from the [reference](https://github.com/neo-project/neo/pull/2712)). It adjusts the prices of `System.Contract.CreateStandardAccount` and `System.Contract.CreateMultisigAccount` interops so that the resulting prices are in accordance with `sha256` method of native `CryptoLib` contract. It also includes [#2519](https://github.com/nspcc-dev/neo-go/pull/2519) (ported from the [reference](https://github.com/neo-project/neo/pull/2749)) that adjusts the price of `System.Runtime.GetRandom` interop and fixes its vulnerability. A special NeoGo-specific change is included as well for ContractManagement's update/deploy call flags behaviour to be compatible with pre-0.99.0 behaviour that was changed because of the [3.2.0 protocol change](https://github.com/neo-project/neo/pull/2653). |
|
||||||
| KeepOnlyLatestState | `bool` | `false` | Specifies if MPT should only store the latest state (or a set of latest states, see `P2PStateExcangeExtensions` section for details). If true, DB size will be smaller, but older roots won't be accessible. This value should remain the same for the same database. | This setting is deprecated in favor of the same setting in the ApplicationConfiguration and will be removed in future node versions. If both settings are used, setting any of them to true enables the function. |
|
| KeepOnlyLatestState | `bool` | `false` | Specifies if MPT should only store the latest state (or a set of latest states, see `P2PStateExcangeExtensions` section for details). If true, DB size will be smaller, but older roots won't be accessible. This value should remain the same for the same database. | This setting is deprecated in favor of the same setting in the ApplicationConfiguration and will be removed in future node versions. If both settings are used, setting any of them to true enables the function. |
|
||||||
| Magic | `uint32` | `0` | Magic number which uniquely identifies Neo network. |
|
| Magic | `uint32` | `0` | Magic number which uniquely identifies Neo network. |
|
||||||
| MaxBlockSize | `uint32` | `262144` | Maximum block size in bytes. |
|
| MaxBlockSize | `uint32` | `262144` | Maximum block size in bytes. |
|
||||||
|
|
|
@ -4,8 +4,10 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"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/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
)
|
)
|
||||||
|
@ -16,31 +18,37 @@ func Call(ic *interop.Context) error {
|
||||||
if version != 0 {
|
if version != 0 {
|
||||||
return fmt.Errorf("native contract of version %d is not active", version)
|
return fmt.Errorf("native contract of version %d is not active", version)
|
||||||
}
|
}
|
||||||
var c interop.Contract
|
var meta *interop.ContractMD
|
||||||
curr := ic.VM.GetCurrentScriptHash()
|
curr := ic.VM.GetCurrentScriptHash()
|
||||||
for _, ctr := range ic.Natives {
|
for _, ctr := range ic.Natives {
|
||||||
if ctr.Metadata().Hash == curr {
|
m := ctr.Metadata()
|
||||||
c = ctr
|
if m.Hash == curr {
|
||||||
|
meta = m
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c == nil {
|
if meta == nil {
|
||||||
return fmt.Errorf("native contract %s (version %d) not found", curr.StringLE(), version)
|
return fmt.Errorf("native contract %s (version %d) not found", curr.StringLE(), version)
|
||||||
}
|
}
|
||||||
history := c.Metadata().UpdateHistory
|
history := meta.UpdateHistory
|
||||||
if len(history) == 0 {
|
if len(history) == 0 {
|
||||||
return fmt.Errorf("native contract %s is disabled", c.Metadata().Name)
|
return fmt.Errorf("native contract %s is disabled", meta.Name)
|
||||||
}
|
}
|
||||||
if history[0] > ic.BlockHeight() {
|
if history[0] > ic.BlockHeight() {
|
||||||
return fmt.Errorf("native contract %s is active after height = %d", c.Metadata().Name, history[0])
|
return fmt.Errorf("native contract %s is active after height = %d", meta.Name, history[0])
|
||||||
}
|
}
|
||||||
m, ok := c.Metadata().GetMethodByOffset(ic.VM.Context().IP())
|
m, ok := meta.GetMethodByOffset(ic.VM.Context().IP())
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("method not found")
|
return fmt.Errorf("method not found")
|
||||||
}
|
}
|
||||||
if !ic.VM.Context().GetCallFlags().Has(m.RequiredFlags) {
|
reqFlags := m.RequiredFlags
|
||||||
|
if !ic.IsHardforkEnabled(config.HFAspidochelone) && meta.ID == ManagementContractID &&
|
||||||
|
(m.MD.Name == "deploy" || m.MD.Name == "update") {
|
||||||
|
reqFlags &= callflag.States | callflag.AllowNotify
|
||||||
|
}
|
||||||
|
if !ic.VM.Context().GetCallFlags().Has(reqFlags) {
|
||||||
return fmt.Errorf("missing call flags for native %d `%s` operation call: %05b vs %05b",
|
return fmt.Errorf("missing call flags for native %d `%s` operation call: %05b vs %05b",
|
||||||
version, m.MD.Name, ic.VM.Context().GetCallFlags(), m.RequiredFlags)
|
version, m.MD.Name, ic.VM.Context().GetCallFlags(), reqFlags)
|
||||||
}
|
}
|
||||||
invokeFee := m.CPUFee*ic.BaseExecFee() +
|
invokeFee := m.CPUFee*ic.BaseExecFee() +
|
||||||
m.StorageFee*ic.BaseStorageFee()
|
m.StorageFee*ic.BaseStorageFee()
|
||||||
|
|
|
@ -132,6 +132,48 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
|
||||||
require.Equal(t, hash.RipeMD160(input).BytesBE(), value)
|
require.Equal(t, hash.RipeMD160(input).BytesBE(), value)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
manState := bc.GetContractState(e.NativeHash(t, nativenames.Management))
|
||||||
|
require.NotNil(t, manState)
|
||||||
|
mdDeploy := manState.Manifest.ABI.GetMethod("deploy", 2)
|
||||||
|
require.NotNil(t, mdDeploy)
|
||||||
|
t.Run("fail, bad call flag", func(t *testing.T) {
|
||||||
|
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
v := ic.SpawnVM()
|
||||||
|
v.LoadScriptWithHash(manState.NEF.Script, manState.Hash, callflag.States|callflag.AllowNotify)
|
||||||
|
input := []byte{1, 2, 3, 4}
|
||||||
|
v.Estack().PushVal(input)
|
||||||
|
v.Estack().PushVal(input)
|
||||||
|
v.Context().Jump(mdDeploy.Offset)
|
||||||
|
|
||||||
|
// Can't call with these flags, Aspidochelone is active.
|
||||||
|
err = v.Run()
|
||||||
|
require.Error(t, err)
|
||||||
|
require.True(t, strings.Contains(err.Error(), "missing call flags for native 0 `deploy` operation call"))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("good, pre-aspidochelone deploy", func(t *testing.T) {
|
||||||
|
bc, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
|
||||||
|
c.Hardforks = map[string]uint32{
|
||||||
|
config.HFAspidochelone.String(): 100500,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
v := ic.SpawnVM()
|
||||||
|
v.LoadScriptWithHash(manState.NEF.Script, manState.Hash, callflag.States|callflag.AllowNotify)
|
||||||
|
input := []byte{1, 2, 3, 4}
|
||||||
|
v.Estack().PushVal(input)
|
||||||
|
v.Estack().PushVal(input)
|
||||||
|
v.Context().Jump(mdDeploy.Offset)
|
||||||
|
|
||||||
|
// We have an invalid input, but call flags are OK.
|
||||||
|
err = v.Run()
|
||||||
|
require.Error(t, err)
|
||||||
|
require.True(t, strings.Contains(err.Error(), "invalid NEF file"))
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("success", func(t *testing.T) {
|
t.Run("success", func(t *testing.T) {
|
||||||
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
|
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
Loading…
Reference in a new issue