Compare commits

..

9 commits

Author SHA1 Message Date
Roman Khimov
ce7bc26a64 native: use ABORT in Koblitz multisig
Make the script a bit shorter. ABORTMSG would cost a bit more.
2024-05-03 15:35:10 +03:00
Roman Khimov
7bce46d8c8 native: make multisig koblitz easier to parse
1. Make prologue be exactly the same as regular CheckMultisig.
2. But instead of "SYSCALL System.Crypto.CheckMultisig" do INITSLOT and K check.
3. This makes all of the code from INITSLOT below be independent of N/M, so
   one can parse the script beginning in the same way CheckMultisig is parsed and
   then just compare the rest of it with some known-good blob.
4. The script becomes a tiny bit larger now, but properties above are too good.
2024-05-03 15:32:27 +03:00
Anna Shaleva
18a4f0b928 rpcsrv: test calculatenetworkfee with custom Koblitz-based witness
Value calculated by calculatenetworkfee is enough to pass the real
tx verification. However, network fee may be decreased, so calculations
are not quite accurate. Need to investigate, why.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-03 12:36:03 +03:00
Anna Shaleva
37d0e73a3f *: update interop deps
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-03 12:20:47 +03:00
Anna Shaleva
fab5893b95 native: add test for multisignature Koblitz witness verification
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-03 12:20:46 +03:00
Anna Shaleva
ee8ae6a8d5 native: add preferable method to TestCryptoLib_KoblitzVerificationScript
It's based on the constant-length network magic, ref.
https://github.com/nspcc-dev/neo-go/pull/3425#discussion_r1582068061.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-03 12:07:56 +03:00
Anna Shaleva
7b660d0dcd crypto: export GetSignedData function
It's needed for tests and further custom verification script build.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-03 12:07:56 +03:00
Anna Shaleva
1e2b438b55 native: extend CryptoLib's verifyWithECDsa with hasher parameter
Replace native CryptoLib's verifyWithECDsa `curve` parameter by
`curveHash` parameter which is a enum over supported pairs of named
curves and hash functions.

Even though this change is a compatible extension of the protocol, it
changes the genesis state due to parameter renaming. But we're going to
resync chain in 3.7 release anyway, so it's not a big deal.

Also, we need to check mainnet and testnet compatibility in case if
anyone has ever called verifyWithECDsa with 24 or 25 `curve` value.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-03 12:07:56 +03:00
Anna Shaleva
17a99aa427 native: add test for custom Koblitz witness verification script
Every single thing is already implemented in the protocol for Koblitz
verification scripts.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2024-05-01 15:50:17 +03:00
110 changed files with 455 additions and 1722 deletions

View file

@ -8,7 +8,7 @@ on:
- master - master
types: [opened, synchronize] types: [opened, synchronize]
paths-ignore: paths-ignore:
- 'scripts/*.sh' - 'scripts/**'
- '**/*.md' - '**/*.md'
workflow_dispatch: workflow_dispatch:
@ -39,14 +39,6 @@ jobs:
- name: Check dependencies - name: Check dependencies
run: | run: |
./scripts/check_deps.sh ./scripts/check_deps.sh
- name: Check go.mod is tidy
run: |
go mod tidy
if [[ $(git diff --name-only go.* | grep '' -c) != 0 ]]; then
echo "go mod tidy should be executed before the merge, following packages are unused or out of date:";
git diff go.*;
exit 1;
fi
codegencheck: codegencheck:
name: Check code generated with 'go generate' is up-to-date name: Check code generated with 'go generate' is up-to-date

View file

@ -2,119 +2,6 @@
This document outlines major changes between releases. This document outlines major changes between releases.
## 0.106.1 "Implication" (3 Jun 2024)
An urgent release that fixes mainnet state difference at block 5462944 which halts
blocks processing starting from the height 5468658. This release requires full node
DB resynchronization for mainnet nodes. T5 testnet DB state is not affected by this
bug (at least up to the current 4087361 height). Thus, DB resynchronisation may be
skipped for testnet nodes. No configuration changes implied.
Bugs fixed:
* mainnet state difference at block 5462944 caused by runtime notification
permissions check against the updated contract state instead of executing state
(#3472)
* unused neofs-contract dependency in the node modules (#3458)
## 0.106.0 "Zephyranthes" (21 May 2024)
We're rolling out a large set of updates including all of Neo 3.7.4 protocol changes:
native contracts update functionality and extended native contract APIs united under
the upcoming Cockatrice hardfork. For smart contract developers an ability to
generate smart contract bindings with dynamic hash is supported as well as a number
of useful extensions for `unwrap` package, compatible NNS smart contract RPC binding
and a lot of other handy enhancements. This release also includes a couple of severe
regression bug fixes affecting the node state. As a bonus of fixing a wide range of
failing tests, we've refactored the node services start and shutdown procedures to
make it more stable. This version drops support for Go 1.19 and requires 1.20+ to
build (with Go 1.22 supported).
Notice that this release requires full node resynchronization for both mainnet
and testnet nodes. Please pay a special attention to the Cockatrice hardfork schedule
and check your configurations. It should be configured for 3967000 of T5 testnet and
5450000 of mainnet. To ensure compatibility your node must be configured
appropriately.
New features:
* native contracts update functionality bound to hardforks (#3402, #3444)
* Cockatrice hardfork planned for 5450000 block of mainnet and 3967000 block of T5
testnet (#3402, #3448, #3402, #3446)
* `CommitteeChanged` events are emitted by NeoToken native contract starting from
Cockatrice hardfork (#3351, #3448)
* `getCommitteeAddress` method of NeoToken native contract is available starting
from Cockatrice hardfork (#3362, #3402)
* `keccak256` method of CryptoLib native contract is available starting from
Cockatrice hardfork (#3301, #3402)
* dynamic contract hash support for smart contract bindings (#3405)
* support `StringCompressed` API for `crypto.PublicKey` (#3408)
* support `Copy` API for `transaction.Transaction` and `payload.P2PNotaryRequest`
(#3407)
* extend `verifyWithECDsa` method of native CryptoLib contract with Keccak256 hasher
starting from Cockatrice and add an example of custom Koblitz-based and
Keccak256-based transaction witness verification (#3425)
* autogenerated `nativehashes` package (#3402, #3431)
* introduce `unwrap.Exception` type for better RPC invocation result exceptions
detection (#3438)
Behavior changes:
* Neo Name Service smart contract RPC binding follows the official N3 implementation
(#3291)
* clear LastGasPerVote NeoToken account info on unvoting (#3349)
* return fault exception (if any) in `unwrap` RPC client helpers (#3356)
* move P2PNotary designation role out of P2PSigExtensions (#3452)
Improvements:
* support `smartcontract.Convertible` interface as RPC Actor and Invoker call
parameters (#3297)
* allow to import multisignature account into wallet without WIF and password
specified (#3293)
* upgrade go-ordered-json dependency to avoid possible node state incompatibility
issues caused by smart contract manifest marshalling (#3331, #3333)
* Go 1.22 support, bump minimum required Go version up to Go 1.20 (#3336)
* a number of dependent libraries are updated to the fresh versions (#3338, #3418)
* improve error message of `System.Crypto.CheckMultisig` interop API handler (#3374)
* upgrade dBFT library to v0.2.0 (#3371, #3413)
* increase `ValidUntilBlock` value for transactions generated by CLI commands
(#3376)
* documentation updates (#3375, #3382)
* let default Notary Actor options be customizable (#3394)
* extend `getversion` RPC response with RPC server settings (#3386)
* make errors related to wallet opening more detailed (#3389)
* adjust error messages of `setExecFeeFactor` and `setStoragePrice` methods of
native PolicyContract (#3406)
* make neotest chain constructor options customizable (#3404)
* format improvements for CLI commands description (#3410)
* make state dumps comparator script more verbose (#3411)
* refactor storage `Get` implementation for BoltDB (#3441)
* add `updatecounter` field to the resulting items of `getnativecontracts` RPC API
call (#3439)
Bugs fixed:
* node panic on committee missing from node configuration (#3294)
* autogenerated RPC bindings do not follow Go naming convention (#3299)
* a batch of failing tests is fixed (#3306, #3313, #3321, #3332, #3337, #3335,
#3344, #3340, #3350, #3355, #3364, #3368, #3377, #3393, #3397, #3392, #3398,
#3400)
* outdated minimum required Go version of boilerplate contract generated by
`neo-go contract init` (#3318)
* outdated address used as an example in RPC client documentation (#3327)
* ungraceful node services shutdown procedure (#3307)
* logging data race on node services shutdown (#3307)
* Map parameter support is missing from RPC server handlers (#3329)
* smart contract storage iterator prefix wasn't copied while iterating over values
(#3336)
* RPC error with -511 code (insufficient funds) returned on `sendrawtransaction` RPC
request should cover multiple cases of sender's insufficient funds (#3360, #3361)
* reentrancy possibility for Notary deposit withdrawal (#3357)
* null `findstorage` RPC response in case of missing storage items (#3385)
* uninitialized named return variables in compiler (#3401)
* wrong debug sequence points after `JUMP*` instructions shortening by compiler
(#3412)
* corrupted genesis block record and application log caused by improper Conflicts
attribute processing (#3437)
* false positive DB-based blocked accounts detection in native PolicyContract leaded
to invalid committee computations and reward distribution made by NeoToken (#3443)
## 0.105.1 "Enumeration" (12 Jan 2024) ## 0.105.1 "Enumeration" (12 Jan 2024)
This is another v3.6.2-compatible release that fixes mainnet state difference at This is another v3.6.2-compatible release that fixes mainnet state difference at

View file

@ -7,11 +7,10 @@ functionality.
## Versions 0.7X.Y (as needed) ## Versions 0.7X.Y (as needed)
* Neo 2.0 support (bug fixes, minor functionality additions) * Neo 2.0 support (bug fixes, minor functionality additions)
## Version 0.107.0 (~Jun-Jul 2024) ## Version 0.106.0 (~February 2023)
* extended data types for iterators to be used by RPC wrapper generator
* protocol updates * protocol updates
* bug fixes * test fixes
* node resynchronisation from local DB
* CLI library upgrade
## Version 1.0 (2024, TBD) ## Version 1.0 (2024, TBD)
* stable version * stable version
@ -31,15 +30,15 @@ GetPeers RPC command returns a list of Peers where the port type has changed fro
string to uint16 to match C#. The RPC client currently supports unmarshalling both string to uint16 to match C#. The RPC client currently supports unmarshalling both
formats. formats.
Removal of Peer unmarshalling with string based ports is scheduled for Jun-Jul 2024 Removal of Peer unmarshalling with string based ports is scheduled for ~September 2023
(~0.107.0 release). (~0.105.0 release).
## `NEOBalance` from stack item ## `NEOBalance` from stack item
We check struct items count before convert LastGasPerVote to let RPC client be compatible with We check struct items count before convert LastGasPerVote to let RPC client be compatible with
old versions. old versions.
Removal of this compatiblility code is scheduled for Jun-Jul 2024. Removal of this compatiblility code is scheduled for Sep-Oct 2023.
## `serv_node_version` Prometheus gauge metric ## `serv_node_version` Prometheus gauge metric
@ -48,7 +47,7 @@ metrics with proper version formatting. `neogo_version` contains NeoGo version
hidden under `version` label and `server_id` contains network server ID hidden hidden under `version` label and `server_id` contains network server ID hidden
under `server_id` label. under `server_id` label.
Removal of `serv_node_version` is scheduled for Jun-Jul 2024 (~0.107.0 release). Removal of `serv_node_version` is scheduled for Sep-Oct 2023 (~0.105.0 release).
## RPC error codes returned by old versions and C#-nodes ## RPC error codes returned by old versions and C#-nodes
@ -56,8 +55,7 @@ NeoGo retains certain deprecated error codes: `neorpc.ErrCompatGeneric`,
`neorpc.ErrCompatNoOpenedWallet`. They returned by nodes not compliant with the `neorpc.ErrCompatNoOpenedWallet`. They returned by nodes not compliant with the
neo-project/proposals#156 (NeoGo pre-0.102.0 and all known C# versions). neo-project/proposals#156 (NeoGo pre-0.102.0 and all known C# versions).
Removal of the deprecated RPC error codes is planned for Jun-Jul 2024 (~0.107.0 Removal of the deprecated RPC error codes is planned once all nodes adopt the new error standard.
release).
## Block based web-socket waiter transaction awaiting ## Block based web-socket waiter transaction awaiting
@ -68,4 +66,4 @@ event-based waiter fallbacks to the old way of block monitoring with
`block_added` notifications subscription. `block_added` notifications subscription.
Removal of stale RPC server compatibility code from `waiter.EventWaiter` is Removal of stale RPC server compatibility code from `waiter.EventWaiter` is
scheduled for Jun-Jul 2024 (~0.107.0 release). scheduled for May-June 2024 (~0.107.0 release).

View file

@ -29,7 +29,6 @@ import (
"github.com/urfave/cli" "github.com/urfave/cli"
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore" "go.uber.org/zap/zapcore"
"golang.org/x/term"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -220,7 +219,6 @@ var (
// If logPath is configured -- function creates a dir and a file for logging. // If logPath is configured -- function creates a dir and a file for logging.
// If logPath is configured on Windows -- function returns closer to be // If logPath is configured on Windows -- function returns closer to be
// able to close sink for the opened log output file. // able to close sink for the opened log output file.
// If the program is run in TTY then logger adds timestamp to its entries.
func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.Logger, *zap.AtomicLevel, func() error, error) { func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.Logger, *zap.AtomicLevel, func() error, error) {
var ( var (
level = zapcore.InfoLevel level = zapcore.InfoLevel
@ -241,11 +239,7 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
cc.DisableStacktrace = true cc.DisableStacktrace = true
cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
if term.IsTerminal(int(os.Stdout.Fd())) { cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
} else {
cc.EncoderConfig.EncodeTime = func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {}
}
cc.Encoding = "console" cc.Encoding = "console"
cc.Level = zap.NewAtomicLevelAt(level) cc.Level = zap.NewAtomicLevelAt(level)
cc.Sampling = nil cc.Sampling = nil

View file

@ -65,6 +65,7 @@
"key": "6PYSATFztBa3CHjSR6sLAKungUEAbQUCVE16KzmaQQ38gLeYGZ9Knd5mGv", "key": "6PYSATFztBa3CHjSR6sLAKungUEAbQUCVE16KzmaQQ38gLeYGZ9Knd5mGv",
"label": "verify", "label": "verify",
"contract": { "contract": {
"script": "VwEAEUBXAANA",
"parameters": [], "parameters": [],
"deployed": true "deployed": true
}, },

View file

@ -1105,7 +1105,7 @@ func handleRun(c *cli.Context) error {
breaks := v.Context().BreakPoints() // We ensure that there's a context loaded. breaks := v.Context().BreakPoints() // We ensure that there's a context loaded.
ic.ReuseVM(v) ic.ReuseVM(v)
v.GasLimit = gasLimit v.GasLimit = gasLimit
v.LoadNEFMethod(&cs.NEF, &cs.Manifest, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil) v.LoadNEFMethod(&cs.NEF, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil)
for _, bp := range breaks { for _, bp := range breaks {
v.AddBreakPoint(bp) v.AddBreakPoint(bp)
} }

View file

@ -134,10 +134,6 @@ func newTestVMClIWithState(t *testing.T) *executor {
} }
bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, store) bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, store)
require.NoError(t, err) require.NoError(t, err)
// Save config for future usage.
protoCfg := bc.GetConfig()
go bc.Run() go bc.Run()
e := neotest.NewExecutor(t, bc, validators, committee) e := neotest.NewExecutor(t, bc, validators, committee)
basicchain.InitSimple(t, "../../", e) basicchain.InitSimple(t, "../../", e)
@ -149,9 +145,7 @@ func newTestVMClIWithState(t *testing.T) *executor {
require.NoError(t, err) require.NoError(t, err)
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions = opts cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions = opts
cfg.ProtocolConfiguration.StateRootInHeader = protoCfg.StateRootInHeader cfg.ProtocolConfiguration.StateRootInHeader = true
cfg.ProtocolConfiguration.P2PStateExchangeExtensions = protoCfg.P2PStateExchangeExtensions
cfg.ProtocolConfiguration.Hardforks = protoCfg.Hardforks
return newTestVMCLIWithLogoAndCustomConfig(t, false, &cfg) return newTestVMCLIWithLogoAndCustomConfig(t, false, &cfg)
} }

View file

@ -651,8 +651,7 @@ func importDeployed(ctx *cli.Context) error {
return cli.NewExitError("contract has no `verify` method with boolean return", 1) return cli.NewExitError("contract has no `verify` method with boolean return", 1)
} }
acc.Address = address.Uint160ToString(cs.Hash) acc.Address = address.Uint160ToString(cs.Hash)
// Explicitly overwrite single signature script of the provided WIF since the contract is known to be deployed. acc.Contract.Script = cs.NEF.Script
acc.Contract.Script = nil
acc.Contract.Parameters = acc.Contract.Parameters[:0] acc.Contract.Parameters = acc.Contract.Parameters[:0]
for _, p := range md.Parameters { for _, p := range md.Parameters {
acc.Contract.Parameters = append(acc.Contract.Parameters, wallet.ContractParam{ acc.Contract.Parameters = append(acc.Contract.Parameters, wallet.ContractParam{

View file

@ -26,7 +26,6 @@ ProtocolConfiguration:
Hardforks: Hardforks:
Aspidochelone: 3000000 Aspidochelone: 3000000
Basilisk: 4500000 Basilisk: 4500000
Cockatrice: 5800000
ApplicationConfiguration: ApplicationConfiguration:
SkipBlockVerification: false SkipBlockVerification: false

View file

@ -38,7 +38,6 @@ ProtocolConfiguration:
Hardforks: Hardforks:
Aspidochelone: 1730000 Aspidochelone: 1730000
Basilisk: 4120000 Basilisk: 4120000
Cockatrice: 5450000
ApplicationConfiguration: ApplicationConfiguration:
SkipBlockVerification: false SkipBlockVerification: false

View file

@ -41,7 +41,6 @@ ProtocolConfiguration:
Hardforks: Hardforks:
Aspidochelone: 210000 Aspidochelone: 210000
Basilisk: 2680000 Basilisk: 2680000
Cockatrice: 3967000
ApplicationConfiguration: ApplicationConfiguration:
SkipBlockVerification: false SkipBlockVerification: false

View file

@ -332,7 +332,7 @@ protocol-related settings described in the table below.
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| CommitteeHistory | map[uint32]uint32 | 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]uint32 | 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. |
| Genesis | [Genesis](#Genesis-Configuration) | none | The set of genesis block settings including NeoGo-specific protocol extensions that should be enabled at the genesis block or during native contracts initialisation. | | Genesis | [Genesis](#Genesis-Configuration) | none | The set of genesis block settings including NeoGo-specific protocol extensions that should be enabled at the genesis block or during native contracts initialisation. |
| 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).<br>`Basilisk` represents hard-fork introduced in [#3056](https://github.com/nspcc-dev/neo-go/pull/3056) (ported from the [reference](https://github.com/neo-project/neo/pull/2881)). It enables strict smart contract script check against a set of JMP instructions and against method boundaries enabled on contract deploy or update. It also includes [#3080](https://github.com/nspcc-dev/neo-go/pull/3080) (ported from the [reference](https://github.com/neo-project/neo/pull/2883)) that increases `stackitem.Integer` JSON parsing precision up to the maximum value supported by the NeoVM. It also includes [#3085](https://github.com/nspcc-dev/neo-go/pull/3085) (ported from the [reference](https://github.com/neo-project/neo/pull/2810)) that enables strict check for notifications emitted by a contract to precisely match the events specified in the contract manifest. <br>`Cockatrice` represents hard-fork introduced in [#3402](https://github.com/nspcc-dev/neo-go/pull/3402) (ported from the [reference](https://github.com/neo-project/neo/pull/2942)). Initially it is introduced along with the ability to update native contracts. This hard-fork also includes a couple of new native smart contract APIs: `keccak256` of native CryptoLib contract introduced in [#3301](https://github.com/nspcc-dev/neo-go/pull/3301) (ported from the [reference](https://github.com/neo-project/neo/pull/2925)) and `getCommitteeAddress` of native NeoToken contract inctroduced in [#3362](https://github.com/nspcc-dev/neo-go/pull/3362) (ported from the [reference](https://github.com/neo-project/neo/pull/3154)). | | 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).<br>`Basilisk` represents hard-fork introduced in [#3056](https://github.com/nspcc-dev/neo-go/pull/3056) (ported from the [reference](https://github.com/neo-project/neo/pull/2881)). It enables strict smart contract script check against a set of JMP instructions and against method boundaries enabled on contract deploy or update. It also includes [#3080](https://github.com/nspcc-dev/neo-go/pull/3080) (ported from the [reference](https://github.com/neo-project/neo/pull/2883)) that increases `stackitem.Integer` JSON parsing precision up to the maximum value supported by the NeoVM. It also includes [#3085](https://github.com/nspcc-dev/neo-go/pull/3085) (ported from the [reference](https://github.com/neo-project/neo/pull/2810)) that enables strict check for notifications emitted by a contract to precisely match the events specified in the contract manifest. |
| 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. |
| MaxBlockSystemFee | `int64` | `900000000000` | Maximum overall transactions system fee per block. | | MaxBlockSystemFee | `int64` | `900000000000` | Maximum overall transactions system fee per block. |

View file

@ -10,8 +10,7 @@ These should run successfully:
* unit-tests * unit-tests
* lint * lint
* privnet with consensus nodes * privnet with consensus nodes
* testnet and mainnet synchronization * mainnet synchronization
* NeoFS testnet and mainnet synchronisation and containers compatibility tests
## Update CHANGELOG and ROADMAP ## Update CHANGELOG and ROADMAP

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -4,7 +4,7 @@ go 1.20
require ( require (
github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
) )

View file

@ -200,8 +200,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h
github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y=
github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 h1:WnEdGAQwaW0C8wnNnQZ+rM/JfFKZDSTOqwm8cS0TOdk= github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 h1:WnEdGAQwaW0C8wnNnQZ+rM/JfFKZDSTOqwm8cS0TOdk=
github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689/go.mod h1:x+wmcYqpZYJwLp1l/pHZrqNp3RSWlkMymWGDij3/OPo= github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689/go.mod h1:x+wmcYqpZYJwLp1l/pHZrqNp3RSWlkMymWGDij3/OPo=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk=
github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -33,7 +33,7 @@ require (
github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect
github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c // indirect github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c // indirect
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d // indirect github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d // indirect
github.com/nspcc-dev/rfc6979 v0.2.0 // indirect github.com/nspcc-dev/rfc6979 v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect

View file

@ -216,8 +216,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c/go.mod h
github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y=
github.com/nspcc-dev/neo-go v0.103.1 h1:BfRBceHUu8jSc1KQy7CzmQ/pa+xzAmgcyteGf0/IGgM= github.com/nspcc-dev/neo-go v0.103.1 h1:BfRBceHUu8jSc1KQy7CzmQ/pa+xzAmgcyteGf0/IGgM=
github.com/nspcc-dev/neo-go v0.103.1/go.mod h1:MD7MPiyshUwrE5n1/LzxeandbItaa/iLW/bJb6gNs/U= github.com/nspcc-dev/neo-go v0.103.1/go.mod h1:MD7MPiyshUwrE5n1/LzxeandbItaa/iLW/bJb6gNs/U=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk=
github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/zkp/xor
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

20
go.mod
View file

@ -16,8 +16,8 @@ require (
github.com/mr-tron/base58 v1.2.0 github.com/mr-tron/base58 v1.2.0
github.com/nspcc-dev/dbft v0.2.0 github.com/nspcc-dev/dbft v0.2.0
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12 github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11
github.com/nspcc-dev/rfc6979 v0.2.1 github.com/nspcc-dev/rfc6979 v0.2.1
github.com/pierrec/lz4 v2.6.1+incompatible github.com/pierrec/lz4 v2.6.1+incompatible
github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib v1.0.0
@ -51,22 +51,24 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/nspcc-dev/hrw/v2 v2.0.1 // indirect github.com/nspcc-dev/hrw v1.0.9 // indirect
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 // indirect github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 // indirect
github.com/nspcc-dev/tzhash v1.7.2 // indirect github.com/nspcc-dev/neofs-crypto v0.4.0 // indirect
github.com/nspcc-dev/tzhash v1.7.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/rs/zerolog v1.30.0 // indirect github.com/rs/zerolog v1.30.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.10.0 // indirect
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
golang.org/x/mod v0.16.0 // indirect golang.org/x/mod v0.16.0 // indirect
golang.org/x/net v0.23.0 // indirect golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.18.0 // indirect golang.org/x/sys v0.18.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/grpc v1.62.0 // indirect google.golang.org/grpc v1.57.1 // indirect
google.golang.org/protobuf v1.33.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
rsc.io/tmplfunc v0.0.3 // indirect rsc.io/tmplfunc v0.0.3 // indirect
) )

47
go.sum
View file

@ -26,6 +26,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
@ -91,18 +92,21 @@ github.com/nspcc-dev/dbft v0.2.0 h1:sDwsQES600OSIMncV176t2SX5OvB14lzeOAyKFOkbMI=
github.com/nspcc-dev/dbft v0.2.0/go.mod h1:oFE6paSC/yfFh9mcNU6MheMGOYXK9+sPiRk3YMoz49o= github.com/nspcc-dev/dbft v0.2.0/go.mod h1:oFE6paSC/yfFh9mcNU6MheMGOYXK9+sPiRk3YMoz49o=
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 h1:mD9hU3v+zJcnHAVmHnZKt3I++tvn30gBj2rP2PocZMk= github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 h1:mD9hU3v+zJcnHAVmHnZKt3I++tvn30gBj2rP2PocZMk=
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc= github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc=
github.com/nspcc-dev/hrw/v2 v2.0.1 h1:CxYUkBeJvNfMEn2lHhrV6FjY8pZPceSxXUtMVq0BUOU= github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y=
github.com/nspcc-dev/hrw/v2 v2.0.1/go.mod h1:iZAs5hT2q47EGq6AZ0FjaUI6ggntOi7vrY4utfzk5VA= github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 h1:arN0Ypn+jawZpu1BND7TGRn44InAVIqKygndsx0y2no= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12 h1:mdxtlSU2I4oVZ/7AXTLKyz8uUPbDWikZw4DM8gvrddA= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12/go.mod h1:JdsEM1qgNukrWqgOBDChcYp8oY4XUzidcKaxY4hNJvQ= github.com/nspcc-dev/neofs-crypto v0.4.0/go.mod h1:6XJ8kbXgOfevbI2WMruOtI+qUJXNwSGM/E9eClXxPHs=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11/go.mod h1:W+ImTNRnSNMH8w43H1knCcIqwu7dLHePXtlJNZ7EFIs=
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM= github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM=
github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc= github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc=
github.com/nspcc-dev/tzhash v1.7.2 h1:iRXoa9TJqH/DQO7FFcqpq9BdruF9E7/xnFGlIghl5J4= github.com/nspcc-dev/tzhash v1.7.0 h1:/+aL33NC7y5OIGnY2kYgjZt8mg7LVGFMdj/KAJLndnk=
github.com/nspcc-dev/tzhash v1.7.2/go.mod h1:oHiH0qwmTsZkeVs7pvCS5cVXUaLhXxSFvnmnZ++ijm4= github.com/nspcc-dev/tzhash v1.7.0/go.mod h1:Dnx9LUlOLr5paL2Rtc96x0PPs8D9eIkUtowt1n+KQus=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -135,6 +139,11 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs=
@ -147,17 +156,18 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -197,10 +207,10 @@ golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo= google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 h1:eSaPbMR4T7WfH9FvABk36NBMacoTUKdWCvV0dx+KfOg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I=
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg=
google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -220,6 +230,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=

View file

@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/internal/examples/oracle
go 1.20 go 1.20
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d

View file

@ -1,2 +1,2 @@
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d h1:Vcb7YkZuUSSIC+WF/xV3UDfHbAxZgyT2zGleJP3Ig5k= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d h1:m7EMAkmBdb3Jzn2oW+ndXSWZ0Y7g8rlfnjWfVM6FVVI=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240502161835-cbf09f29eb8d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=

View file

@ -99,7 +99,7 @@ func (*FakeChain) IsExtensibleAllowed(uint160 util.Uint160) bool {
} }
// GetNatives implements the blockchainer.Blockchainer interface. // GetNatives implements the blockchainer.Blockchainer interface.
func (*FakeChain) GetNatives() []state.Contract { func (*FakeChain) GetNatives() []state.NativeContract {
panic("TODO") panic("TODO")
} }

View file

@ -15,7 +15,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/dao"
"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/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -610,7 +610,7 @@ func TestCallWithVersion(t *testing.T) {
e.DeployContract(t, ctr, nil) e.DeployContract(t, ctr, nil)
c := e.CommitteeInvoker(ctr.Hash) c := e.CommitteeInvoker(ctr.Hash)
policyH := nativehashes.PolicyContract policyH := state.CreateNativeContractHash(nativenames.Policy)
t.Run("good", func(t *testing.T) { t.Run("good", func(t *testing.T) {
c.Invoke(t, e.Chain.GetBaseExecFee(), "callWithVersion", policyH.BytesBE(), 0, "getExecFeeFactor") c.Invoke(t, e.Chain.GetBaseExecFee(), "callWithVersion", policyH.BytesBE(), 0, "getExecFeeFactor")
}) })

View file

@ -290,7 +290,7 @@ func runNativeTestCases(t *testing.T, ctr interop.ContractMD, name string, nativ
}) })
} }
func getMethod(t *testing.T, ctr interop.ContractMD, name string, params []string) interop.HFSpecificMethodAndPrice { func getMethod(t *testing.T, ctr interop.ContractMD, name string, params []string) interop.MethodAndPrice {
paramLen := len(params) paramLen := len(params)
switch { switch {
@ -310,10 +310,8 @@ func getMethod(t *testing.T, ctr interop.ContractMD, name string, params []strin
name = strings.TrimSuffix(name, "WithData") name = strings.TrimSuffix(name, "WithData")
} }
latestHF := config.LatestHardfork() md, ok := ctr.GetMethod(name, paramLen)
cMD := ctr.HFSpecificContractMD(&latestHF) require.True(t, ok, ctr.Manifest.Name, name, paramLen)
md, ok := cMD.GetMethod(name, paramLen)
require.True(t, ok, cMD.Manifest.Name, name, paramLen)
return md return md
} }

View file

@ -5,13 +5,6 @@ package config
// Hardfork represents the application hard-fork identifier. // Hardfork represents the application hard-fork identifier.
type Hardfork byte type Hardfork byte
// HFDefault is a default value of Hardfork enum. It's a special constant
// aimed to denote the node code enabled by default starting from the
// genesis block. HFDefault is not a hard-fork, but this constant can be used for
// convenient hard-forks comparison and to refer to the default hard-fork-less
// node behaviour.
const HFDefault Hardfork = 0 // Default
const ( const (
// HFAspidochelone represents hard-fork introduced in #2469 (ported from // HFAspidochelone represents hard-fork introduced in #2469 (ported from
// https://github.com/neo-project/neo/pull/2712) and #2519 (ported from // https://github.com/neo-project/neo/pull/2712) and #2519 (ported from
@ -22,11 +15,6 @@ const (
// https://github.com/neo-project/neo/pull/2883) and #3085 (ported from // https://github.com/neo-project/neo/pull/2883) and #3085 (ported from
// https://github.com/neo-project/neo/pull/2810). // https://github.com/neo-project/neo/pull/2810).
HFBasilisk // Basilisk HFBasilisk // Basilisk
// HFCockatrice represents hard-fork introduced in #3402 (ported from
// https://github.com/neo-project/neo/pull/2942), #3301 (ported from
// https://github.com/neo-project/neo/pull/2925) and #3362 (ported from
// https://github.com/neo-project/neo/pull/3154).
HFCockatrice // Cockatrice
// hfLast denotes the end of hardforks enum. Consider adding new hardforks // hfLast denotes the end of hardforks enum. Consider adding new hardforks
// before hfLast. // before hfLast.
hfLast hfLast
@ -48,38 +36,9 @@ func init() {
} }
} }
// Cmp returns the result of hardforks comparison. It returns:
//
// -1 if hf < other
// 0 if hf == other
// +1 if hf > other
func (hf Hardfork) Cmp(other Hardfork) int {
switch {
case hf == other:
return 0
case hf < other:
return -1
default:
return 1
}
}
// Prev returns the previous hardfork for the given one. Calling Prev for the default hardfork is a no-op.
func (hf Hardfork) Prev() Hardfork {
if hf == HFDefault {
panic("unexpected call to Prev for the default hardfork")
}
return hf >> 1
}
// IsHardforkValid denotes whether the provided string represents a valid // IsHardforkValid denotes whether the provided string represents a valid
// Hardfork name. // Hardfork name.
func IsHardforkValid(s string) bool { func IsHardforkValid(s string) bool {
_, ok := hardforks[s] _, ok := hardforks[s]
return ok return ok
} }
// LatestHardfork returns latest known hardfork.
func LatestHardfork() Hardfork {
return hfLast >> 1
}

View file

@ -8,31 +8,27 @@ func _() {
// An "invalid array index" compiler error signifies that the constant values have changed. // An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again. // Re-run the stringer command to generate them again.
var x [1]struct{} var x [1]struct{}
_ = x[HFDefault-0]
_ = x[HFAspidochelone-1] _ = x[HFAspidochelone-1]
_ = x[HFBasilisk-2] _ = x[HFBasilisk-2]
_ = x[HFCockatrice-4] _ = x[hfLast-4]
_ = x[hfLast-8]
} }
const ( const (
_Hardfork_name_0 = "DefaultAspidocheloneBasilisk" _Hardfork_name_0 = "AspidocheloneBasilisk"
_Hardfork_name_1 = "Cockatrice" _Hardfork_name_1 = "hfLast"
_Hardfork_name_2 = "hfLast"
) )
var ( var (
_Hardfork_index_0 = [...]uint8{0, 7, 20, 28} _Hardfork_index_0 = [...]uint8{0, 13, 21}
) )
func (i Hardfork) String() string { func (i Hardfork) String() string {
switch { switch {
case i <= 2: case 1 <= i && i <= 2:
i -= 1
return _Hardfork_name_0[_Hardfork_index_0[i]:_Hardfork_index_0[i+1]] return _Hardfork_name_0[_Hardfork_index_0[i]:_Hardfork_index_0[i+1]]
case i == 4: case i == 4:
return _Hardfork_name_1 return _Hardfork_name_1
case i == 8:
return _Hardfork_name_2
default: default:
return "Hardfork(" + strconv.FormatInt(int64(i), 10) + ")" return "Hardfork(" + strconv.FormatInt(int64(i), 10) + ")"
} }

View file

@ -12,7 +12,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
json "github.com/nspcc-dev/go-ordered-json"
"github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/config/limits" "github.com/nspcc-dev/neo-go/pkg/config/limits"
"github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/block"
@ -45,7 +44,7 @@ import (
// Tuning parameters. // Tuning parameters.
const ( const (
version = "0.2.12" version = "0.2.10"
// DefaultInitialGAS is the default amount of GAS emitted to the standby validators // DefaultInitialGAS is the default amount of GAS emitted to the standby validators
// multisignature account during native GAS contract initialization. // multisignature account during native GAS contract initialization.
@ -289,7 +288,7 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
cfg.Hardforks[hf.String()] = 0 cfg.Hardforks[hf.String()] = 0
} }
log.Info("Hardforks are not set, using default value") log.Info("Hardforks are not set, using default value")
} else if len(cfg.Hardforks) != 0 { } else {
// Explicitly set the height of all old omitted hardforks to 0 for proper // Explicitly set the height of all old omitted hardforks to 0 for proper
// IsHardforkEnabled behaviour. // IsHardforkEnabled behaviour.
for _, hf := range config.Hardforks { for _, hf := range config.Hardforks {
@ -342,36 +341,16 @@ func (bc *Blockchain) GetDesignatedByRole(r noderoles.Role) (keys.PublicKeys, ui
return res, h, err return res, h, err
} }
// getCurrentHF returns the latest currently enabled hardfork. In case if no hardforks are enabled, the
// default config.Hardfork(0) value is returned.
func (bc *Blockchain) getCurrentHF() config.Hardfork {
var (
height = bc.BlockHeight()
current config.Hardfork
)
// Rely on the fact that hardforks list is continuous.
for _, hf := range config.Hardforks {
enableHeight, ok := bc.config.Hardforks[hf.String()]
if !ok || height < enableHeight {
break
}
current = hf
}
return current
}
// SetOracle sets oracle module. It can safely be called on the running blockchain. // SetOracle sets oracle module. It can safely be called on the running blockchain.
// To unregister Oracle service use SetOracle(nil). // To unregister Oracle service use SetOracle(nil).
func (bc *Blockchain) SetOracle(mod native.OracleService) { func (bc *Blockchain) SetOracle(mod native.OracleService) {
orc := bc.contracts.Oracle orc := bc.contracts.Oracle
currentHF := bc.getCurrentHF()
if mod != nil { if mod != nil {
orcMd := orc.HFSpecificContractMD(&currentHF) md, ok := orc.GetMethod(manifest.MethodVerify, -1)
md, ok := orcMd.GetMethod(manifest.MethodVerify, -1)
if !ok { if !ok {
panic(fmt.Errorf("%s method not found", manifest.MethodVerify)) panic(fmt.Errorf("%s method not found", manifest.MethodVerify))
} }
mod.UpdateNativeContract(orcMd.NEF.Script, orc.GetOracleResponseScript(), mod.UpdateNativeContract(orc.NEF.Script, orc.GetOracleResponseScript(),
orc.Hash, md.MD.Offset) orc.Hash, md.MD.Offset)
keys, _, err := bc.GetDesignatedByRole(noderoles.Oracle) keys, _, err := bc.GetDesignatedByRole(noderoles.Oracle)
if err != nil { if err != nil {
@ -508,7 +487,6 @@ func (bc *Blockchain) init() error {
// Check autogenerated native contracts' manifests and NEFs against the stored ones. // Check autogenerated native contracts' manifests and NEFs against the stored ones.
// Need to be done after native Management cache initialization to be able to get // Need to be done after native Management cache initialization to be able to get
// contract state from DAO via high-level bc API. // contract state from DAO via high-level bc API.
var current = bc.getCurrentHF()
for _, c := range bc.contracts.Contracts { for _, c := range bc.contracts.Contracts {
md := c.Metadata() md := c.Metadata()
storedCS := bc.GetContractState(md.Hash) storedCS := bc.GetContractState(md.Hash)
@ -526,9 +504,8 @@ func (bc *Blockchain) init() error {
if err != nil { if err != nil {
return fmt.Errorf("failed to check native %s state against autogenerated one: %w", md.Name, err) return fmt.Errorf("failed to check native %s state against autogenerated one: %w", md.Name, err)
} }
hfMD := md.HFSpecificContractMD(&current)
autogenCS := &state.Contract{ autogenCS := &state.Contract{
ContractBase: hfMD.ContractBase, ContractBase: md.ContractBase,
UpdateCounter: storedCS.UpdateCounter, // it can be restored only from the DB, so use the stored value. UpdateCounter: storedCS.UpdateCounter, // it can be restored only from the DB, so use the stored value.
} }
autogenCSBytes, err := stackitem.SerializeConvertible(autogenCS) autogenCSBytes, err := stackitem.SerializeConvertible(autogenCS)
@ -536,10 +513,8 @@ func (bc *Blockchain) init() error {
return fmt.Errorf("failed to check native %s state against autogenerated one: %w", md.Name, err) return fmt.Errorf("failed to check native %s state against autogenerated one: %w", md.Name, err)
} }
if !bytes.Equal(storedCSBytes, autogenCSBytes) { if !bytes.Equal(storedCSBytes, autogenCSBytes) {
storedJ, _ := json.Marshal(storedCS) return fmt.Errorf("native %s: version mismatch (stored contract state differs from autogenerated one), "+
autogenJ, _ := json.Marshal(autogenCS) "try to resynchronize the node from the genesis", md.Name)
return fmt.Errorf("native %s: version mismatch for the latest hardfork %s (stored contract state differs from autogenerated one), "+
"try to resynchronize the node from the genesis: %s vs %s", md.Name, current, string(storedJ), string(autogenJ))
} }
} }
@ -1515,11 +1490,8 @@ func (bc *Blockchain) AddBlock(block *block.Block) error {
} else { } else {
err = bc.verifyAndPoolTx(tx, mp, bc) err = bc.verifyAndPoolTx(tx, mp, bc)
} }
if err != nil { if err != nil && bc.config.VerifyTransactions {
if bc.config.VerifyTransactions { return fmt.Errorf("transaction %s failed to verify: %w", tx.Hash().StringLE(), err)
return fmt.Errorf("transaction %s failed to verify: %w", tx.Hash().StringLE(), err)
}
bc.log.Warn(fmt.Sprintf("transaction %s failed to verify: %s", tx.Hash().StringLE(), err))
} }
} }
} }
@ -2295,19 +2267,10 @@ func (bc *Blockchain) GetNativeContractScriptHash(name string) (util.Uint160, er
} }
// GetNatives returns list of native contracts. // GetNatives returns list of native contracts.
func (bc *Blockchain) GetNatives() []state.Contract { func (bc *Blockchain) GetNatives() []state.NativeContract {
res := make([]state.Contract, 0, len(bc.contracts.Contracts)) res := make([]state.NativeContract, 0, len(bc.contracts.Contracts))
current := bc.getCurrentHF()
for _, c := range bc.contracts.Contracts { for _, c := range bc.contracts.Contracts {
activeIn := c.ActiveIn() res = append(res, c.Metadata().NativeContract)
if !(activeIn == nil || activeIn.Cmp(current) <= 0) {
continue
}
st := bc.GetContractState(c.Metadata().Hash)
if st != nil { // Should never happen, but better safe than sorry.
res = append(res, *st)
}
} }
return res return res
} }
@ -2928,7 +2891,7 @@ func (bc *Blockchain) InitVerificationContext(ic *interop.Context, hash util.Uin
initOffset = md.Offset initOffset = md.Offset
} }
ic.Invocations[cs.Hash]++ ic.Invocations[cs.Hash]++
ic.VM.LoadNEFMethod(&cs.NEF, &cs.Manifest, util.Uint160{}, hash, callflag.ReadOnly, ic.VM.LoadNEFMethod(&cs.NEF, util.Uint160{}, hash, callflag.ReadOnly,
true, verifyOffset, initOffset, nil) true, verifyOffset, initOffset, nil)
} }
if len(witness.InvocationScript) != 0 { if len(witness.InvocationScript) != 0 {
@ -3017,7 +2980,12 @@ func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block
// verifyHeaderWitnesses is a block-specific implementation of VerifyWitnesses logic. // verifyHeaderWitnesses is a block-specific implementation of VerifyWitnesses logic.
func (bc *Blockchain) verifyHeaderWitnesses(currHeader, prevHeader *block.Header) error { func (bc *Blockchain) verifyHeaderWitnesses(currHeader, prevHeader *block.Header) error {
hash := prevHeader.NextConsensus var hash util.Uint160
if prevHeader == nil && currHeader.PrevHash.Equals(util.Uint256{}) {
hash = currHeader.Script.ScriptHash()
} else {
hash = prevHeader.NextConsensus
}
_, err := bc.VerifyWitness(hash, currHeader, &currHeader.Script, HeaderVerificationGasLimit) _, err := bc.VerifyWitness(hash, currHeader, &currHeader.Script, HeaderVerificationGasLimit)
return err return err
} }

View file

@ -361,23 +361,15 @@ func TestBlockchain_IsRunning(t *testing.T) {
} }
func TestNewBlockchain_InitHardforks(t *testing.T) { func TestNewBlockchain_InitHardforks(t *testing.T) {
t.Run("nil set", func(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.Hardforks = nil
require.NoError(t, c.ProtocolConfiguration.Validate())
})
require.Equal(t, map[string]uint32{
config.HFAspidochelone.String(): 0,
config.HFBasilisk.String(): 0,
config.HFCockatrice.String(): 0,
}, bc.GetConfig().Hardforks)
})
t.Run("empty set", func(t *testing.T) { t.Run("empty set", func(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) { bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.Hardforks = map[string]uint32{} c.ProtocolConfiguration.Hardforks = map[string]uint32{}
require.NoError(t, c.ProtocolConfiguration.Validate()) require.NoError(t, c.ProtocolConfiguration.Validate())
}) })
require.Equal(t, map[string]uint32{}, bc.GetConfig().Hardforks) require.Equal(t, map[string]uint32{
config.HFAspidochelone.String(): 0,
config.HFBasilisk.String(): 0,
}, bc.GetConfig().Hardforks)
}) })
t.Run("missing old", func(t *testing.T) { t.Run("missing old", func(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) { bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
@ -400,13 +392,12 @@ func TestNewBlockchain_InitHardforks(t *testing.T) {
}) })
t.Run("all present", func(t *testing.T) { t.Run("all present", func(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) { bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.Hardforks = map[string]uint32{config.HFAspidochelone.String(): 5, config.HFBasilisk.String(): 10, config.HFCockatrice.String(): 15} c.ProtocolConfiguration.Hardforks = map[string]uint32{config.HFAspidochelone.String(): 5, config.HFBasilisk.String(): 10}
require.NoError(t, c.ProtocolConfiguration.Validate()) require.NoError(t, c.ProtocolConfiguration.Validate())
}) })
require.Equal(t, map[string]uint32{ require.Equal(t, map[string]uint32{
config.HFAspidochelone.String(): 5, config.HFAspidochelone.String(): 5,
config.HFBasilisk.String(): 10, config.HFBasilisk.String(): 10,
config.HFCockatrice.String(): 15,
}, bc.GetConfig().Hardforks) }, bc.GetConfig().Hardforks)
}) })
} }

View file

@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -25,7 +24,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/core/mempool" "github.com/nspcc-dev/neo-go/pkg/core/mempool"
"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/native/nativeprices" "github.com/nspcc-dev/neo-go/pkg/core/native/nativeprices"
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
@ -271,7 +269,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
_, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache) _, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
require.Error(t, err) require.Error(t, err)
require.True(t, strings.Contains(err.Error(), fmt.Sprintf("native %s: version mismatch for the latest hardfork Cockatrice (stored contract state differs from autogenerated one)", nativenames.CryptoLib)), err) require.True(t, strings.Contains(err.Error(), fmt.Sprintf("native %s: version mismatch (stored contract state differs from autogenerated one)", nativenames.CryptoLib)), err)
}) })
t.Run("good", func(t *testing.T) { t.Run("good", func(t *testing.T) {
@ -317,92 +315,6 @@ func TestBlockchain_InitializeNeoCache_Bug3181(t *testing.T) {
}) })
} }
// TestBlockchain_InitializeNeoCache_Bug3424 ensures that Neo cache (new epoch
// committee and stand by validators) is properly initialized after node restart
// at the dBFT epoch boundary.
func TestBlockchain_InitializeNeoCache_Bug3424(t *testing.T) {
ps, path := newLevelDBForTestingWithPath(t, "")
bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, nil, ps)
require.NoError(t, err)
go bc.Run()
e := neotest.NewExecutor(t, bc, validators, committee)
cfg := e.Chain.GetConfig()
committeeSize := cfg.GetCommitteeSize(0)
validatorsCount := cfg.GetNumOfCNs(0)
// Stand by committee drives the chain.
standBySorted, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee)
require.NoError(t, err)
standBySorted = standBySorted[:validatorsCount]
sort.Sort(standBySorted)
pubs := e.Chain.ComputeNextBlockValidators()
require.Equal(t, standBySorted, keys.PublicKeys(pubs))
// Move from stand by committee to the elected nodes.
e.ValidatorInvoker(e.NativeHash(t, nativenames.Gas)).Invoke(t, true, "transfer", e.Validator.ScriptHash(), e.CommitteeHash, 100_0000_0000, nil)
neoCommitteeInvoker := e.CommitteeInvoker(e.NativeHash(t, nativenames.Neo))
neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
policyInvoker := neoCommitteeInvoker.CommitteeInvoker(neoCommitteeInvoker.NativeHash(t, nativenames.Policy))
advanceChain := func(t *testing.T) {
for int(e.Chain.BlockHeight())%committeeSize != 0 {
neoCommitteeInvoker.AddNewBlock(t)
}
}
advanceChainToEpochBoundary := func(t *testing.T) {
for int(e.Chain.BlockHeight()+1)%committeeSize != 0 {
neoCommitteeInvoker.AddNewBlock(t)
}
}
// voters vote for candidates.
voters := make([]neotest.Signer, committeeSize+1)
candidates := make([]neotest.Signer, committeeSize+1)
for i := 0; i < committeeSize+1; i++ {
voters[i] = e.NewAccount(t, 10_0000_0000)
candidates[i] = e.NewAccount(t, 2000_0000_0000) // enough for one registration
}
txes := make([]*transaction.Transaction, 0, committeeSize*3)
for i := 0; i < committeeSize+1; i++ {
transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize+1-i)*1000000, nil)
txes = append(txes, transferTx)
registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
txes = append(txes, registerTx)
voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
txes = append(txes, voteTx)
}
txes = append(txes, policyInvoker.PrepareInvoke(t, "blockAccount", candidates[len(candidates)-1].(neotest.SingleSigner).Account().ScriptHash()))
neoValidatorsInvoker.AddNewBlock(t, txes...)
for _, tx := range txes {
e.CheckHalt(t, tx.Hash(), stackitem.Make(true)) // luckily, both `transfer`, `registerCandidate` and `vote` return boolean values
}
// Ensure validators are properly updated.
advanceChain(t)
pubs = e.Chain.ComputeNextBlockValidators()
sortedCandidates := make(keys.PublicKeys, validatorsCount)
for i := range candidates[:validatorsCount] {
sortedCandidates[i] = candidates[i].(neotest.SingleSigner).Account().PublicKey()
}
sort.Sort(sortedCandidates)
require.EqualValues(t, sortedCandidates, keys.PublicKeys(pubs))
// Move to the last block in the epoch and restart the node.
advanceChainToEpochBoundary(t)
bc.Close() // Ensure persist is done and persistent store is properly closed.
ps, _ = newLevelDBForTestingWithPath(t, path)
t.Cleanup(func() { require.NoError(t, ps.Close()) })
// Start chain from the existing database that should trigger an update of native
// Neo newEpoch* cached values during initializaition. This update requires candidates
// list recalculation and caldidates policies checks.
bc, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, nil, ps)
require.NoError(t, err)
pubs = bc.ComputeNextBlockValidators()
require.EqualValues(t, sortedCandidates, keys.PublicKeys(pubs))
}
// This test enables Notary native contract at non-zero height and checks that no // This test enables Notary native contract at non-zero height and checks that no
// Notary cache initialization is performed before that height on node restart. // Notary cache initialization is performed before that height on node restart.
/* /*
@ -2548,7 +2460,7 @@ func TestBlockchain_GenesisTransactionExtension(t *testing.T) {
emit.Syscall(script.BinWriter, interopnames.SystemRuntimeCheckWitness) emit.Syscall(script.BinWriter, interopnames.SystemRuntimeCheckWitness)
emit.Bytes(script.BinWriter, to.BytesBE()) emit.Bytes(script.BinWriter, to.BytesBE())
emit.Syscall(script.BinWriter, interopnames.SystemRuntimeCheckWitness) emit.Syscall(script.BinWriter, interopnames.SystemRuntimeCheckWitness)
emit.AppCall(script.BinWriter, nativehashes.NeoToken, "transfer", callflag.All, from, to, amount, nil) emit.AppCall(script.BinWriter, state.CreateNativeContractHash(nativenames.Neo), "transfer", callflag.All, from, to, amount, nil)
emit.Opcodes(script.BinWriter, opcode.ASSERT) emit.Opcodes(script.BinWriter, opcode.ASSERT)
var sysFee int64 = 1_0000_0000 var sysFee int64 = 1_0000_0000
@ -2567,56 +2479,3 @@ func TestBlockchain_GenesisTransactionExtension(t *testing.T) {
require.Equal(t, int64(amount), actualNeo.Int64()) require.Equal(t, int64(amount), actualNeo.Int64())
require.Equal(t, 0, int(lub)) require.Equal(t, 0, int(lub))
} }
// TestNativenames ensures that nativenames.All contains all expected native contract names
// in the right order.
func TestNativenames(t *testing.T) {
bc, _ := chain.NewSingleWithCustomConfig(t, func(cfg *config.Blockchain) {
cfg.Hardforks = map[string]uint32{}
cfg.P2PSigExtensions = true
})
natives := bc.GetNatives()
require.Equal(t, len(natives), len(nativenames.All))
for i, cs := range natives {
require.Equal(t, cs.Manifest.Name, nativenames.All[i], i)
}
}
// TestBlockchain_StoreAsTransaction_ExecutableConflict ensures that transaction conflicting with
// some on-chain block can be properly stored and doesn't break the database.
func TestBlockchain_StoreAsTransaction_ExecutableConflict(t *testing.T) {
bc, acc := chain.NewSingleWithCustomConfig(t, nil)
e := neotest.NewExecutor(t, bc, acc, acc)
genesisH := bc.GetHeaderHash(0)
currHeight := bc.BlockHeight()
// Ensure AER can be retrieved for genesis block.
aer, err := bc.GetAppExecResults(genesisH, trigger.All)
require.NoError(t, err)
require.Equal(t, 2, len(aer))
tx := transaction.New([]byte{byte(opcode.PUSHT)}, 0)
tx.Nonce = 5
tx.ValidUntilBlock = e.Chain.BlockHeight() + 1
tx.Attributes = []transaction.Attribute{{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: genesisH}}}
e.SignTx(t, tx, -1, acc)
e.AddNewBlock(t, tx)
e.CheckHalt(t, tx.Hash(), stackitem.Make(true))
// Ensure original tx can be retrieved.
actual, actualHeight, err := bc.GetTransaction(tx.Hash())
require.NoError(t, err)
require.Equal(t, currHeight+1, actualHeight)
require.Equal(t, tx, actual, tx)
// Ensure conflict stub is not stored. This check doesn't give us 100% sure that
// there's no specific conflict record since GetTransaction doesn't return conflict records,
// but at least it allows to ensure that no transaction record is present.
_, _, err = bc.GetTransaction(genesisH)
require.ErrorIs(t, err, storage.ErrKeyNotFound)
// Ensure AER still can be retrieved for genesis block.
aer, err = bc.GetAppExecResults(genesisH, trigger.All)
require.NoError(t, err)
require.Equal(t, 2, len(aer))
}

View file

@ -35,11 +35,6 @@ var (
ErrInternalDBInconsistency = errors.New("internal DB inconsistency") ErrInternalDBInconsistency = errors.New("internal DB inconsistency")
) )
// conflictRecordValueLen is the length of value of transaction conflict record.
// It consists of 1-byte [storage.ExecTransaction] prefix and 4-bytes block index
// in the LE form.
const conflictRecordValueLen = 1 + 4
// Simple is memCached wrapper around DB, simple DAO implementation. // Simple is memCached wrapper around DB, simple DAO implementation.
type Simple struct { type Simple struct {
Version Version Version Version
@ -328,7 +323,7 @@ func (dao *Simple) GetTxExecResult(hash util.Uint256) (uint32, *transaction.Tran
// decodeTxAndExecResult decodes transaction, its height and execution result from // decodeTxAndExecResult decodes transaction, its height and execution result from
// the given executable bytes. It performs no executable prefix check. // the given executable bytes. It performs no executable prefix check.
func decodeTxAndExecResult(buf []byte) (uint32, *transaction.Transaction, *state.AppExecResult, error) { func decodeTxAndExecResult(buf []byte) (uint32, *transaction.Transaction, *state.AppExecResult, error) {
if len(buf) == conflictRecordValueLen { // conflict record stub. if len(buf) >= 6 && buf[5] == transaction.DummyVersion {
return 0, nil, nil, storage.ErrKeyNotFound return 0, nil, nil, storage.ErrKeyNotFound
} }
r := io.NewBinReaderFromBuf(buf) r := io.NewBinReaderFromBuf(buf)
@ -610,7 +605,7 @@ func (dao *Simple) DeleteHeaderHashes(since uint32, batchSize int) {
} }
// GetTransaction returns Transaction and its height by the given hash // GetTransaction returns Transaction and its height by the given hash
// if it exists in the store. It does not return conflict record stubs. // if it exists in the store. It does not return dummy transactions.
func (dao *Simple) GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error) { func (dao *Simple) GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error) {
key := dao.makeExecutableKey(hash) key := dao.makeExecutableKey(hash)
b, err := dao.Store.Get(key) b, err := dao.Store.Get(key)
@ -624,7 +619,7 @@ func (dao *Simple) GetTransaction(hash util.Uint256) (*transaction.Transaction,
// It may be a block. // It may be a block.
return nil, 0, storage.ErrKeyNotFound return nil, 0, storage.ErrKeyNotFound
} }
if len(b) == conflictRecordValueLen { if len(b) == 1+4 { // storage.ExecTransaction + index
// It's a conflict record stub. // It's a conflict record stub.
return nil, 0, storage.ErrKeyNotFound return nil, 0, storage.ErrKeyNotFound
} }
@ -704,16 +699,10 @@ func (dao *Simple) HasTransaction(hash util.Uint256, signers []transaction.Signe
return nil return nil
} }
if len(bytes) < conflictRecordValueLen { // (storage.ExecTransaction + index) for conflict record if len(bytes) < 5 { // (storage.ExecTransaction + index) for conflict record
return nil return nil
} }
if bytes[0] != storage.ExecTransaction { if len(bytes) != 5 {
// It's a block, thus no conflict. This path is needed since there's a transaction accepted on mainnet
// that conflicts with block. This transaction was declined by Go nodes, but accepted by C# nodes, and hence
// we need to adjust Go behaviour post-factum. Ref. #3427 and 0x289c235dcdab8be7426d05f0fbb5e86c619f81481ea136493fa95deee5dbb7cc.
return nil
}
if len(bytes) != conflictRecordValueLen {
return ErrAlreadyExists // fully-qualified transaction return ErrAlreadyExists // fully-qualified transaction
} }
if len(signers) == 0 { if len(signers) == 0 {
@ -789,10 +778,6 @@ func (dao *Simple) DeleteBlock(h util.Uint256) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve conflict record stub for %s (height %d, conflict %s): %w", tx.Hash().StringLE(), b.Index, hash.StringLE(), err) return fmt.Errorf("failed to retrieve conflict record stub for %s (height %d, conflict %s): %w", tx.Hash().StringLE(), b.Index, hash.StringLE(), err)
} }
// It might be a block since we allow transactions to have block hash in the Conflicts attribute.
if v[0] != storage.ExecTransaction {
continue
}
index := binary.LittleEndian.Uint32(v[1:]) index := binary.LittleEndian.Uint32(v[1:])
// We can check for `<=` here, but use equality comparison to be more precise // We can check for `<=` here, but use equality comparison to be more precise
// and do not touch earlier conflict records (if any). Their removal must be triggered // and do not touch earlier conflict records (if any). Their removal must be triggered
@ -853,9 +838,8 @@ func (dao *Simple) StoreAsCurrentBlock(block *block.Block) {
dao.Store.Put(dao.mkKeyPrefix(storage.SYSCurrentBlock), buf.Bytes()) dao.Store.Put(dao.mkKeyPrefix(storage.SYSCurrentBlock), buf.Bytes())
} }
// StoreAsTransaction stores the given TX as DataTransaction. It also stores conflict records // StoreAsTransaction stores the given TX as DataTransaction. It also stores transactions
// (hashes of transactions the given tx has conflicts with) as DataTransaction with value containing // the given tx has conflicts with as DataTransaction with dummy version. It can reuse the given
// only five bytes: 1-byte [storage.ExecTransaction] executable prefix + 4-bytes-LE block index. It can reuse the given
// buffer for the purpose of value serialization. // buffer for the purpose of value serialization.
func (dao *Simple) StoreAsTransaction(tx *transaction.Transaction, index uint32, aer *state.AppExecResult) error { func (dao *Simple) StoreAsTransaction(tx *transaction.Transaction, index uint32, aer *state.AppExecResult) error {
key := dao.makeExecutableKey(tx.Hash()) key := dao.makeExecutableKey(tx.Hash())
@ -873,23 +857,12 @@ func (dao *Simple) StoreAsTransaction(tx *transaction.Transaction, index uint32,
val := buf.Bytes() val := buf.Bytes()
dao.Store.Put(key, val) dao.Store.Put(key, val)
val = val[:conflictRecordValueLen] // storage.ExecTransaction (1 byte) + index (4 bytes) val = val[:5] // storage.ExecTransaction (1 byte) + index (4 bytes)
attrs := tx.GetAttributes(transaction.ConflictsT) attrs := tx.GetAttributes(transaction.ConflictsT)
for _, attr := range attrs { for _, attr := range attrs {
// Conflict record stub. // Conflict record stub.
hash := attr.Value.(*transaction.Conflicts).Hash hash := attr.Value.(*transaction.Conflicts).Hash
copy(key[1:], hash.BytesBE()) copy(key[1:], hash.BytesBE())
// A short path if there's a block with the matching hash. If it's there, then
// don't store the conflict record stub and conflict signers since it's a
// useless record, no transaction with the same hash is possible.
exec, err := dao.Store.Get(key)
if err == nil {
if len(exec) > 0 && exec[0] != storage.ExecTransaction {
continue
}
}
dao.Store.Put(key, val) dao.Store.Put(key, val)
// Conflicting signers. // Conflicting signers.

View file

@ -242,53 +242,6 @@ func TestStoreAsTransaction(t *testing.T) {
} }
err = dao.StoreAsTransaction(tx2, blockIndex, aer2) err = dao.StoreAsTransaction(tx2, blockIndex, aer2)
require.NoError(t, err) require.NoError(t, err)
// A special transaction that conflicts with genesis block.
genesis := &block.Block{
Header: block.Header{
Version: 0,
Timestamp: 123,
Nonce: 1,
Index: 0,
NextConsensus: util.Uint160{1, 2, 3},
},
}
genesisAer1 := &state.AppExecResult{
Container: genesis.Hash(),
Execution: state.Execution{
Trigger: trigger.OnPersist,
Events: []state.NotificationEvent{},
Stack: []stackitem.Item{},
},
}
genesisAer2 := &state.AppExecResult{
Container: genesis.Hash(),
Execution: state.Execution{
Trigger: trigger.PostPersist,
Events: []state.NotificationEvent{},
Stack: []stackitem.Item{},
},
}
require.NoError(t, dao.StoreAsBlock(genesis, genesisAer1, genesisAer2))
tx3 := transaction.New([]byte{byte(opcode.PUSH1)}, 1)
tx3.Signers = append(tx3.Signers, transaction.Signer{Account: signer1})
tx3.Scripts = append(tx3.Scripts, transaction.Witness{})
tx3.Attributes = []transaction.Attribute{
{
Type: transaction.ConflictsT,
Value: &transaction.Conflicts{Hash: genesis.Hash()},
},
}
hash3 := tx3.Hash()
aer3 := &state.AppExecResult{
Container: hash3,
Execution: state.Execution{
Trigger: trigger.Application,
Events: []state.NotificationEvent{},
Stack: []stackitem.Item{},
},
}
err = dao.HasTransaction(hash1, nil, 0, 0) err = dao.HasTransaction(hash1, nil, 0, 0)
require.ErrorIs(t, err, ErrAlreadyExists) require.ErrorIs(t, err, ErrAlreadyExists)
err = dao.HasTransaction(hash2, nil, 0, 0) err = dao.HasTransaction(hash2, nil, 0, 0)
@ -327,29 +280,6 @@ func TestStoreAsTransaction(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, 1, len(gotAppExecResult)) require.Equal(t, 1, len(gotAppExecResult))
require.Equal(t, *aer2, gotAppExecResult[0]) require.Equal(t, *aer2, gotAppExecResult[0])
// Ensure block is not treated as transaction.
err = dao.HasTransaction(genesis.Hash(), nil, 0, 0)
require.NoError(t, err)
// Store tx3 and ensure genesis executable record is not corrupted.
require.NoError(t, dao.StoreAsTransaction(tx3, 0, aer3))
err = dao.HasTransaction(hash3, nil, 0, 0)
require.ErrorIs(t, err, ErrAlreadyExists)
actualAer, err := dao.GetAppExecResults(hash3, trigger.All)
require.NoError(t, err)
require.Equal(t, 1, len(actualAer))
require.Equal(t, *aer3, actualAer[0])
actualGenesisAer, err := dao.GetAppExecResults(genesis.Hash(), trigger.All)
require.NoError(t, err)
require.Equal(t, 2, len(actualGenesisAer))
require.Equal(t, *genesisAer1, actualGenesisAer[0])
require.Equal(t, *genesisAer2, actualGenesisAer[1])
// A special requirement for transactions that conflict with block: they should
// not produce conflict record stub, ref. #3427.
err = dao.HasTransaction(genesis.Hash(), nil, 0, 0)
require.NoError(t, err)
}) })
} }

View file

@ -140,15 +140,8 @@ type Function struct {
// Method is a signature for a native method. // Method is a signature for a native method.
type Method = func(ic *Context, args []stackitem.Item) stackitem.Item type Method = func(ic *Context, args []stackitem.Item) stackitem.Item
// MethodAndPrice is a generic hardfork-independent native contract method descriptor. // MethodAndPrice is a native-contract method descriptor.
type MethodAndPrice struct { type MethodAndPrice struct {
HFSpecificMethodAndPrice
ActiveFrom *config.Hardfork
ActiveTill *config.Hardfork
}
// HFSpecificMethodAndPrice is a hardfork-specific native contract method descriptor.
type HFSpecificMethodAndPrice struct {
Func Method Func Method
MD *manifest.Method MD *manifest.Method
CPUFee int64 CPUFee int64
@ -157,24 +150,10 @@ type HFSpecificMethodAndPrice struct {
RequiredFlags callflag.CallFlag RequiredFlags callflag.CallFlag
} }
// Event is a generic hardfork-independent native contract event descriptor.
type Event struct {
HFSpecificEvent
ActiveFrom *config.Hardfork
ActiveTill *config.Hardfork
}
// HFSpecificEvent is a hardfork-specific native contract event descriptor.
type HFSpecificEvent struct {
MD *manifest.Event
}
// Contract is an interface for all native contracts. // Contract is an interface for all native contracts.
type Contract interface { type Contract interface {
// Initialize performs native contract initialization on contract deploy or update. Initialize(*Context) error
// Active hardfork is passed as the second argument. // ActiveIn returns the hardfork native contract is active from or nil in case
Initialize(*Context, *config.Hardfork, *HFSpecificContractMD) error
// ActiveIn returns the hardfork native contract is active starting from or nil in case
// it's always active. // it's always active.
ActiveIn() *config.Hardfork ActiveIn() *config.Hardfork
// InitializeCache aimed to initialize contract's cache when the contract has // InitializeCache aimed to initialize contract's cache when the contract has
@ -182,176 +161,53 @@ type Contract interface {
// It should be called each time after node restart iff the contract was // It should be called each time after node restart iff the contract was
// deployed and no Initialize method was called. // deployed and no Initialize method was called.
InitializeCache(blockHeight uint32, d *dao.Simple) error InitializeCache(blockHeight uint32, d *dao.Simple) error
// Metadata returns generic native contract metadata.
Metadata() *ContractMD Metadata() *ContractMD
OnPersist(*Context) error OnPersist(*Context) error
PostPersist(*Context) error PostPersist(*Context) error
} }
// ContractMD represents a generic hardfork-independent native contract instance. // ContractMD represents a native contract instance.
type ContractMD struct { type ContractMD struct {
ID int32 state.NativeContract
Hash util.Uint160 Name string
Name string Methods []MethodAndPrice
// methods is a generic set of contract methods with activation hardforks. Any HF-dependent part of included methods
// (offsets, in particular) must not be used, there's a mdCache field for that.
methods []MethodAndPrice
// events is a generic set of contract events with activation hardforks. Any HF-dependent part of events must not be
// used, there's a mdCache field for that.
events []Event
// ActiveHFs is a map of hardforks that contract should react to. Contract update should be called for active
// hardforks. Note, that unlike the C# implementation, this map doesn't include contract's activation hardfork.
// This map is being initialized on contract creation and used as a read-only, hence, not protected
// by mutex.
ActiveHFs map[config.Hardfork]struct{}
// mdCache contains hardfork-specific ready-to-use contract descriptors. This cache is initialized in the native
// contracts constructors, and acts as read-only during the whole node lifetime, thus not protected by mutex.
mdCache map[config.Hardfork]*HFSpecificContractMD
// onManifestConstruction is a callback for manifest finalization.
onManifestConstruction func(*manifest.Manifest)
} }
// HFSpecificContractMD is a hardfork-specific native contract descriptor. // NewContractMD returns Contract with the specified list of methods.
type HFSpecificContractMD struct { func NewContractMD(name string, id int32) *ContractMD {
state.ContractBase
Methods []HFSpecificMethodAndPrice
Events []HFSpecificEvent
}
// NewContractMD returns Contract with the specified fields set. onManifestConstruction callback every time
// after hardfork-specific manifest creation and aimed to finalize the manifest.
func NewContractMD(name string, id int32, onManifestConstruction ...func(*manifest.Manifest)) *ContractMD {
c := &ContractMD{Name: name} c := &ContractMD{Name: name}
if len(onManifestConstruction) != 0 {
c.onManifestConstruction = onManifestConstruction[0]
}
c.ID = id c.ID = id
// NEF is now stored in the contract state and affects state dump.
// Therefore, values are taken from C# node.
c.NEF.Header.Compiler = "neo-core-v3.0"
c.NEF.Header.Magic = nef.Magic
c.NEF.Tokens = []nef.MethodToken{} // avoid `nil` result during JSON marshalling
c.Hash = state.CreateNativeContractHash(c.Name) c.Hash = state.CreateNativeContractHash(c.Name)
c.ActiveHFs = make(map[config.Hardfork]struct{}) c.Manifest = *manifest.DefaultManifest(name)
c.mdCache = make(map[config.Hardfork]*HFSpecificContractMD)
return c return c
} }
// HFSpecificContractMD returns hardfork-specific native contract metadata, i.e. with methods, events and script // UpdateHash creates a native contract script and updates hash.
// corresponding to the specified hardfork. If hardfork is not specified, then default metadata will be returned func (c *ContractMD) UpdateHash() {
// (methods, events and script that are always active). Calling this method for hardforks older than the contract
// activation hardfork is a no-op.
func (c *ContractMD) HFSpecificContractMD(hf *config.Hardfork) *HFSpecificContractMD {
var key config.Hardfork
if hf != nil {
key = *hf
}
md, ok := c.mdCache[key]
if !ok {
panic(fmt.Errorf("native contract descriptor cache is not initialized: contract %s, hardfork %s", c.Hash.StringLE(), key))
}
if md == nil {
panic(fmt.Errorf("native contract descriptor cache is nil: contract %s, hardfork %s", c.Hash.StringLE(), key))
}
return md
}
// BuildHFSpecificMD generates and caches contract's descriptor for every known hardfork.
func (c *ContractMD) BuildHFSpecificMD(activeIn *config.Hardfork) {
var start config.Hardfork
if activeIn != nil {
start = *activeIn
}
for _, hf := range append([]config.Hardfork{config.HFDefault}, config.Hardforks...) {
switch {
case hf.Cmp(start) < 0:
continue
case hf.Cmp(start) == 0:
c.buildHFSpecificMD(hf)
default:
if _, ok := c.ActiveHFs[hf]; !ok {
// Intentionally omit HFSpecificContractMD structure copying since mdCache is read-only.
c.mdCache[hf] = c.mdCache[hf.Prev()]
continue
}
c.buildHFSpecificMD(hf)
}
}
}
// buildHFSpecificMD builds hardfork-specific contract descriptor that includes methods and events active starting from
// the specified hardfork or older. It also updates cache with the received value.
func (c *ContractMD) buildHFSpecificMD(hf config.Hardfork) {
var (
abiMethods = make([]manifest.Method, 0, len(c.methods))
methods = make([]HFSpecificMethodAndPrice, 0, len(c.methods))
abiEvents = make([]manifest.Event, 0, len(c.events))
events = make([]HFSpecificEvent, 0, len(c.events))
)
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
for i := range c.methods { for i := range c.Methods {
m := c.methods[i] offset := w.Len()
if !(m.ActiveFrom == nil || (hf != config.HFDefault && (*m.ActiveFrom).Cmp(hf) >= 0)) || c.Methods[i].MD.Offset = offset
(m.ActiveTill != nil && (*m.ActiveTill).Cmp(hf) <= 0) { c.Manifest.ABI.Methods[i].Offset = offset
continue
}
// Perform method descriptor copy to support independent HF-based offset update.
md := *m.MD
m.MD = &md
m.MD.Offset = w.Len()
emit.Int(w.BinWriter, 0) emit.Int(w.BinWriter, 0)
m.SyscallOffset = w.Len() c.Methods[i].SyscallOffset = w.Len()
emit.Syscall(w.BinWriter, interopnames.SystemContractCallNative) emit.Syscall(w.BinWriter, interopnames.SystemContractCallNative)
emit.Opcodes(w.BinWriter, opcode.RET) emit.Opcodes(w.BinWriter, opcode.RET)
abiMethods = append(abiMethods, *m.MD)
methods = append(methods, m.HFSpecificMethodAndPrice)
} }
if w.Err != nil { if w.Err != nil {
panic(fmt.Errorf("can't create native contract script: %w", w.Err)) panic(fmt.Errorf("can't create native contract script: %w", w.Err))
} }
for i := range c.events {
e := c.events[i]
if !(e.ActiveFrom == nil || (hf != config.HFDefault && (*e.ActiveFrom).Cmp(hf) >= 0)) ||
(e.ActiveTill != nil && (*e.ActiveTill).Cmp(hf) <= 0) {
continue
}
abiEvents = append(abiEvents, *e.MD) c.NEF.Script = w.Bytes()
events = append(events, e.HFSpecificEvent) c.NEF.Checksum = c.NEF.CalculateChecksum()
}
// NEF is now stored in the contract state and affects state dump.
// Therefore, values are taken from C# node.
nf := nef.File{
Header: nef.Header{
Magic: nef.Magic,
Compiler: "neo-core-v3.0",
},
Tokens: []nef.MethodToken{}, // avoid `nil` result during JSON marshalling,
Script: w.Bytes(),
}
nf.Checksum = nf.CalculateChecksum()
m := manifest.DefaultManifest(c.Name)
m.ABI.Methods = abiMethods
m.ABI.Events = abiEvents
if c.onManifestConstruction != nil {
c.onManifestConstruction(m)
}
md := &HFSpecificContractMD{
ContractBase: state.ContractBase{
ID: c.ID,
Hash: c.Hash,
NEF: nf,
Manifest: *m,
},
Methods: methods,
Events: events,
}
c.mdCache[hf] = md
} }
// AddMethod adds a new method to a native contract. // AddMethod adds a new method to a native contract.
@ -359,38 +215,36 @@ func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method) {
md.MD = desc md.MD = desc
desc.Safe = md.RequiredFlags&(callflag.All^callflag.ReadOnly) == 0 desc.Safe = md.RequiredFlags&(callflag.All^callflag.ReadOnly) == 0
index := sort.Search(len(c.methods), func(i int) bool { index := sort.Search(len(c.Manifest.ABI.Methods), func(i int) bool {
md := c.methods[i].MD md := c.Manifest.ABI.Methods[i]
if md.Name != desc.Name { if md.Name != desc.Name {
return md.Name >= desc.Name return md.Name >= desc.Name
} }
return len(md.Parameters) > len(desc.Parameters) return len(md.Parameters) > len(desc.Parameters)
}) })
c.methods = append(c.methods, MethodAndPrice{}) c.Manifest.ABI.Methods = append(c.Manifest.ABI.Methods, manifest.Method{})
copy(c.methods[index+1:], c.methods[index:]) copy(c.Manifest.ABI.Methods[index+1:], c.Manifest.ABI.Methods[index:])
c.methods[index] = *md c.Manifest.ABI.Methods[index] = *desc
if md.ActiveFrom != nil { // Cache follows the same order.
c.ActiveHFs[*md.ActiveFrom] = struct{}{} c.Methods = append(c.Methods, MethodAndPrice{})
} copy(c.Methods[index+1:], c.Methods[index:])
if md.ActiveTill != nil { c.Methods[index] = *md
c.ActiveHFs[*md.ActiveTill] = struct{}{}
}
} }
// GetMethodByOffset returns method with the provided offset. // GetMethodByOffset returns method with the provided offset.
// Offset is offset of `System.Contract.CallNative` syscall. // Offset is offset of `System.Contract.CallNative` syscall.
func (c *HFSpecificContractMD) GetMethodByOffset(offset int) (HFSpecificMethodAndPrice, bool) { func (c *ContractMD) GetMethodByOffset(offset int) (MethodAndPrice, bool) {
for k := range c.Methods { for k := range c.Methods {
if c.Methods[k].SyscallOffset == offset { if c.Methods[k].SyscallOffset == offset {
return c.Methods[k], true return c.Methods[k], true
} }
} }
return HFSpecificMethodAndPrice{}, false return MethodAndPrice{}, false
} }
// GetMethod returns method `name` with the specified number of parameters. // GetMethod returns method `name` with the specified number of parameters.
func (c *HFSpecificContractMD) GetMethod(name string, paramCount int) (HFSpecificMethodAndPrice, bool) { func (c *ContractMD) GetMethod(name string, paramCount int) (MethodAndPrice, bool) {
index := sort.Search(len(c.Methods), func(i int) bool { index := sort.Search(len(c.Methods), func(i int) bool {
md := c.Methods[i] md := c.Methods[i]
res := strings.Compare(name, md.MD.Name) res := strings.Compare(name, md.MD.Name)
@ -407,19 +261,15 @@ func (c *HFSpecificContractMD) GetMethod(name string, paramCount int) (HFSpecifi
return md, true return md, true
} }
} }
return HFSpecificMethodAndPrice{}, false return MethodAndPrice{}, false
} }
// AddEvent adds a new event to the native contract. // AddEvent adds a new event to the native contract.
func (c *ContractMD) AddEvent(md Event) { func (c *ContractMD) AddEvent(name string, ps ...manifest.Parameter) {
c.events = append(c.events, md) c.Manifest.ABI.Events = append(c.Manifest.ABI.Events, manifest.Event{
Name: name,
if md.ActiveFrom != nil { Parameters: ps,
c.ActiveHFs[*md.ActiveFrom] = struct{}{} })
}
if md.ActiveTill != nil {
c.ActiveHFs[*md.ActiveTill] = struct{}{}
}
} }
// Sort sorts interop functions by id. // Sort sorts interop functions by id.

View file

@ -144,7 +144,7 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
} }
return nil return nil
} }
ic.VM.LoadNEFMethod(&cs.NEF, &cs.Manifest, caller, cs.Hash, f, ic.VM.LoadNEFMethod(&cs.NEF, caller, cs.Hash, f,
hasReturn, methodOff, initOff, onUnload) hasReturn, methodOff, initOff, onUnload)
for e, i := ic.VM.Estack(), len(args)-1; i >= 0; i-- { for e, i := ic.VM.Estack(), len(args)-1; i >= 0; i-- {

View file

@ -80,19 +80,19 @@ func Notify(ic *interop.Context) error {
if len(name) > MaxEventNameLen { if len(name) > MaxEventNameLen {
return fmt.Errorf("event name must be less than %d", MaxEventNameLen) return fmt.Errorf("event name must be less than %d", MaxEventNameLen)
} }
curr := ic.VM.Context().GetManifest() curHash := ic.VM.GetCurrentScriptHash()
if curr == nil { ctr, err := ic.GetContract(curHash)
if err != nil {
return errors.New("notifications are not allowed in dynamic scripts") return errors.New("notifications are not allowed in dynamic scripts")
} }
var ( var (
ev = curr.ABI.GetEvent(name) ev = ctr.Manifest.ABI.GetEvent(name)
checkErr error checkErr error
curHash = ic.VM.GetCurrentScriptHash()
) )
if ev == nil { if ev == nil {
checkErr = fmt.Errorf("notification %s does not exist", name) checkErr = fmt.Errorf("notification %s does not exist", name)
} else { } else {
err := ev.CheckCompliance(args) err = ev.CheckCompliance(args)
if err != nil { if err != nil {
checkErr = fmt.Errorf("notification %s is invalid: %w", name, err) checkErr = fmt.Errorf("notification %s is invalid: %w", name, err)
} }

View file

@ -637,7 +637,7 @@ func TestNotify(t *testing.T) {
_, _, bc, cs := getDeployedInternal(t) _, _, bc, cs := getDeployedInternal(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)
ic.VM.LoadNEFMethod(&cs.NEF, &cs.Manifest, caller, cs.Hash, callflag.NoneFlag, true, 0, -1, nil) ic.VM.LoadNEFMethod(&cs.NEF, caller, cs.Hash, callflag.NoneFlag, true, 0, -1, nil)
ic.VM.Estack().PushVal(args) ic.VM.Estack().PushVal(args)
ic.VM.Estack().PushVal(name) ic.VM.Estack().PushVal(name)
return ic return ic

View file

@ -12,14 +12,12 @@ import (
func TestNamesASCII(t *testing.T) { func TestNamesASCII(t *testing.T) {
cfg := config.ProtocolConfiguration{P2PSigExtensions: true} cfg := config.ProtocolConfiguration{P2PSigExtensions: true}
cs := NewContracts(cfg) cs := NewContracts(cfg)
latestHF := config.LatestHardfork()
for _, c := range cs.Contracts { for _, c := range cs.Contracts {
require.True(t, isASCII(c.Metadata().Name)) require.True(t, isASCII(c.Metadata().Name))
hfMD := c.Metadata().HFSpecificContractMD(&latestHF) for _, m := range c.Metadata().Methods {
for _, m := range hfMD.Methods {
require.True(t, isASCII(m.MD.Name)) require.True(t, isASCII(m.MD.Name))
} }
for _, e := range hfMD.Manifest.ABI.Events { for _, e := range c.Metadata().Manifest.ABI.Events {
require.True(t, isASCII(e.Name)) require.True(t, isASCII(e.Name))
} }
} }

View file

@ -88,7 +88,7 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts {
cs.Policy = policy cs.Policy = policy
cs.Contracts = append(cs.Contracts, neo, gas, policy) cs.Contracts = append(cs.Contracts, neo, gas, policy)
desig := newDesignate(cfg.Genesis.Roles) desig := newDesignate(cfg.P2PSigExtensions, cfg.Genesis.Roles)
desig.NEO = neo desig.NEO = neo
cs.Designate = desig cs.Designate = desig
cs.Contracts = append(cs.Contracts, desig) cs.Contracts = append(cs.Contracts, desig)

View file

@ -12,12 +12,10 @@ import (
func TestNativeGetMethod(t *testing.T) { func TestNativeGetMethod(t *testing.T) {
cfg := config.ProtocolConfiguration{P2PSigExtensions: true} cfg := config.ProtocolConfiguration{P2PSigExtensions: true}
cs := NewContracts(cfg) cs := NewContracts(cfg)
latestHF := config.LatestHardfork()
for _, c := range cs.Contracts { for _, c := range cs.Contracts {
hfMD := c.Metadata().HFSpecificContractMD(&latestHF)
t.Run(c.Metadata().Name, func(t *testing.T) { t.Run(c.Metadata().Name, func(t *testing.T) {
for _, m := range hfMD.Methods { for _, m := range c.Metadata().Methods {
_, ok := hfMD.GetMethod(m.MD.Name, len(m.MD.Parameters)) _, ok := c.Metadata().GetMethod(m.MD.Name, len(m.MD.Parameters))
require.True(t, ok) require.True(t, ok)
} }
}) })

View file

@ -21,7 +21,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/twmb/murmur3" "github.com/twmb/murmur3"
"golang.org/x/crypto/sha3"
) )
// Crypto represents CryptoLib contract. // Crypto represents CryptoLib contract.
@ -39,15 +38,15 @@ type NamedCurveHash byte
const ( const (
Secp256k1Sha256 NamedCurveHash = 22 Secp256k1Sha256 NamedCurveHash = 22
Secp256r1Sha256 NamedCurveHash = 23 Secp256r1Sha256 NamedCurveHash = 23
Secp256k1Keccak256 NamedCurveHash = 122 Secp256k1Keccak256 NamedCurveHash = 24
Secp256r1Keccak256 NamedCurveHash = 123 Secp256r1Keccak256 NamedCurveHash = 25
) )
const cryptoContractID = -3 const cryptoContractID = -3
func newCrypto() *Crypto { func newCrypto() *Crypto {
c := &Crypto{ContractMD: *interop.NewContractMD(nativenames.CryptoLib, cryptoContractID)} c := &Crypto{ContractMD: *interop.NewContractMD(nativenames.CryptoLib, cryptoContractID)}
defer c.BuildHFSpecificMD(c.ActiveIn()) defer c.UpdateHash()
desc := newDescriptor("sha256", smartcontract.ByteArrayType, desc := newDescriptor("sha256", smartcontract.ByteArrayType,
manifest.NewParameter("data", smartcontract.ByteArrayType)) manifest.NewParameter("data", smartcontract.ByteArrayType))
@ -65,20 +64,12 @@ func newCrypto() *Crypto {
md = newMethodAndPrice(c.murmur32, 1<<13, callflag.NoneFlag) md = newMethodAndPrice(c.murmur32, 1<<13, callflag.NoneFlag)
c.AddMethod(md, desc) c.AddMethod(md, desc)
desc = newDescriptor("verifyWithECDsa", smartcontract.BoolType,
manifest.NewParameter("message", smartcontract.ByteArrayType),
manifest.NewParameter("pubkey", smartcontract.ByteArrayType),
manifest.NewParameter("signature", smartcontract.ByteArrayType),
manifest.NewParameter("curve", smartcontract.IntegerType))
md = newMethodAndPrice(c.verifyWithECDsaPreCockatrice, 1<<15, callflag.NoneFlag, config.HFDefault, config.HFCockatrice)
c.AddMethod(md, desc)
desc = newDescriptor("verifyWithECDsa", smartcontract.BoolType, desc = newDescriptor("verifyWithECDsa", smartcontract.BoolType,
manifest.NewParameter("message", smartcontract.ByteArrayType), manifest.NewParameter("message", smartcontract.ByteArrayType),
manifest.NewParameter("pubkey", smartcontract.ByteArrayType), manifest.NewParameter("pubkey", smartcontract.ByteArrayType),
manifest.NewParameter("signature", smartcontract.ByteArrayType), manifest.NewParameter("signature", smartcontract.ByteArrayType),
manifest.NewParameter("curveHash", smartcontract.IntegerType)) manifest.NewParameter("curveHash", smartcontract.IntegerType))
md = newMethodAndPrice(c.verifyWithECDsa, 1<<15, callflag.NoneFlag, config.HFCockatrice) md = newMethodAndPrice(c.verifyWithECDsa, 1<<15, callflag.NoneFlag)
c.AddMethod(md, desc) c.AddMethod(md, desc)
desc = newDescriptor("bls12381Serialize", smartcontract.ByteArrayType, desc = newDescriptor("bls12381Serialize", smartcontract.ByteArrayType,
@ -118,7 +109,7 @@ func newCrypto() *Crypto {
desc = newDescriptor("keccak256", smartcontract.ByteArrayType, desc = newDescriptor("keccak256", smartcontract.ByteArrayType,
manifest.NewParameter("data", smartcontract.ByteArrayType)) manifest.NewParameter("data", smartcontract.ByteArrayType))
md = newMethodAndPrice(c.keccak256, 1<<15, callflag.NoneFlag, config.HFCockatrice) md = newMethodAndPrice(c.keccak256, 1<<15, callflag.NoneFlag)
c.AddMethod(md, desc) c.AddMethod(md, desc)
return c return c
} }
@ -151,15 +142,7 @@ func (c *Crypto) murmur32(_ *interop.Context, args []stackitem.Item) stackitem.I
return stackitem.NewByteArray(result) return stackitem.NewByteArray(result)
} }
func (c *Crypto) verifyWithECDsaPreCockatrice(_ *interop.Context, args []stackitem.Item) stackitem.Item {
return verifyWithECDsaGeneric(args, false)
}
func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stackitem.Item { func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stackitem.Item {
return verifyWithECDsaGeneric(args, true)
}
func verifyWithECDsaGeneric(args []stackitem.Item, allowKeccak bool) stackitem.Item {
msg, err := args[0].TryBytes() msg, err := args[0].TryBytes()
if err != nil { if err != nil {
panic(fmt.Errorf("invalid message stackitem: %w", err)) panic(fmt.Errorf("invalid message stackitem: %w", err))
@ -172,7 +155,7 @@ func verifyWithECDsaGeneric(args []stackitem.Item, allowKeccak bool) stackitem.I
if err != nil { if err != nil {
panic(fmt.Errorf("invalid signature stackitem: %w", err)) panic(fmt.Errorf("invalid signature stackitem: %w", err))
} }
curve, hasher, err := curveHasherFromStackitem(args[3], allowKeccak) curve, hasher, err := curveHasherFromStackitem(args[3])
if err != nil { if err != nil {
panic(fmt.Errorf("invalid curveHash stackitem: %w", err)) panic(fmt.Errorf("invalid curveHash stackitem: %w", err))
} }
@ -185,7 +168,7 @@ func verifyWithECDsaGeneric(args []stackitem.Item, allowKeccak bool) stackitem.I
return stackitem.NewBool(res) return stackitem.NewBool(res)
} }
func curveHasherFromStackitem(si stackitem.Item, allowKeccak bool) (elliptic.Curve, HashFunc, error) { func curveHasherFromStackitem(si stackitem.Item) (elliptic.Curve, HashFunc, error) {
curve, err := si.TryInteger() curve, err := si.TryInteger()
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -200,15 +183,9 @@ func curveHasherFromStackitem(si stackitem.Item, allowKeccak bool) (elliptic.Cur
case int64(Secp256r1Sha256): case int64(Secp256r1Sha256):
return elliptic.P256(), hash.Sha256, nil return elliptic.P256(), hash.Sha256, nil
case int64(Secp256k1Keccak256): case int64(Secp256k1Keccak256):
if !allowKeccak { return secp256k1.S256(), hash.Keccak256, nil
return nil, nil, errors.New("unsupported hash type")
}
return secp256k1.S256(), Keccak256, nil
case int64(Secp256r1Keccak256): case int64(Secp256r1Keccak256):
if !allowKeccak { return elliptic.P256(), hash.Keccak256, nil
return nil, nil, errors.New("unsupported hash type")
}
return elliptic.P256(), Keccak256, nil
default: default:
return nil, nil, errors.New("unsupported curve/hash type") return nil, nil, errors.New("unsupported curve/hash type")
} }
@ -327,7 +304,7 @@ func (c *Crypto) keccak256(_ *interop.Context, args []stackitem.Item) stackitem.
if err != nil { if err != nil {
panic(err) panic(err)
} }
return stackitem.NewByteArray(Keccak256(bs).BytesBE()) return stackitem.NewByteArray(hash.Keccak256(bs).BytesBE())
} }
// Metadata implements the Contract interface. // Metadata implements the Contract interface.
@ -336,7 +313,7 @@ func (c *Crypto) Metadata() *interop.ContractMD {
} }
// Initialize implements the Contract interface. // Initialize implements the Contract interface.
func (c *Crypto) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error { func (c *Crypto) Initialize(ic *interop.Context) error {
return nil return nil
} }
@ -359,14 +336,3 @@ func (c *Crypto) PostPersist(ic *interop.Context) error {
func (c *Crypto) ActiveIn() *config.Hardfork { func (c *Crypto) ActiveIn() *config.Hardfork {
return nil return nil
} }
// Keccak256 hashes the incoming byte slice using the
// keccak256 algorithm.
func Keccak256(data []byte) util.Uint256 {
var hash util.Uint256
hasher := sha3.NewLegacyKeccak256()
_, _ = hasher.Write(data)
hasher.Sum(hash[:0])
return hash
}

View file

@ -151,10 +151,10 @@ func testECDSAVerify(t *testing.T, curve NamedCurveHash) {
hasher = hash.Sha256 hasher = hash.Sha256
case Secp256k1Keccak256: case Secp256k1Keccak256:
priv, err = keys.NewSecp256k1PrivateKey() priv, err = keys.NewSecp256k1PrivateKey()
hasher = Keccak256 hasher = hash.Keccak256
case Secp256r1Keccak256: case Secp256r1Keccak256:
priv, err = keys.NewPrivateKey() priv, err = keys.NewPrivateKey()
hasher = Keccak256 hasher = hash.Keccak256
default: default:
t.Fatal("unknown curve/hash") t.Fatal("unknown curve/hash")
} }
@ -199,7 +199,7 @@ func testECDSAVerify(t *testing.T, curve NamedCurveHash) {
runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(1))) runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(1)))
}) })
t.Run("unknown curve", func(t *testing.T) { t.Run("unknown curve", func(t *testing.T) {
runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, int64(124)) runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, int64(123))
}) })
t.Run("invalid signature", func(t *testing.T) { t.Run("invalid signature", func(t *testing.T) {
s := priv.Sign(msg) s := priv.Sign(msg)
@ -270,13 +270,3 @@ func TestCryptolib_ScalarFromBytes_Compat(t *testing.T) {
}) })
} }
} }
func TestKeccak256(t *testing.T) {
input := []byte("hello")
data := Keccak256(input)
expected := "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
actual := hex.EncodeToString(data.BytesBE())
require.Equal(t, expected, actual)
}

View file

@ -32,6 +32,8 @@ type Designate struct {
interop.ContractMD interop.ContractMD
NEO *NEO NEO *NEO
// p2pSigExtensionsEnabled defines whether the P2P signature extensions logic is relevant.
p2pSigExtensionsEnabled bool
// initialNodeRoles defines a set of node roles that should be defined at the contract // initialNodeRoles defines a set of node roles that should be defined at the contract
// deployment (initialization). // deployment (initialization).
initialNodeRoles map[noderoles.Role]keys.PublicKeys initialNodeRoles map[noderoles.Role]keys.PublicKeys
@ -97,14 +99,14 @@ func copyDesignationCache(src, dst *DesignationCache) {
func (s *Designate) isValidRole(r noderoles.Role) bool { func (s *Designate) isValidRole(r noderoles.Role) bool {
return r == noderoles.Oracle || r == noderoles.StateValidator || return r == noderoles.Oracle || r == noderoles.StateValidator ||
r == noderoles.NeoFSAlphabet || r == noderoles.P2PNotary r == noderoles.NeoFSAlphabet || (s.p2pSigExtensionsEnabled && r == noderoles.P2PNotary)
} }
func newDesignate(initialNodeRoles map[noderoles.Role]keys.PublicKeys) *Designate { func newDesignate(p2pSigExtensionsEnabled bool, initialNodeRoles map[noderoles.Role]keys.PublicKeys) *Designate {
s := &Designate{ContractMD: *interop.NewContractMD(nativenames.Designation, designateContractID)} s := &Designate{ContractMD: *interop.NewContractMD(nativenames.Designation, designateContractID)}
defer s.BuildHFSpecificMD(s.ActiveIn()) s.p2pSigExtensionsEnabled = p2pSigExtensionsEnabled
s.initialNodeRoles = initialNodeRoles s.initialNodeRoles = initialNodeRoles
defer s.UpdateHash()
desc := newDescriptor("getDesignatedByRole", smartcontract.ArrayType, desc := newDescriptor("getDesignatedByRole", smartcontract.ArrayType,
manifest.NewParameter("role", smartcontract.IntegerType), manifest.NewParameter("role", smartcontract.IntegerType),
@ -118,11 +120,9 @@ func newDesignate(initialNodeRoles map[noderoles.Role]keys.PublicKeys) *Designat
md = newMethodAndPrice(s.designateAsRole, 1<<15, callflag.States|callflag.AllowNotify) md = newMethodAndPrice(s.designateAsRole, 1<<15, callflag.States|callflag.AllowNotify)
s.AddMethod(md, desc) s.AddMethod(md, desc)
eDesc := newEventDescriptor(DesignationEventName, s.AddEvent(DesignationEventName,
manifest.NewParameter("Role", smartcontract.IntegerType), manifest.NewParameter("Role", smartcontract.IntegerType),
manifest.NewParameter("BlockIndex", smartcontract.IntegerType)) manifest.NewParameter("BlockIndex", smartcontract.IntegerType))
eMD := newEvent(eDesc)
s.AddEvent(eMD)
return s return s
} }
@ -130,11 +130,7 @@ func newDesignate(initialNodeRoles map[noderoles.Role]keys.PublicKeys) *Designat
// Initialize initializes Designation contract. It is called once at native Management's OnPersist // Initialize initializes Designation contract. It is called once at native Management's OnPersist
// at the genesis block, and we can't properly fill the cache at this point, as there are no roles // at the genesis block, and we can't properly fill the cache at this point, as there are no roles
// data in the storage. // data in the storage.
func (s *Designate) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error { func (s *Designate) Initialize(ic *interop.Context) error {
if hf != s.ActiveIn() {
return nil
}
cache := &DesignationCache{} cache := &DesignationCache{}
ic.DAO.SetCache(s.ID, cache) ic.DAO.SetCache(s.ID, cache)
@ -157,7 +153,10 @@ func (s *Designate) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *
// we can fetch the roles data right from the storage. // we can fetch the roles data right from the storage.
func (s *Designate) InitializeCache(blockHeight uint32, d *dao.Simple) error { func (s *Designate) InitializeCache(blockHeight uint32, d *dao.Simple) error {
cache := &DesignationCache{} cache := &DesignationCache{}
roles := []noderoles.Role{noderoles.Oracle, noderoles.NeoFSAlphabet, noderoles.StateValidator, noderoles.P2PNotary} roles := []noderoles.Role{noderoles.Oracle, noderoles.NeoFSAlphabet, noderoles.StateValidator}
if s.p2pSigExtensionsEnabled {
roles = append(roles, noderoles.P2PNotary)
}
for _, r := range roles { for _, r := range roles {
err := s.updateCachedRoleData(cache, d, r) err := s.updateCachedRoleData(cache, d, r)
if err != nil { if err != nil {
@ -183,7 +182,9 @@ func (s *Designate) PostPersist(ic *interop.Context) error {
s.notifyRoleChanged(&cache.oracles, noderoles.Oracle) s.notifyRoleChanged(&cache.oracles, noderoles.Oracle)
s.notifyRoleChanged(&cache.stateVals, noderoles.StateValidator) s.notifyRoleChanged(&cache.stateVals, noderoles.StateValidator)
s.notifyRoleChanged(&cache.neofsAlphabet, noderoles.NeoFSAlphabet) s.notifyRoleChanged(&cache.neofsAlphabet, noderoles.NeoFSAlphabet)
s.notifyRoleChanged(&cache.notaries, noderoles.P2PNotary) if s.p2pSigExtensionsEnabled {
s.notifyRoleChanged(&cache.notaries, noderoles.P2PNotary)
}
cache.rolesChangedFlag = false cache.rolesChangedFlag = false
return nil return nil

View file

@ -32,25 +32,17 @@ func Call(ic *interop.Context) error {
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)
} }
var ( var (
genericMeta = c.Metadata() meta = c.Metadata()
activeIn = c.ActiveIn() activeIn = c.ActiveIn()
) )
if activeIn != nil { if activeIn != nil {
height, ok := ic.Hardforks[activeIn.String()] height, ok := ic.Hardforks[activeIn.String()]
// Persisting block must not be taken into account, native contract can be called // Persisting block must not be taken into account, native contract can be called
// only AFTER its initialization block persist, thus, can't use ic.IsHardforkEnabled. // only AFTER its initialization block persist, thus, can't use ic.IsHardforkEnabled.
if !ok || ic.BlockHeight() < height { if !ok || ic.BlockHeight() < height {
return fmt.Errorf("native contract %s is active after hardfork %s", genericMeta.Name, activeIn.String()) return fmt.Errorf("native contract %s is active after hardfork %s", meta.Name, activeIn.String())
} }
} }
var current config.Hardfork
for _, hf := range config.Hardforks {
if !ic.IsHardforkEnabled(hf) {
break
}
current = hf
}
meta := genericMeta.HFSpecificContractMD(&current)
m, ok := meta.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")

View file

@ -31,7 +31,7 @@ func newLedger() *Ledger {
var l = &Ledger{ var l = &Ledger{
ContractMD: *interop.NewContractMD(nativenames.Ledger, ledgerContractID), ContractMD: *interop.NewContractMD(nativenames.Ledger, ledgerContractID),
} }
defer l.BuildHFSpecificMD(l.ActiveIn()) defer l.UpdateHash()
desc := newDescriptor("currentHash", smartcontract.Hash256Type) desc := newDescriptor("currentHash", smartcontract.Hash256Type)
md := newMethodAndPrice(l.currentHash, 1<<15, callflag.ReadStates) md := newMethodAndPrice(l.currentHash, 1<<15, callflag.ReadStates)
@ -81,7 +81,7 @@ func (l *Ledger) Metadata() *interop.ContractMD {
} }
// Initialize implements the Contract interface. // Initialize implements the Contract interface.
func (l *Ledger) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error { func (l *Ledger) Initialize(ic *interop.Context) error {
return nil return nil
} }

View file

@ -101,7 +101,7 @@ func newManagement() *Management {
var m = &Management{ var m = &Management{
ContractMD: *interop.NewContractMD(nativenames.Management, ManagementContractID), ContractMD: *interop.NewContractMD(nativenames.Management, ManagementContractID),
} }
defer m.BuildHFSpecificMD(m.ActiveIn()) defer m.UpdateHash()
desc := newDescriptor("getContract", smartcontract.ArrayType, desc := newDescriptor("getContract", smartcontract.ArrayType,
manifest.NewParameter("hash", smartcontract.Hash160Type)) manifest.NewParameter("hash", smartcontract.Hash160Type))
@ -164,17 +164,9 @@ func newManagement() *Management {
m.AddMethod(md, desc) m.AddMethod(md, desc)
hashParam := manifest.NewParameter("Hash", smartcontract.Hash160Type) hashParam := manifest.NewParameter("Hash", smartcontract.Hash160Type)
eDesc := newEventDescriptor(contractDeployNotificationName, hashParam) m.AddEvent(contractDeployNotificationName, hashParam)
eMD := newEvent(eDesc) m.AddEvent(contractUpdateNotificationName, hashParam)
m.AddEvent(eMD) m.AddEvent(contractDestroyNotificationName, hashParam)
eDesc = newEventDescriptor(contractUpdateNotificationName, hashParam)
eMD = newEvent(eDesc)
m.AddEvent(eMD)
eDesc = newEventDescriptor(contractDestroyNotificationName, hashParam)
eMD = newEvent(eDesc)
m.AddEvent(eMD)
return m return m
} }
@ -228,11 +220,6 @@ func (m *Management) getContractByID(ic *interop.Context, args []stackitem.Item)
// GetContract returns a contract with the given hash from the given DAO. // GetContract returns a contract with the given hash from the given DAO.
func GetContract(d *dao.Simple, hash util.Uint160) (*state.Contract, error) { func GetContract(d *dao.Simple, hash util.Uint160) (*state.Contract, error) {
cache := d.GetROCache(ManagementContractID).(*ManagementCache) cache := d.GetROCache(ManagementContractID).(*ManagementCache)
return getContract(cache, hash)
}
// getContract returns a contract with the given hash from provided RO or RW cache.
func getContract(cache *ManagementCache, hash util.Uint160) (*state.Contract, error) {
cs, ok := cache.contracts[hash] cs, ok := cache.contracts[hash]
if !ok { if !ok {
return nil, storage.ErrKeyNotFound return nil, storage.ErrKeyNotFound
@ -596,92 +583,27 @@ func updateContractCache(cache *ManagementCache, cs *state.Contract) {
func (m *Management) OnPersist(ic *interop.Context) error { func (m *Management) OnPersist(ic *interop.Context) error {
var cache *ManagementCache var cache *ManagementCache
for _, native := range ic.Natives { for _, native := range ic.Natives {
var ( activeIn := native.ActiveIn()
activeIn = native.ActiveIn() if !(activeIn == nil && ic.Block.Index == 0 ||
isDeploy bool activeIn != nil && ic.IsHardforkActivation(*activeIn)) {
isUpdate bool
latestHF config.Hardfork
currentActiveHFs []config.Hardfork
)
activeHFs := native.Metadata().ActiveHFs
isDeploy = activeIn == nil && ic.Block.Index == 0 ||
activeIn != nil && ic.IsHardforkActivation(*activeIn)
if !isDeploy {
for _, hf := range config.Hardforks {
if _, ok := activeHFs[hf]; ok && ic.IsHardforkActivation(hf) {
isUpdate = true
activation := hf // avoid loop variable pointer exporting.
activeIn = &activation // reuse ActiveIn variable for the initialization hardfork.
// Break immediately since native Initialize should be called starting from the first hardfork in a raw
// (if there are multiple hardforks with the same enabling height).
break
}
}
}
// Search for the latest active hardfork to properly construct manifest and
// initialize natives for the range of active hardforks.
for _, hf := range config.Hardforks {
if _, ok := activeHFs[hf]; ok && ic.IsHardforkActivation(hf) {
latestHF = hf
currentActiveHFs = append(currentActiveHFs, hf)
}
}
if !(isDeploy || isUpdate) {
continue continue
} }
md := native.Metadata()
hfSpecificMD := md.HFSpecificContractMD(&latestHF)
base := hfSpecificMD.ContractBase
var cs *state.Contract
switch {
case isDeploy:
cs = &state.Contract{
ContractBase: base,
}
case isUpdate:
if cache == nil {
cache = ic.DAO.GetRWCache(m.ID).(*ManagementCache)
}
oldcontract, err := getContract(cache, md.Hash)
if err != nil {
return fmt.Errorf("failed to retrieve native %s from cache: %w", md.Name, err)
}
contract := *oldcontract // Make a copy, don't ruin cached contract and cache. md := native.Metadata()
contract.NEF = base.NEF cs := &state.Contract{
contract.Manifest = base.Manifest ContractBase: md.ContractBase,
contract.UpdateCounter++ }
cs = &contract if err := native.Initialize(ic); err != nil {
return fmt.Errorf("initializing %s native contract: %w", md.Name, err)
} }
err := putContractState(ic.DAO, cs, false) // Perform cache update manually. err := putContractState(ic.DAO, cs, false) // Perform cache update manually.
if err != nil { if err != nil {
return fmt.Errorf("failed to put contract state: %w", err) return err
} }
// Deploy hardfork (contract's ActiveIn) is not a part of contract's active hardforks and
// allowed to be nil, this, a special initialization call for it.
if isDeploy {
if err := native.Initialize(ic, activeIn, hfSpecificMD); err != nil {
return fmt.Errorf("initializing %s native contract at HF %v: %w", md.Name, activeIn, err)
}
}
// The rest of activating hardforks also require initialization.
for _, hf := range currentActiveHFs {
if err := native.Initialize(ic, &hf, hfSpecificMD); err != nil {
return fmt.Errorf("initializing %s native contract at HF %d: %w", md.Name, activeIn, err)
}
}
if cache == nil { if cache == nil {
cache = ic.DAO.GetRWCache(m.ID).(*ManagementCache) cache = ic.DAO.GetRWCache(m.ID).(*ManagementCache)
} }
updateContractCache(cache, cs) updateContractCache(cache, cs)
ntfName := contractDeployNotificationName
if isUpdate {
ntfName = contractUpdateNotificationName
}
m.emitNotification(ic, ntfName, cs.Hash)
} }
return nil return nil
@ -744,11 +666,7 @@ func (m *Management) GetNEP17Contracts(d *dao.Simple) []util.Uint160 {
} }
// Initialize implements the Contract interface. // Initialize implements the Contract interface.
func (m *Management) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error { func (m *Management) Initialize(ic *interop.Context) error {
if hf != m.ActiveIn() {
return nil
}
setIntWithKey(m.ID, ic.DAO, keyMinimumDeploymentFee, defaultMinimumDeploymentFee) setIntWithKey(m.ID, ic.DAO, keyMinimumDeploymentFee, defaultMinimumDeploymentFee)
setIntWithKey(m.ID, ic.DAO, keyNextAvailableID, 1) setIntWithKey(m.ID, ic.DAO, keyNextAvailableID, 1)

View file

@ -20,9 +20,9 @@ func TestDeployGetUpdateDestroyContract(t *testing.T) {
mgmt.Policy = newPolicy(false) mgmt.Policy = newPolicy(false)
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)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, mgmt.Policy.Initialize(&interop.Context{DAO: d}, nil, nil)) require.NoError(t, mgmt.Policy.Initialize(&interop.Context{DAO: d}))
script := []byte{byte(opcode.RET)} script := []byte{byte(opcode.RET)}
sender := util.Uint160{1, 2, 3} sender := util.Uint160{1, 2, 3}
ne, err := nef.NewFile(script) ne, err := nef.NewFile(script)
@ -97,9 +97,9 @@ func TestManagement_GetNEP17Contracts(t *testing.T) {
mgmt := newManagement() mgmt := newManagement()
mgmt.Policy = newPolicy(false) mgmt.Policy = newPolicy(false)
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})
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, mgmt.Policy.Initialize(&interop.Context{DAO: d}, nil, nil)) require.NoError(t, mgmt.Policy.Initialize(&interop.Context{DAO: d}))
err = mgmt.InitializeCache(0, d) err = mgmt.InitializeCache(0, d)
require.NoError(t, err) require.NoError(t, err)

View file

@ -37,7 +37,7 @@ func newGAS(init int64, p2pSigExtensionsEnabled bool) *GAS {
initialSupply: init, initialSupply: init,
p2pSigExtensionsEnabled: p2pSigExtensionsEnabled, p2pSigExtensionsEnabled: p2pSigExtensionsEnabled,
} }
defer g.BuildHFSpecificMD(g.ActiveIn()) defer g.UpdateHash()
nep17 := newNEP17Native(nativenames.Gas, gasContractID) nep17 := newNEP17Native(nativenames.Gas, gasContractID)
nep17.symbol = "GAS" nep17.symbol = "GAS"
@ -83,11 +83,7 @@ func (g *GAS) balanceFromBytes(si *state.StorageItem) (*big.Int, error) {
} }
// Initialize initializes a GAS contract. // Initialize initializes a GAS contract.
func (g *GAS) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error { func (g *GAS) Initialize(ic *interop.Context) error {
if hf != g.ActiveIn() {
return nil
}
if err := g.nep17TokenNative.Initialize(ic); err != nil { if err := g.nep17TokenNative.Initialize(ic); err != nil {
return err return err
} }

View file

@ -172,7 +172,7 @@ func makeValidatorKey(key *keys.PublicKey) []byte {
// newNEO returns NEO native contract. // newNEO returns NEO native contract.
func newNEO(cfg config.ProtocolConfiguration) *NEO { func newNEO(cfg config.ProtocolConfiguration) *NEO {
n := &NEO{} n := &NEO{}
defer n.BuildHFSpecificMD(n.ActiveIn()) defer n.UpdateHash()
nep17 := newNEP17Native(nativenames.Neo, neoContractID) nep17 := newNEP17Native(nativenames.Neo, neoContractID)
nep17.symbol = "NEO" nep17.symbol = "NEO"
@ -233,7 +233,7 @@ func newNEO(cfg config.ProtocolConfiguration) *NEO {
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("getCommitteeAddress", smartcontract.Hash160Type) desc = newDescriptor("getCommitteeAddress", smartcontract.Hash160Type)
md = newMethodAndPrice(n.getCommitteeAddress, 1<<16, callflag.ReadStates, config.HFCockatrice) md = newMethodAndPrice(n.getCommitteeAddress, 1<<16, callflag.ReadStates)
n.AddMethod(md, desc) n.AddMethod(md, desc)
desc = newDescriptor("getNextBlockValidators", smartcontract.ArrayType) desc = newDescriptor("getNextBlockValidators", smartcontract.ArrayType)
@ -258,39 +258,27 @@ func newNEO(cfg config.ProtocolConfiguration) *NEO {
md = newMethodAndPrice(n.setRegisterPrice, 1<<15, callflag.States) md = newMethodAndPrice(n.setRegisterPrice, 1<<15, callflag.States)
n.AddMethod(md, desc) n.AddMethod(md, desc)
eDesc := newEventDescriptor("CandidateStateChanged", n.AddEvent("CandidateStateChanged",
manifest.NewParameter("pubkey", smartcontract.PublicKeyType), manifest.NewParameter("pubkey", smartcontract.PublicKeyType),
manifest.NewParameter("registered", smartcontract.BoolType), manifest.NewParameter("registered", smartcontract.BoolType),
manifest.NewParameter("votes", smartcontract.IntegerType), manifest.NewParameter("votes", smartcontract.IntegerType),
) )
eMD := newEvent(eDesc) n.AddEvent("Vote",
n.AddEvent(eMD)
eDesc = newEventDescriptor("Vote",
manifest.NewParameter("account", smartcontract.Hash160Type), manifest.NewParameter("account", smartcontract.Hash160Type),
manifest.NewParameter("from", smartcontract.PublicKeyType), manifest.NewParameter("from", smartcontract.PublicKeyType),
manifest.NewParameter("to", smartcontract.PublicKeyType), manifest.NewParameter("to", smartcontract.PublicKeyType),
manifest.NewParameter("amount", smartcontract.IntegerType), manifest.NewParameter("amount", smartcontract.IntegerType),
) )
eMD = newEvent(eDesc) n.AddEvent("CommitteeChanged",
n.AddEvent(eMD)
eDesc = newEventDescriptor("CommitteeChanged",
manifest.NewParameter("old", smartcontract.ArrayType), manifest.NewParameter("old", smartcontract.ArrayType),
manifest.NewParameter("new", smartcontract.ArrayType), manifest.NewParameter("new", smartcontract.ArrayType),
) )
eMD = newEvent(eDesc, config.HFCockatrice)
n.AddEvent(eMD)
return n return n
} }
// Initialize initializes a NEO contract. // Initialize initializes a NEO contract.
func (n *NEO) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error { func (n *NEO) Initialize(ic *interop.Context) error {
if hf != n.ActiveIn() {
return nil
}
if err := n.nep17TokenNative.Initialize(ic); err != nil { if err := n.nep17TokenNative.Initialize(ic); err != nil {
return err return err
} }

View file

@ -6,7 +6,6 @@ import (
"math" "math"
"math/big" "math/big"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/dao"
"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/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
@ -46,9 +45,8 @@ func (c *nep17TokenNative) Metadata() *interop.ContractMD {
} }
func newNEP17Native(name string, id int32) *nep17TokenNative { func newNEP17Native(name string, id int32) *nep17TokenNative {
n := &nep17TokenNative{ContractMD: *interop.NewContractMD(name, id, func(m *manifest.Manifest) { n := &nep17TokenNative{ContractMD: *interop.NewContractMD(name, id)}
m.SupportedStandards = []string{manifest.NEP17StandardName} n.Manifest.SupportedStandards = []string{manifest.NEP17StandardName}
})}
desc := newDescriptor("symbol", smartcontract.StringType) desc := newDescriptor("symbol", smartcontract.StringType)
md := newMethodAndPrice(n.Symbol, 0, callflag.NoneFlag) md := newMethodAndPrice(n.Symbol, 0, callflag.NoneFlag)
@ -79,9 +77,7 @@ func newNEP17Native(name string, id int32) *nep17TokenNative {
md.StorageFee = 50 md.StorageFee = 50
n.AddMethod(md, desc) n.AddMethod(md, desc)
eDesc := newEventDescriptor("Transfer", transferParams...) n.AddEvent("Transfer", transferParams...)
eMD := newEvent(eDesc)
n.AddEvent(eMD)
return n return n
} }
@ -323,53 +319,12 @@ func newDescriptor(name string, ret smartcontract.ParamType, ps ...manifest.Para
} }
} }
// newMethodAndPrice builds method with the provided descriptor and ActiveFrom/ActiveTill hardfork func newMethodAndPrice(f interop.Method, cpuFee int64, flags callflag.CallFlag) *interop.MethodAndPrice {
// values consequently specified via activations. [config.HFDefault] specfied as ActiveFrom is treated return &interop.MethodAndPrice{
// as active starting from the genesis block. Func: f,
func newMethodAndPrice(f interop.Method, cpuFee int64, flags callflag.CallFlag, activations ...config.Hardfork) *interop.MethodAndPrice { CPUFee: cpuFee,
md := &interop.MethodAndPrice{ RequiredFlags: flags,
HFSpecificMethodAndPrice: interop.HFSpecificMethodAndPrice{
Func: f,
CPUFee: cpuFee,
RequiredFlags: flags,
},
} }
if len(activations) > 0 {
if activations[0] != config.HFDefault {
md.ActiveFrom = &activations[0]
}
}
if len(activations) > 1 {
md.ActiveTill = &activations[1]
}
return md
}
func newEventDescriptor(name string, ps ...manifest.Parameter) *manifest.Event {
if len(ps) == 0 {
ps = []manifest.Parameter{}
}
return &manifest.Event{
Name: name,
Parameters: ps,
}
}
// newEvent builds event with the provided descriptor and ActiveFrom/ActiveTill hardfork
// values consequently specified via activations.
func newEvent(desc *manifest.Event, activations ...config.Hardfork) interop.Event {
md := interop.Event{
HFSpecificEvent: interop.HFSpecificEvent{
MD: desc,
},
}
if len(activations) > 0 {
md.ActiveFrom = &activations[0]
}
if len(activations) > 1 {
md.ActiveTill = &activations[1]
}
return md
} }
func toBigInt(s stackitem.Item) *big.Int { func toBigInt(s stackitem.Item) *big.Int {

View file

@ -4,7 +4,6 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/nspcc-dev/neo-go/pkg/config"
"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/noderoles" "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
@ -20,11 +19,7 @@ import (
) )
func newNativeClient(t *testing.T, name string) *neotest.ContractInvoker { func newNativeClient(t *testing.T, name string) *neotest.ContractInvoker {
return newCustomNativeClient(t, name, nil) bc, acc := chain.NewSingle(t)
}
func newCustomNativeClient(t *testing.T, name string, f func(cfg *config.Blockchain)) *neotest.ContractInvoker {
bc, acc := chain.NewSingleWithCustomConfig(t, f)
e := neotest.NewExecutor(t, bc, acc, acc) e := neotest.NewExecutor(t, bc, acc, acc)
return e.CommitteeInvoker(e.NativeHash(t, name)) return e.CommitteeInvoker(e.NativeHash(t, name))

View file

@ -1,6 +1,7 @@
package native_test package native_test
import ( import (
"encoding/base64"
"math/big" "math/big"
"sort" "sort"
"testing" "testing"
@ -78,11 +79,11 @@ func TestCryptoLib_KoblitzVerificationScript(t *testing.T) {
// The user has to sign the hash of the message by his Koblitz key. // The user has to sign the hash of the message by his Koblitz key.
// Please, note that this Keccak256 hash may easily be replaced by sha256 hash if needed. // Please, note that this Keccak256 hash may easily be replaced by sha256 hash if needed.
signature := pk.SignHash(native.Keccak256(msg)) signature := pk.SignHash(hash.Keccak256(msg))
// Ensure that signature verification passes. This line here is just for testing purposes, // Ensure that signature verification passes. This line here is just for testing purposes,
// it won't be present in the real code. // it won't be present in the real code.
require.True(t, pk.PublicKey().Verify(signature, native.Keccak256(msg).BytesBE())) require.True(t, pk.PublicKey().Verify(signature, hash.Keccak256(msg).BytesBE()))
// Build invocation witness script for the user's account. // Build invocation witness script for the user's account.
invBytes := buildKoblitzInvocationScript(t, [][]byte{signature}) invBytes := buildKoblitzInvocationScript(t, [][]byte{signature})
@ -165,8 +166,8 @@ func buildKoblitzVerificationScript(t *testing.T, pub *keys.PublicKey) []byte {
// Concatenate network magic and transaction hash. // Concatenate network magic and transaction hash.
emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion.
// Continue construction of 'verifyWithECDsa' call. // Continue construction of 'verifyWithECDsa' call.
emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call.
emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself.
require.NoError(t, vrf.Err) require.NoError(t, vrf.Err)
return vrf.Bytes() return vrf.Bytes()
@ -175,7 +176,7 @@ func buildKoblitzVerificationScript(t *testing.T, pub *keys.PublicKey) []byte {
// READY: loaded 110 instructions // READY: loaded 110 instructions
// NEO-GO-VM 0 > ops // NEO-GO-VM 0 > ops
// INDEX OPCODE PARAMETER // INDEX OPCODE PARAMETER
// 0 PUSHINT8 122 (7a) << // 0 PUSHINT8 24 (18) <<
// 2 SWAP // 2 SWAP
// 3 PUSHDATA1 02a088bfab1e4b4bede7d4624572861b401cb20c3b14e90687bd8862272a4e6166 // 3 PUSHDATA1 02a088bfab1e4b4bede7d4624572861b401cb20c3b14e90687bd8862272a4e6166
// 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0)
@ -189,7 +190,7 @@ func buildKoblitzVerificationScript(t *testing.T, pub *keys.PublicKey) []byte {
// 62 CAT // 62 CAT
// 63 PUSH4 // 63 PUSH4
// 64 PACK // 64 PACK
// 65 PUSH0 // 65 PUSH15
// 66 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 66 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa")
// 83 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 83 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b")
// 105 SYSCALL System.Contract.Call (627d5b52) // 105 SYSCALL System.Contract.Call (627d5b52)
@ -222,8 +223,8 @@ func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.Publ
// Concatenate network magic and transaction hash. // Concatenate network magic and transaction hash.
emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion.
// Continue construction of 'verifyWithECDsa' call. // Continue construction of 'verifyWithECDsa' call.
emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call.
emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself.
require.NoError(t, vrf.Err) require.NoError(t, vrf.Err)
return vrf.Bytes() return vrf.Bytes()
@ -232,7 +233,7 @@ func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.Publ
// READY: loaded 98 instructions // READY: loaded 98 instructions
// NEO-GO-VM 0 > ops // NEO-GO-VM 0 > ops
// INDEX OPCODE PARAMETER // INDEX OPCODE PARAMETER
// 0 PUSHINT8 122 (7a) << // 0 PUSHINT8 24 (18) <<
// 2 SWAP // 2 SWAP
// 3 PUSHDATA1 0363d7a48125a76cdea6e098c9f128e82920ed428e5fb4caf1d7f81c16cad0c205 // 3 PUSHDATA1 0363d7a48125a76cdea6e098c9f128e82920ed428e5fb4caf1d7f81c16cad0c205
// 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0)
@ -242,7 +243,7 @@ func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.Publ
// 50 CAT // 50 CAT
// 51 PUSH4 // 51 PUSH4
// 52 PACK // 52 PACK
// 53 PUSH0 // 53 PUSH15
// 54 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 54 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa")
// 71 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 71 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b")
// 93 SYSCALL System.Contract.Call (627d5b52) // 93 SYSCALL System.Contract.Call (627d5b52)
@ -278,8 +279,8 @@ func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub
// Concatenate network magic and transaction hash. // Concatenate network magic and transaction hash.
emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion.
// Continue construction of 'verifyWithECDsa' call. // Continue construction of 'verifyWithECDsa' call.
emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call.
emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself.
require.NoError(t, vrf.Err) require.NoError(t, vrf.Err)
return vrf.Bytes() return vrf.Bytes()
@ -288,7 +289,7 @@ func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub
// READY: loaded 95 instructions // READY: loaded 95 instructions
// NEO-GO-VM 0 > ops // NEO-GO-VM 0 > ops
// INDEX OPCODE PARAMETER // INDEX OPCODE PARAMETER
// 0 PUSHINT8 122 (7a) << // 0 PUSHINT8 24 (18) <<
// 2 SWAP // 2 SWAP
// 3 PUSHDATA1 0296e13080ade92a2ab722338c2a249ee8d83a14f649c68321664165f06bd110bd // 3 PUSHDATA1 0296e13080ade92a2ab722338c2a249ee8d83a14f649c68321664165f06bd110bd
// 38 PUSHINT8 42 (2a) // 38 PUSHINT8 42 (2a)
@ -298,7 +299,7 @@ func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub
// 47 CAT // 47 CAT
// 48 PUSH4 // 48 PUSH4
// 49 PACK // 49 PACK
// 50 PUSH0 // 50 PUSH15
// 51 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 51 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa")
// 68 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 68 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b")
// 90 SYSCALL System.Contract.Call (627d5b52) // 90 SYSCALL System.Contract.Call (627d5b52)
@ -336,10 +337,10 @@ func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []b
opcode.CAT, // concatenate network magic and transaction hash; this instruction will convert network magic to bytes using BigInteger rules of conversion. opcode.CAT, // concatenate network magic and transaction hash; this instruction will convert network magic to bytes using BigInteger rules of conversion.
opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib). opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib).
opcode.PACK) // pack arguments for 'sha256' call. opcode.PACK) // pack arguments for 'sha256' call.
emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.NoneFlag) // emit the call to 'sha256' itself. emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.All) // emit the call to 'sha256' itself.
// Continue construction of 'verifyWithECDsa' call. // Continue construction of 'verifyWithECDsa' call.
emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call.
emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself.
require.NoError(t, vrf.Err) require.NoError(t, vrf.Err)
return vrf.Bytes() return vrf.Bytes()
@ -348,7 +349,7 @@ func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []b
// READY: loaded 136 instructions // READY: loaded 136 instructions
// NEO-GO-VM 0 > ops // NEO-GO-VM 0 > ops
// INDEX OPCODE PARAMETER // INDEX OPCODE PARAMETER
// 0 PUSHINT8 122 (7a) << // 0 PUSHINT8 24 (18) <<
// 2 SWAP // 2 SWAP
// 3 PUSHDATA1 03a77f137afbb4b68d7a450aa5a28fe335f804c589a808494b4b626eb98707f37d // 3 PUSHDATA1 03a77f137afbb4b68d7a450aa5a28fe335f804c589a808494b4b626eb98707f37d
// 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0)
@ -358,13 +359,13 @@ func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []b
// 50 CAT // 50 CAT
// 51 PUSH1 // 51 PUSH1
// 52 PACK // 52 PACK
// 53 PUSH0 // 53 PUSH15
// 54 PUSHDATA1 736861323536 ("sha256") // 54 PUSHDATA1 736861323536 ("sha256")
// 62 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 62 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b")
// 84 SYSCALL System.Contract.Call (627d5b52) // 84 SYSCALL System.Contract.Call (627d5b52)
// 89 PUSH4 // 89 PUSH4
// 90 PACK // 90 PACK
// 91 PUSH0 // 91 PUSH15
// 92 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 92 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa")
// 109 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 109 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b")
// 131 SYSCALL System.Contract.Call (627d5b52) // 131 SYSCALL System.Contract.Call (627d5b52)
@ -437,10 +438,10 @@ func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []b
opcode.CAT, // concatenate network magic and transaction hash. opcode.CAT, // concatenate network magic and transaction hash.
opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib). opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib).
opcode.PACK) // pack arguments for 'sha256' call. opcode.PACK) // pack arguments for 'sha256' call.
emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.NoneFlag) // emit the call to 'sha256' itself. emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.All) // emit the call to 'sha256' itself.
// Continue construction of 'verifyWithECDsa' call. // Continue construction of 'verifyWithECDsa' call.
emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call.
emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself.
require.NoError(t, vrf.Err) require.NoError(t, vrf.Err)
return vrf.Bytes() return vrf.Bytes()
@ -449,7 +450,7 @@ func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []b
// READY: loaded 186 instructions // READY: loaded 186 instructions
// NEO-GO-VM 0 > ops // NEO-GO-VM 0 > ops
// INDEX OPCODE PARAMETER // INDEX OPCODE PARAMETER
// 0 PUSHINT8 122 (7a) << // 0 PUSHINT8 24 (18) <<
// 2 SWAP // 2 SWAP
// 3 PUSHDATA1 02627ef9c3631e3ccb8fbc4c5b6c49e38ccede5a79afb1e1b0708fbb958a7802d7 // 3 PUSHDATA1 02627ef9c3631e3ccb8fbc4c5b6c49e38ccede5a79afb1e1b0708fbb958a7802d7
// 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0)
@ -501,13 +502,13 @@ func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []b
// 100 CAT // 100 CAT
// 101 PUSH1 // 101 PUSH1
// 102 PACK // 102 PACK
// 103 PUSH0 // 103 PUSH15
// 104 PUSHDATA1 736861323536 ("sha256") // 104 PUSHDATA1 736861323536 ("sha256")
// 112 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 112 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b")
// 134 SYSCALL System.Contract.Call (627d5b52) // 134 SYSCALL System.Contract.Call (627d5b52)
// 139 PUSH4 // 139 PUSH4
// 140 PACK // 140 PACK
// 141 PUSH0 // 141 PUSH15
// 142 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 142 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa")
// 159 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 159 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b")
// 181 SYSCALL System.Contract.Call (627d5b52) // 181 SYSCALL System.Contract.Call (627d5b52)
@ -651,7 +652,7 @@ func TestCryptoLib_KoblitzMultisigVerificationScript(t *testing.T) {
if i > 3 { if i > 3 {
j++ // Add more shift for large number of public keys for the same purpose. j++ // Add more shift for large number of public keys for the same purpose.
} }
sigs[i] = pks[j].SignHash(native.Keccak256(msg)) sigs[i] = pks[j].SignHash(hash.Keccak256(msg))
} }
// Build invocation witness script for the signatures. // Build invocation witness script for the signatures.
@ -674,7 +675,7 @@ func TestCryptoLib_KoblitzMultisigVerificationScript(t *testing.T) {
} }
// The proposed multisig verification script. // The proposed multisig verification script.
// (264 bytes, 8390070 GAS including Invocation script execution for 3/4 multisig). // (261 bytes, 8389470 GAS including Invocation script execution for 3/4 multisig).
// The user has to sign the keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]). // The user has to sign the keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]).
check(t, buildKoblitzMultisigVerificationScript, constructMessage) check(t, buildKoblitzMultisigVerificationScript, constructMessage)
} }
@ -714,11 +715,11 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi
vrf := io.NewBufBinWriter() vrf := io.NewBufBinWriter()
// Start the same way as regular multisig script. // Start the same way as regular multisig script.
emit.Int(vrf.BinWriter, int64(m)) // push m. emit.Int(vrf.BinWriter, int64(m))
for _, pub := range pubs { for _, pub := range pubs {
emit.Bytes(vrf.BinWriter, pub.Bytes()) // push public keys in compressed form. emit.Bytes(vrf.BinWriter, pub.Bytes())
} }
emit.Int(vrf.BinWriter, int64(n)) // push n. emit.Int(vrf.BinWriter, int64(n))
// Initialize slots for local variables. Locals slot scheme: // Initialize slots for local variables. Locals slot scheme:
// LOC0 -> sigs // LOC0 -> sigs
@ -726,32 +727,32 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi
// LOC2 -> msg (ByteString) // LOC2 -> msg (ByteString)
// LOC3 -> sigCnt (Integer) // LOC3 -> sigCnt (Integer)
// LOC4 -> pubCnt (Integer) // LOC4 -> pubCnt (Integer)
// LOC5 -> n // LOC5 -> N
// LOC6 -> m // LOC6 -> M
emit.InitSlot(vrf.BinWriter, 7, 0) emit.InitSlot(vrf.BinWriter, 7, 0)
// Store n. // Store N.
emit.Opcodes(vrf.BinWriter, opcode.STLOC5) emit.Opcodes(vrf.BinWriter, opcode.STLOC5)
// Pack public keys and store at LOC1. // Pack public keys and store at LOC1.
emit.Opcodes(vrf.BinWriter, opcode.LDLOC5) emit.Opcodes(vrf.BinWriter, opcode.LDLOC5)
emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC1) emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC1)
// Store m. // Store M.
emit.Opcodes(vrf.BinWriter, opcode.STLOC6) emit.Opcodes(vrf.BinWriter, opcode.STLOC6)
// Check the number of signatures is m. Abort the execution if not. // Check the number of signatures is m. Return false if not.
emit.Opcodes(vrf.BinWriter, opcode.DEPTH) // push the number of signatures onto stack. emit.Opcodes(vrf.BinWriter, opcode.DEPTH) // Push the number of signatures onto stack.
emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // load m. emit.Opcodes(vrf.BinWriter, opcode.LDLOC6)
emit.Instruction(vrf.BinWriter, opcode.JMPEQ, []byte{0}) // here and below short jumps are sufficient. emit.Instruction(vrf.BinWriter, opcode.JMPEQ, []byte{0}) // here and below short jumps are sufficient.
sigsLenCheckEndOffset := vrf.Len() // offset of the signatures count check. sigsLenCheckEndOffset := vrf.Len() // offset of the signatures count check.
emit.Opcodes(vrf.BinWriter, opcode.ABORT) // abort execution if length of the signatures not equal to m. emit.Opcodes(vrf.BinWriter, opcode.ABORT) // fail if length of the signatures not equal to M.
// Start the check. // Start the check.
checkStartOffset := vrf.Len() checkStartOffset := vrf.Len()
// Pack signatures and store at LOC0. // Pack signatures and store at LOC0.
emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // load m. emit.Opcodes(vrf.BinWriter, opcode.LDLOC6)
emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC0) emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC0)
// Get message and store it at LOC2. // Get message and store it at LOC2.
@ -794,7 +795,7 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi
opcode.PICKITEM, // pick pub at index pubCnt. opcode.PICKITEM, // pick pub at index pubCnt.
opcode.LDLOC2, // load msg. opcode.LDLOC2, // load msg.
opcode.PUSH4, opcode.PACK) // pack 4 arguments for 'verifyWithECDsa' call. opcode.PUSH4, opcode.PACK) // pack 4 arguments for 'verifyWithECDsa' call.
emit.AppCallNoArgs(vrf.BinWriter, cryptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. emit.AppCallNoArgs(vrf.BinWriter, cryptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself.
// Update loop variables. // Update loop variables.
emit.Opcodes(vrf.BinWriter, opcode.LDLOC3, opcode.ADD, opcode.STLOC3, // increment sigCnt if signature is valid. emit.Opcodes(vrf.BinWriter, opcode.LDLOC3, opcode.ADD, opcode.STLOC3, // increment sigCnt if signature is valid.
@ -819,8 +820,9 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi
script[loopEndOffset-1] = byte(loopStartOffset - loopEndOffset + 2) script[loopEndOffset-1] = byte(loopStartOffset - loopEndOffset + 2)
script[loopConditionOffset-1] = byte(progRetOffset - loopConditionOffset + 2) script[loopConditionOffset-1] = byte(progRetOffset - loopConditionOffset + 2)
require.Equal(t, "", base64.StdEncoding.EncodeToString(script))
return script return script
// Here's an example of the resulting single witness invocation script (264 bytes length, the length may vary depending on m/n): // Here's an example of the resulting single witness invocation script (261 bytes length, the length may vary depending on m/n):
// NEO-GO-VM > loadbase64 EwwhAg1khs9yqTuG8R7dEj8/GhCqKwkL+6shSOczeaHENFo8DCECibz2wVNY1zRkRCbn+Qr87lQFjStnrQrwv1CSoea/91sMIQPiiV+wNGl5g5SVULR+BM/G2n6WO0WrGIsq+GBRqQHYwAwhAuwZz40NwnerrmSusUUgNqsZiv0WFj3KQE1BYd7lU7mDFFcHAHVtwHF2Q24oAzhuwHBBxfug4AMAAAAAAQAAAJ4UjUEtUQgwEM6LchBzEHRrbrhsbbiSJEIAGGhrzmlszmoUwB8MD3ZlcmlmeVdpdGhFQ0RzYQwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUmuec2ycdCK5a26z // NEO-GO-VM > loadbase64 EwwhAg1khs9yqTuG8R7dEj8/GhCqKwkL+6shSOczeaHENFo8DCECibz2wVNY1zRkRCbn+Qr87lQFjStnrQrwv1CSoea/91sMIQPiiV+wNGl5g5SVULR+BM/G2n6WO0WrGIsq+GBRqQHYwAwhAuwZz40NwnerrmSusUUgNqsZiv0WFj3KQE1BYd7lU7mDFFcHAHVtwHF2Q24oAzhuwHBBxfug4AMAAAAAAQAAAJ4UjUEtUQgwEM6LchBzEHRrbrhsbbiSJEIAGGhrzmlszmoUwB8MD3ZlcmlmeVdpdGhFQ0RzYQwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUmuec2ycdCK5a26z
// READY: loaded 264 instructions // READY: loaded 264 instructions
// NEO-GO-VM 0 > ops // NEO-GO-VM 0 > ops
@ -866,7 +868,7 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi
// 193 GE // 193 GE
// 194 OR // 194 OR
// 195 JMPIF 261 (66/42) // 195 JMPIF 261 (66/42)
// 197 PUSHINT8 122 (7a) // 197 PUSHINT8 24 (18)
// 199 LDLOC0 // 199 LDLOC0
// 200 LDLOC3 // 200 LDLOC3
// 201 PICKITEM // 201 PICKITEM
@ -876,7 +878,7 @@ func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.Publi
// 205 LDLOC2 // 205 LDLOC2
// 206 PUSH4 // 206 PUSH4
// 207 PACK // 207 PACK
// 208 PUSH0 // 208 PUSH15
// 209 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 209 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa")
// 226 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 226 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b")
// 248 SYSCALL System.Contract.Call (627d5b52) // 248 SYSCALL System.Contract.Call (627d5b52)

View file

@ -6,13 +6,9 @@ import (
"fmt" "fmt"
"testing" "testing"
ojson "github.com/nspcc-dev/go-ordered-json"
"github.com/nspcc-dev/neo-go/internal/contracts" "github.com/nspcc-dev/neo-go/internal/contracts"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/chaindump" "github.com/nspcc-dev/neo-go/pkg/core/chaindump"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"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/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
@ -34,47 +30,10 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
var (
// defaultCSS holds serialized native contract states built for genesis block (with UpdateCounter 0)
// under assumption that all hardforks are disabled.
defaultCSS = map[string]string{
nativenames.Management: `{"id":-1,"hash":"0xfffdc93764dbaddd97c48f252a53ea4643faa3fd","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"ContractManagement","abi":{"methods":[{"name":"deploy","offset":0,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Array","safe":false},{"name":"deploy","offset":7,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Array","safe":false},{"name":"destroy","offset":14,"parameters":[],"returntype":"Void","safe":false},{"name":"getContract","offset":21,"parameters":[{"name":"hash","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getContractById","offset":28,"parameters":[{"name":"id","type":"Integer"}],"returntype":"Array","safe":true},{"name":"getContractHashes","offset":35,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getMinimumDeploymentFee","offset":42,"parameters":[],"returntype":"Integer","safe":true},{"name":"hasMethod","offset":49,"parameters":[{"name":"hash","type":"Hash160"},{"name":"method","type":"String"},{"name":"pcount","type":"Integer"}],"returntype":"Boolean","safe":true},{"name":"setMinimumDeploymentFee","offset":56,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"update","offset":63,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"update","offset":70,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false}],"events":[{"name":"Deploy","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Update","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Destroy","parameters":[{"name":"Hash","type":"Hash160"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
nativenames.StdLib: `{"id":-2,"hash":"0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1991619121},"manifest":{"name":"StdLib","abi":{"methods":[{"name":"atoi","offset":0,"parameters":[{"name":"value","type":"String"}],"returntype":"Integer","safe":true},{"name":"atoi","offset":7,"parameters":[{"name":"value","type":"String"},{"name":"base","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"base58CheckDecode","offset":14,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base58CheckEncode","offset":21,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base58Decode","offset":28,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base58Encode","offset":35,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base64Decode","offset":42,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base64Encode","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"deserialize","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"itoa","offset":63,"parameters":[{"name":"value","type":"Integer"}],"returntype":"String","safe":true},{"name":"itoa","offset":70,"parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","safe":true},{"name":"jsonDeserialize","offset":77,"parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"jsonSerialize","offset":84,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"memoryCompare","offset":91,"parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":98,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":105,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":112,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","safe":true},{"name":"serialize","offset":119,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"strLen","offset":126,"parameters":[{"name":"str","type":"String"}],"returntype":"Integer","safe":true},{"name":"stringSplit","offset":133,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","safe":true},{"name":"stringSplit","offset":140,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"},{"name":"removeEmptyEntries","type":"Boolean"}],"returntype":"Array","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":2135988409},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":42,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":63,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curve","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
nativenames.Ledger: `{"id":-4,"hash":"0xda65b600f7124ce6c79950c1772a36403104f2be","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"LedgerContract","abi":{"methods":[{"name":"currentHash","offset":0,"parameters":[],"returntype":"Hash256","safe":true},{"name":"currentIndex","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getBlock","offset":14,"parameters":[{"name":"indexOrHash","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"getTransaction","offset":21,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","safe":true},{"name":"getTransactionFromBlock","offset":28,"parameters":[{"name":"blockIndexOrHash","type":"ByteArray"},{"name":"txIndex","type":"Integer"}],"returntype":"Array","safe":true},{"name":"getTransactionHeight","offset":35,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","safe":true},{"name":"getTransactionSigners","offset":42,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","safe":true},{"name":"getTransactionVMState","offset":49,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
nativenames.Neo: `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":65467259},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getGasPerBlock","offset":49,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":56,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":63,"parameters":[],"returntype":"Integer","safe":true},{"name":"registerCandidate","offset":70,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":77,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":84,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":91,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":98,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":105,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":112,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":119,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":126,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`,
nativenames.Gas: `{"id":-6,"hash":"0xd2a4cff31913016155e38e474a2c06d08be276cf","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"GasToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"symbol","offset":14,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":28,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"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}`,
nativenames.Designation: `{"id":-8,"hash":"0x49cf4e5378ffcd4dec034fd98a174c5491e395e2","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0A=","checksum":983638438},"manifest":{"name":"RoleManagement","abi":{"methods":[{"name":"designateAsRole","offset":0,"parameters":[{"name":"role","type":"Integer"},{"name":"nodes","type":"Array"}],"returntype":"Void","safe":false},{"name":"getDesignatedByRole","offset":7,"parameters":[{"name":"role","type":"Integer"},{"name":"index","type":"Integer"}],"returntype":"Array","safe":true}],"events":[{"name":"Designation","parameters":[{"name":"Role","type":"Integer"},{"name":"BlockIndex","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
nativenames.Oracle: `{"id":-9,"hash":"0xfe924b7cfe89ddd271abaf7210a80a7e11178758","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"OracleContract","abi":{"methods":[{"name":"finish","offset":0,"parameters":[],"returntype":"Void","safe":false},{"name":"getPrice","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"request","offset":14,"parameters":[{"name":"url","type":"String"},{"name":"filter","type":"String"},{"name":"callback","type":"String"},{"name":"userData","type":"Any"},{"name":"gasForResponse","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setPrice","offset":21,"parameters":[{"name":"price","type":"Integer"}],"returntype":"Void","safe":false},{"name":"verify","offset":28,"parameters":[],"returntype":"Boolean","safe":true}],"events":[{"name":"OracleRequest","parameters":[{"name":"Id","type":"Integer"},{"name":"RequestContract","type":"Hash160"},{"name":"Url","type":"String"},{"name":"Filter","type":"String"}]},{"name":"OracleResponse","parameters":[{"name":"Id","type":"Integer"},{"name":"OriginalTx","type":"Hash256"}]}]},"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}`,
}
// cockatriceCSS holds serialized native contract states built for genesis block (with UpdateCounter 0)
// under assumption that hardforks from Aspidochelone to Cockatrice (included) are enabled.
cockatriceCSS = map[string]string{
nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"keccak256","offset":42,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":49,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":63,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":70,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
nativenames.Neo: `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1325686241},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommitteeAddress","offset":49,"parameters":[],"returntype":"Hash160","safe":true},{"name":"getGasPerBlock","offset":56,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":63,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":70,"parameters":[],"returntype":"Integer","safe":true},{"name":"registerCandidate","offset":77,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":84,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":91,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":98,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":105,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":112,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":119,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":126,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":133,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`,
}
)
func init() {
for k, v := range defaultCSS {
if _, ok := cockatriceCSS[k]; !ok {
cockatriceCSS[k] = v
}
}
}
func newManagementClient(t *testing.T) *neotest.ContractInvoker { func newManagementClient(t *testing.T) *neotest.ContractInvoker {
return newNativeClient(t, nativenames.Management) return newNativeClient(t, nativenames.Management)
} }
// newCustomManagementClient returns native Management invoker backed with chain with
// specified custom configuration.
func newCustomManagementClient(t *testing.T, f func(cfg *config.Blockchain)) *neotest.ContractInvoker {
return newCustomNativeClient(t, nativenames.Management, f)
}
func TestManagement_MinimumDeploymentFee(t *testing.T) { func TestManagement_MinimumDeploymentFee(t *testing.T) {
testGetSet(t, newManagementClient(t), "MinimumDeploymentFee", 10_00000000, 0, 0) testGetSet(t, newManagementClient(t), "MinimumDeploymentFee", 10_00000000, 0, 0)
} }
@ -84,253 +43,6 @@ func TestManagement_MinimumDeploymentFeeCache(t *testing.T) {
testGetSetCache(t, c, "MinimumDeploymentFee", 10_00000000) testGetSetCache(t, c, "MinimumDeploymentFee", 10_00000000)
} }
func TestManagement_GenesisNativeState(t *testing.T) {
// check ensures that contract state stored in native Management matches the expected one.
check := func(t *testing.T, c *neotest.ContractInvoker, expected map[string]string) {
for _, name := range nativenames.All {
h := state.CreateNativeContractHash(name)
c.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
si := stack[0]
var cs = &state.Contract{}
require.NoError(t, cs.FromStackItem(si), name)
jBytes, err := ojson.Marshal(cs)
require.NoError(t, err)
require.Equal(t, expected[name], string(jBytes), fmt.Errorf("contract %s state mismatch", name))
}, "getContract", h.BytesBE())
}
}
t.Run("disabled hardforks", func(t *testing.T) {
mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
cfg.Hardforks = map[string]uint32{}
cfg.P2PSigExtensions = true
})
check(t, mgmt, defaultCSS)
})
t.Run("remotely enabled hardforks", func(t *testing.T) {
mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
cfg.Hardforks = map[string]uint32{
config.HFAspidochelone.String(): 100500,
config.HFBasilisk.String(): 100500,
config.HFCockatrice.String(): 100500,
}
cfg.P2PSigExtensions = true
})
check(t, mgmt, defaultCSS)
})
t.Run("Aspidochelone enabled", func(t *testing.T) {
mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
cfg.Hardforks = map[string]uint32{
config.HFAspidochelone.String(): 0,
}
cfg.P2PSigExtensions = true
})
check(t, mgmt, defaultCSS)
})
t.Run("Basilisk enabled", func(t *testing.T) {
mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
cfg.Hardforks = map[string]uint32{
config.HFAspidochelone.String(): 0,
config.HFBasilisk.String(): 0,
}
cfg.P2PSigExtensions = true
})
check(t, mgmt, defaultCSS)
})
t.Run("Cockatrice enabled", func(t *testing.T) {
mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
cfg.Hardforks = map[string]uint32{
config.HFAspidochelone.String(): 0,
config.HFBasilisk.String(): 0,
config.HFCockatrice.String(): 0,
}
cfg.P2PSigExtensions = true
})
check(t, mgmt, cockatriceCSS)
})
}
func TestManagement_NativeDeployUpdateNotifications(t *testing.T) {
const cockatriceHeight = 3
mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
cfg.Hardforks = map[string]uint32{
config.HFAspidochelone.String(): 0,
config.HFBasilisk.String(): 0,
config.HFCockatrice.String(): cockatriceHeight,
}
cfg.P2PSigExtensions = true
})
e := mgmt.Executor
// Check Deploy notifications.
aer, err := mgmt.Chain.GetAppExecResults(e.GetBlockByIndex(t, 0).Hash(), trigger.OnPersist)
require.NoError(t, err)
require.Equal(t, 1, len(aer))
var expected []state.NotificationEvent
for _, name := range nativenames.All {
switch name {
case nativenames.Gas:
expected = append(expected, state.NotificationEvent{
ScriptHash: nativehashes.GasToken,
Name: "Transfer",
Item: stackitem.NewArray([]stackitem.Item{
stackitem.Null{},
stackitem.Make(mgmt.Validator.ScriptHash()),
stackitem.Make(mgmt.Chain.GetConfig().InitialGASSupply),
}),
})
case nativenames.Neo:
expected = append(expected, state.NotificationEvent{
ScriptHash: nativehashes.NeoToken,
Name: "Transfer",
Item: stackitem.NewArray([]stackitem.Item{
stackitem.Null{},
stackitem.Make(mgmt.Validator.ScriptHash()),
stackitem.Make(native.NEOTotalSupply),
}),
})
}
expected = append(expected, state.NotificationEvent{
ScriptHash: nativehashes.ContractManagement,
Name: "Deploy",
Item: stackitem.NewArray([]stackitem.Item{
stackitem.Make(state.CreateNativeContractHash(name)),
}),
})
}
require.Equal(t, expected, aer[0].Events)
// Generate some blocks and check Update notifications.
cockatriceBlock := mgmt.GenerateNewBlocks(t, cockatriceHeight)[cockatriceHeight-1]
aer, err = mgmt.Chain.GetAppExecResults(cockatriceBlock.Hash(), trigger.OnPersist)
require.NoError(t, err)
require.Equal(t, 1, len(aer))
expected = expected[:0]
for _, name := range []string{nativenames.CryptoLib, nativenames.Neo} {
expected = append(expected, state.NotificationEvent{
ScriptHash: nativehashes.ContractManagement,
Name: "Update",
Item: stackitem.NewArray([]stackitem.Item{
stackitem.Make(state.CreateNativeContractHash(name)),
}),
})
}
require.Equal(t, expected, aer[0].Events)
}
func TestManagement_NativeUpdate(t *testing.T) {
const cockatriceHeight = 3
c := newCustomManagementClient(t, func(cfg *config.Blockchain) {
cfg.Hardforks = map[string]uint32{
config.HFAspidochelone.String(): 0,
config.HFBasilisk.String(): 0,
config.HFCockatrice.String(): cockatriceHeight,
}
cfg.P2PSigExtensions = true
})
// Add some blocks up to the Cockatrice enabling height and check the default natives state.
for i := 0; i < cockatriceHeight-1; i++ {
c.AddNewBlock(t)
for _, name := range nativenames.All {
h := state.CreateNativeContractHash(name)
cs := c.Chain.GetContractState(h)
require.NotNil(t, cs, name)
jBytes, err := ojson.Marshal(cs)
require.NoError(t, err, name)
require.Equal(t, defaultCSS[name], string(jBytes), fmt.Errorf("contract %s state mismatch", name))
}
}
// Add Cockatrice block and check the updated native state.
c.AddNewBlock(t)
for _, name := range nativenames.All {
h := state.CreateNativeContractHash(name)
cs := c.Chain.GetContractState(h)
require.NotNil(t, cs, name)
if name == nativenames.Neo || name == nativenames.CryptoLib {
// A tiny hack to reuse cockatriceCSS map in the check below.
require.Equal(t, uint16(1), cs.UpdateCounter, name)
cs.UpdateCounter--
}
jBytes, err := ojson.Marshal(cs)
require.NoError(t, err, name)
require.Equal(t, cockatriceCSS[name], string(jBytes), fmt.Errorf("contract %s state mismatch", name))
}
}
func TestManagement_NativeUpdate_Call(t *testing.T) {
const (
cockatriceHeight = 3
method = "getCommitteeAddress"
)
c := newCustomNativeClient(t, nativenames.Neo, func(cfg *config.Blockchain) {
cfg.Hardforks = map[string]uint32{
config.HFAspidochelone.String(): 0,
config.HFBasilisk.String(): 0,
config.HFCockatrice.String(): cockatriceHeight,
}
cfg.P2PSigExtensions = true
})
// Invoke Cockatrice-dependant method before Cockatrice should fail.
for i := 0; i < cockatriceHeight-1; i++ {
c.InvokeFail(t, "at instruction 45 (SYSCALL): System.Contract.Call failed: method not found: getCommitteeAddress/0", method)
}
// Invoke Cockatrice-dependant method at Cockatrice should be OK.
tx := c.NewUnsignedTx(t, c.Hash, method)
c.SignTx(t, tx, 1_0000_0000, c.Signers...)
c.AddNewBlock(t, tx)
c.CheckHalt(t, tx.Hash(), stackitem.Make(c.CommitteeHash))
// Invoke Cockatrice-dependant method after Cockatrice should be OK.
c.Invoke(t, c.CommitteeHash, method)
}
// TestBlockchain_GetNatives ensures that Blockchain's GetNatives API works as expected with
// different block heights depending on hardfork settings. This test is located here since it
// depends on defaultCSS and cockatriceCSS.
func TestBlockchain_GetNatives(t *testing.T) {
const cockatriceHeight = 3
bc, acc := chain.NewSingleWithCustomConfig(t, func(cfg *config.Blockchain) {
cfg.Hardforks = map[string]uint32{
config.HFAspidochelone.String(): 0,
config.HFBasilisk.String(): 0,
config.HFCockatrice.String(): cockatriceHeight,
}
cfg.P2PSigExtensions = true
})
e := neotest.NewExecutor(t, bc, acc, acc)
// Check genesis-based native contract states.
natives := bc.GetNatives()
require.Equal(t, len(nativenames.All), len(natives))
for _, cs := range natives {
csFull := state.Contract{
ContractBase: cs.ContractBase,
UpdateCounter: 0,
}
jBytes, err := ojson.Marshal(csFull)
require.NoError(t, err, cs.Manifest.Name)
require.Equal(t, defaultCSS[cs.Manifest.Name], string(jBytes), fmt.Errorf("contract %s state mismatch", cs.Manifest.Name))
}
// Check native state after update.
e.GenerateNewBlocks(t, cockatriceHeight)
natives = bc.GetNatives()
require.Equal(t, len(nativenames.All), len(natives))
for _, cs := range natives {
csFull := state.Contract{
ContractBase: cs.ContractBase,
UpdateCounter: 0, // Since we're comparing only state.NativeContract part, set the update counter to 0 to match the cockatriceCSS.
}
jBytes, err := ojson.Marshal(csFull)
require.NoError(t, err, cs.Manifest.Name)
require.Equal(t, cockatriceCSS[cs.Manifest.Name], string(jBytes), fmt.Errorf("contract %s state mismatch", cs.Manifest.Name))
}
}
func TestManagement_ContractCache(t *testing.T) { func TestManagement_ContractCache(t *testing.T) {
c := newManagementClient(t) c := newManagementClient(t)
managementInvoker := c.WithSigners(c.Committee) managementInvoker := c.WithSigners(c.Committee)

View file

@ -39,7 +39,7 @@ func newNeoCommitteeClient(t *testing.T, expectedGASBalance int) *neotest.Contra
e := neotest.NewExecutor(t, bc, validators, committee) e := neotest.NewExecutor(t, bc, validators, committee)
if expectedGASBalance > 0 { if expectedGASBalance > 0 {
e.ValidatorInvoker(e.NativeHash(t, nativenames.Gas)).Invoke(t, true, "transfer", e.Validator.ScriptHash(), e.CommitteeHash, expectedGASBalance, nil) e.ValidatorInvoker(e.NativeHash(t, nativenames.Gas)).Invoke(t, true, "transfer", e.Validator.ScriptHash(), e.CommitteeHash, 100_0000_0000, nil)
} }
return e.CommitteeInvoker(e.NativeHash(t, nativenames.Neo)) return e.CommitteeInvoker(e.NativeHash(t, nativenames.Neo))

View file

@ -1,70 +0,0 @@
//go:build ignore
// This program generates hashes.go. It can be invoked by running
// go generate.
package main
import (
"fmt"
"log"
"os"
"text/template"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/state"
)
// srcTmpl is a nativehashes package template.
const srcTmpl = `// Code generated by "go generate go run gen.go"; DO NOT EDIT.
//go:generate go run gen.go
// package nativehashes contains hashes of all native contracts in their LE and Uint160 representation.
package nativehashes
import "github.com/nspcc-dev/neo-go/pkg/util"
// Hashes of all native contracts.
var (
{{- range .Natives }}
// {{ .Name }} is a hash of native {{ .Name }} contract.
{{ .Name }} = {{ .Hash }}
{{- end }}
)
`
type (
// Config contains parameters for the nativehashes package generation.
Config struct {
Natives []NativeInfo
}
// NativeInfo contains information about native contract needed for
// nativehashes package generation.
NativeInfo struct {
Name string
Hash string
}
)
// srcTemplate is a parsed nativehashes package template.
var srcTemplate = template.Must(template.New("nativehashes").Parse(srcTmpl))
func main() {
f, err := os.Create("hashes.go")
if err != nil {
log.Fatal(err)
}
defer f.Close()
var cfg = Config{Natives: make([]NativeInfo, len(nativenames.All))}
for i, name := range nativenames.All {
var hash = state.CreateNativeContractHash(name)
cfg.Natives[i] = NativeInfo{
Name: name,
Hash: fmt.Sprintf("%#v", hash),
}
}
srcTemplate.Execute(f, cfg)
}

View file

@ -1,32 +0,0 @@
// Code generated by "go generate go run gen.go"; DO NOT EDIT.
//go:generate go run gen.go
// package nativehashes contains hashes of all native contracts in their LE and Uint160 representation.
package nativehashes
import "github.com/nspcc-dev/neo-go/pkg/util"
// Hashes of all native contracts.
var (
// ContractManagement is a hash of native ContractManagement contract.
ContractManagement = util.Uint160{0xfd, 0xa3, 0xfa, 0x43, 0x46, 0xea, 0x53, 0x2a, 0x25, 0x8f, 0xc4, 0x97, 0xdd, 0xad, 0xdb, 0x64, 0x37, 0xc9, 0xfd, 0xff}
// StdLib is a hash of native StdLib contract.
StdLib = util.Uint160{0xc0, 0xef, 0x39, 0xce, 0xe0, 0xe4, 0xe9, 0x25, 0xc6, 0xc2, 0xa0, 0x6a, 0x79, 0xe1, 0x44, 0xd, 0xd8, 0x6f, 0xce, 0xac}
// CryptoLib is a hash of native CryptoLib contract.
CryptoLib = util.Uint160{0x1b, 0xf5, 0x75, 0xab, 0x11, 0x89, 0x68, 0x84, 0x13, 0x61, 0xa, 0x35, 0xa1, 0x28, 0x86, 0xcd, 0xe0, 0xb6, 0x6c, 0x72}
// LedgerContract is a hash of native LedgerContract contract.
LedgerContract = util.Uint160{0xbe, 0xf2, 0x4, 0x31, 0x40, 0x36, 0x2a, 0x77, 0xc1, 0x50, 0x99, 0xc7, 0xe6, 0x4c, 0x12, 0xf7, 0x0, 0xb6, 0x65, 0xda}
// NeoToken is a hash of native NeoToken contract.
NeoToken = util.Uint160{0xf5, 0x63, 0xea, 0x40, 0xbc, 0x28, 0x3d, 0x4d, 0xe, 0x5, 0xc4, 0x8e, 0xa3, 0x5, 0xb3, 0xf2, 0xa0, 0x73, 0x40, 0xef}
// GasToken is a hash of native GasToken contract.
GasToken = util.Uint160{0xcf, 0x76, 0xe2, 0x8b, 0xd0, 0x6, 0x2c, 0x4a, 0x47, 0x8e, 0xe3, 0x55, 0x61, 0x1, 0x13, 0x19, 0xf3, 0xcf, 0xa4, 0xd2}
// PolicyContract is a hash of native PolicyContract contract.
PolicyContract = util.Uint160{0x7b, 0xc6, 0x81, 0xc0, 0xa1, 0xf7, 0x1d, 0x54, 0x34, 0x57, 0xb6, 0x8b, 0xba, 0x8d, 0x5f, 0x9f, 0xdd, 0x4e, 0x5e, 0xcc}
// RoleManagement is a hash of native RoleManagement contract.
RoleManagement = util.Uint160{0xe2, 0x95, 0xe3, 0x91, 0x54, 0x4c, 0x17, 0x8a, 0xd9, 0x4f, 0x3, 0xec, 0x4d, 0xcd, 0xff, 0x78, 0x53, 0x4e, 0xcf, 0x49}
// OracleContract is a hash of native OracleContract contract.
OracleContract = util.Uint160{0x58, 0x87, 0x17, 0x11, 0x7e, 0xa, 0xa8, 0x10, 0x72, 0xaf, 0xab, 0x71, 0xd2, 0xdd, 0x89, 0xfe, 0x7c, 0x4b, 0x92, 0xfe}
// Notary is a hash of native Notary contract.
Notary = util.Uint160{0x3b, 0xec, 0x35, 0x31, 0x11, 0x9b, 0xba, 0xd7, 0x6d, 0xd0, 0x44, 0x92, 0xb, 0xd, 0xe6, 0xc3, 0x19, 0x4f, 0xe1, 0xc1}
)

View file

@ -14,20 +14,6 @@ const (
StdLib = "StdLib" StdLib = "StdLib"
) )
// All contains the list of all native contract names ordered by the contract ID.
var All = []string{
Management,
StdLib,
CryptoLib,
Ledger,
Neo,
Gas,
Policy,
Designation,
Oracle,
Notary,
}
// IsValid checks if the name is a valid native contract's name. // IsValid checks if the name is a valid native contract's name.
func IsValid(name string) bool { func IsValid(name string) bool {
return name == Management || return name == Management ||

View file

@ -73,7 +73,7 @@ func copyNotaryCache(src, dst *NotaryCache) {
// newNotary returns Notary native contract. // newNotary returns Notary native contract.
func newNotary() *Notary { func newNotary() *Notary {
n := &Notary{ContractMD: *interop.NewContractMD(nativenames.Notary, notaryContractID)} n := &Notary{ContractMD: *interop.NewContractMD(nativenames.Notary, notaryContractID)}
defer n.BuildHFSpecificMD(n.ActiveIn()) defer n.UpdateHash()
desc := newDescriptor("onNEP17Payment", smartcontract.VoidType, desc := newDescriptor("onNEP17Payment", smartcontract.VoidType,
manifest.NewParameter("from", smartcontract.Hash160Type), manifest.NewParameter("from", smartcontract.Hash160Type),
@ -127,11 +127,7 @@ func (n *Notary) Metadata() *interop.ContractMD {
} }
// Initialize initializes Notary native contract and implements the Contract interface. // Initialize initializes Notary native contract and implements the Contract interface.
func (n *Notary) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error { func (n *Notary) Initialize(ic *interop.Context) error {
if hf != n.ActiveIn() {
return nil
}
setIntWithKey(n.ID, ic.DAO, maxNotValidBeforeDeltaKey, defaultMaxNotValidBeforeDelta) setIntWithKey(n.ID, ic.DAO, maxNotValidBeforeDeltaKey, defaultMaxNotValidBeforeDelta)
cache := &NotaryCache{ cache := &NotaryCache{

View file

@ -118,7 +118,7 @@ func newOracle() *Oracle {
ContractMD: *interop.NewContractMD(nativenames.Oracle, oracleContractID), ContractMD: *interop.NewContractMD(nativenames.Oracle, oracleContractID),
newRequests: make(map[uint64]*state.OracleRequest), newRequests: make(map[uint64]*state.OracleRequest),
} }
defer o.BuildHFSpecificMD(o.ActiveIn()) defer o.UpdateHash()
o.oracleScript = CreateOracleResponseScript(o.Hash) o.oracleScript = CreateOracleResponseScript(o.Hash)
@ -139,17 +139,12 @@ func newOracle() *Oracle {
md = newMethodAndPrice(o.verify, 1<<15, callflag.NoneFlag) md = newMethodAndPrice(o.verify, 1<<15, callflag.NoneFlag)
o.AddMethod(md, desc) o.AddMethod(md, desc)
eDesc := newEventDescriptor("OracleRequest", manifest.NewParameter("Id", smartcontract.IntegerType), o.AddEvent("OracleRequest", manifest.NewParameter("Id", smartcontract.IntegerType),
manifest.NewParameter("RequestContract", smartcontract.Hash160Type), manifest.NewParameter("RequestContract", smartcontract.Hash160Type),
manifest.NewParameter("Url", smartcontract.StringType), manifest.NewParameter("Url", smartcontract.StringType),
manifest.NewParameter("Filter", smartcontract.StringType)) manifest.NewParameter("Filter", smartcontract.StringType))
eMD := newEvent(eDesc) o.AddEvent("OracleResponse", manifest.NewParameter("Id", smartcontract.IntegerType),
o.AddEvent(eMD)
eDesc = newEventDescriptor("OracleResponse", manifest.NewParameter("Id", smartcontract.IntegerType),
manifest.NewParameter("OriginalTx", smartcontract.Hash256Type)) manifest.NewParameter("OriginalTx", smartcontract.Hash256Type))
eMD = newEvent(eDesc)
o.AddEvent(eMD)
desc = newDescriptor("getPrice", smartcontract.IntegerType) desc = newDescriptor("getPrice", smartcontract.IntegerType)
md = newMethodAndPrice(o.getPrice, 1<<15, callflag.ReadStates) md = newMethodAndPrice(o.getPrice, 1<<15, callflag.ReadStates)
@ -246,28 +241,14 @@ func (o *Oracle) Metadata() *interop.ContractMD {
} }
// Initialize initializes an Oracle contract. // Initialize initializes an Oracle contract.
func (o *Oracle) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error { func (o *Oracle) Initialize(ic *interop.Context) error {
switch hf { setIntWithKey(o.ID, ic.DAO, prefixRequestID, 0)
case o.ActiveIn(): setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, DefaultOracleRequestPrice)
setIntWithKey(o.ID, ic.DAO, prefixRequestID, 0)
setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, DefaultOracleRequestPrice)
cache := &OracleCache{ cache := &OracleCache{
requestPrice: int64(DefaultOracleRequestPrice), requestPrice: int64(DefaultOracleRequestPrice),
}
ic.DAO.SetCache(o.ID, cache)
default:
orc, _ := o.Module.Load().(*OracleService)
if orc != nil && *orc != nil {
md, ok := newMD.GetMethod(manifest.MethodVerify, -1)
if !ok {
panic(fmt.Errorf("%s method not found", manifest.MethodVerify))
}
(*orc).UpdateNativeContract(newMD.NEF.Script, o.GetOracleResponseScript(),
o.Hash, md.MD.Offset)
}
} }
ic.DAO.SetCache(o.ID, cache)
return nil return nil
} }

View file

@ -105,7 +105,7 @@ func newPolicy(p2pSigExtensionsEnabled bool) *Policy {
ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID), ContractMD: *interop.NewContractMD(nativenames.Policy, policyContractID),
p2pSigExtensionsEnabled: p2pSigExtensionsEnabled, p2pSigExtensionsEnabled: p2pSigExtensionsEnabled,
} }
defer p.BuildHFSpecificMD(p.ActiveIn()) defer p.UpdateHash()
desc := newDescriptor("getFeePerByte", smartcontract.IntegerType) desc := newDescriptor("getFeePerByte", smartcontract.IntegerType)
md := newMethodAndPrice(p.getFeePerByte, 1<<15, callflag.ReadStates) md := newMethodAndPrice(p.getFeePerByte, 1<<15, callflag.ReadStates)
@ -169,11 +169,7 @@ 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) error {
if hf != p.ActiveIn() {
return nil
}
setIntWithKey(p.ID, ic.DAO, feePerByteKey, defaultFeePerByte) setIntWithKey(p.ID, ic.DAO, feePerByteKey, defaultFeePerByte)
setIntWithKey(p.ID, ic.DAO, execFeeFactorKey, defaultExecFeeFactor) setIntWithKey(p.ID, ic.DAO, execFeeFactorKey, defaultExecFeeFactor)
setIntWithKey(p.ID, ic.DAO, storagePriceKey, DefaultStoragePrice) setIntWithKey(p.ID, ic.DAO, storagePriceKey, DefaultStoragePrice)
@ -319,7 +315,7 @@ func (p *Policy) IsBlocked(dao *dao.Simple, hash util.Uint160) bool {
cache := dao.GetROCache(p.ID) cache := dao.GetROCache(p.ID)
if cache == nil { if cache == nil {
key := append([]byte{blockedAccountPrefix}, hash.BytesBE()...) key := append([]byte{blockedAccountPrefix}, hash.BytesBE()...)
return dao.GetStorageItem(p.ID, key) != nil return dao.GetStorageItem(p.ID, key) == nil
} }
_, isBlocked := p.isBlockedInternal(cache.(*PolicyCache), hash) _, isBlocked := p.isBlockedInternal(cache.(*PolicyCache), hash)
return isBlocked return isBlocked

View file

@ -46,7 +46,7 @@ var (
func newStd() *Std { func newStd() *Std {
s := &Std{ContractMD: *interop.NewContractMD(nativenames.StdLib, stdContractID)} s := &Std{ContractMD: *interop.NewContractMD(nativenames.StdLib, stdContractID)}
defer s.BuildHFSpecificMD(s.ActiveIn()) defer s.UpdateHash()
desc := newDescriptor("serialize", smartcontract.ByteArrayType, desc := newDescriptor("serialize", smartcontract.ByteArrayType,
manifest.NewParameter("item", smartcontract.AnyType)) manifest.NewParameter("item", smartcontract.AnyType))
@ -439,7 +439,7 @@ func (s *Std) Metadata() *interop.ContractMD {
} }
// Initialize implements the Contract interface. // Initialize implements the Contract interface.
func (s *Std) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error { func (s *Std) Initialize(ic *interop.Context) error {
return nil return nil
} }

View file

@ -29,6 +29,11 @@ type ContractBase struct {
Manifest manifest.Manifest `json:"manifest"` Manifest manifest.Manifest `json:"manifest"`
} }
// NativeContract holds information about the native contract.
type NativeContract struct {
ContractBase
}
// ToStackItem converts state.Contract to stackitem.Item. // ToStackItem converts state.Contract to stackitem.Item.
func (c *Contract) ToStackItem() (stackitem.Item, error) { func (c *Contract) ToStackItem() (stackitem.Item, error) {
// Do not skip the NEF size check, it won't affect native Management related // Do not skip the NEF size check, it won't affect native Management related

View file

@ -77,8 +77,11 @@ func NewBoltDBStore(cfg dbconfig.BoltDBOptions) (*BoltDBStore, error) {
func (s *BoltDBStore) Get(key []byte) (val []byte, err error) { func (s *BoltDBStore) Get(key []byte) (val []byte, err error) {
err = s.db.View(func(tx *bbolt.Tx) error { err = s.db.View(func(tx *bbolt.Tx) error {
b := tx.Bucket(Bucket) b := tx.Bucket(Bucket)
val = b.Get(key)
// Value from Get is only valid for the lifetime of transaction, #1482 // Value from Get is only valid for the lifetime of transaction, #1482
val = bytes.Clone(b.Get(key)) if val != nil {
val = bytes.Clone(val)
}
return nil return nil
}) })
if val == nil { if val == nil {

View file

@ -26,6 +26,8 @@ const (
// MaxAttributes is maximum number of attributes including signers that can be contained // MaxAttributes is maximum number of attributes including signers that can be contained
// within a transaction. It is set to be 16. // within a transaction. It is set to be 16.
MaxAttributes = 16 MaxAttributes = 16
// DummyVersion represents reserved transaction version for trimmed transactions.
DummyVersion = 255
) )
// ErrInvalidWitnessNum returns when the number of witnesses does not match signers. // ErrInvalidWitnessNum returns when the number of witnesses does not match signers.
@ -406,7 +408,7 @@ var (
// isValid checks whether decoded/unmarshalled transaction has all fields valid. // isValid checks whether decoded/unmarshalled transaction has all fields valid.
func (t *Transaction) isValid() error { func (t *Transaction) isValid() error {
if t.Version > 0 { if t.Version > 0 && t.Version != DummyVersion {
return ErrInvalidVersion return ErrInvalidVersion
} }
if t.SystemFee < 0 { if t.SystemFee < 0 {

View file

@ -6,6 +6,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"golang.org/x/crypto/ripemd160" //nolint:staticcheck // SA1019: package golang.org/x/crypto/ripemd160 is deprecated "golang.org/x/crypto/ripemd160" //nolint:staticcheck // SA1019: package golang.org/x/crypto/ripemd160 is deprecated
"golang.org/x/crypto/sha3"
) )
// Hashable represents an object which can be hashed. Usually, these objects // Hashable represents an object which can be hashed. Usually, these objects
@ -49,6 +50,17 @@ func DoubleSha256(data []byte) util.Uint256 {
return hash return hash
} }
// Keccak256 hashes the incoming byte slice using the
// keccak256 algorithm.
func Keccak256(data []byte) util.Uint256 {
var hash util.Uint256
hasher := sha3.NewLegacyKeccak256() // TODO: @roman-khimov, can we allow to replace it with New256? I don't think we ever need non-standard padding support.
_, _ = hasher.Write(data)
hasher.Sum(hash[:0])
return hash
}
// RipeMD160 performs the RIPEMD160 hash algorithm // RipeMD160 performs the RIPEMD160 hash algorithm
// on the given data. // on the given data.
func RipeMD160(data []byte) util.Uint160 { func RipeMD160(data []byte) util.Uint160 {

View file

@ -50,6 +50,16 @@ func TestHash160(t *testing.T) {
assert.Equal(t, expected, actual) assert.Equal(t, expected, actual)
} }
func TestKeccak256(t *testing.T) {
input := []byte("hello")
data := Keccak256(input)
expected := "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
actual := hex.EncodeToString(data.BytesBE())
assert.Equal(t, expected, actual)
}
func TestChecksum(t *testing.T) { func TestChecksum(t *testing.T) {
testCases := []struct { testCases := []struct {
data []byte data []byte

View file

@ -20,8 +20,8 @@ type NamedCurveHash byte
const ( const (
Secp256k1Sha256 NamedCurveHash = 22 Secp256k1Sha256 NamedCurveHash = 22
Secp256r1Sha256 NamedCurveHash = 23 Secp256r1Sha256 NamedCurveHash = 23
Secp256k1Keccak256 NamedCurveHash = 122 Secp256k1Keccak256 NamedCurveHash = 24
Secp256r1Keccak256 NamedCurveHash = 123 Secp256r1Keccak256 NamedCurveHash = 25
) )
// Sha256 calls `sha256` method of native CryptoLib contract and computes SHA256 hash of b. // Sha256 calls `sha256` method of native CryptoLib contract and computes SHA256 hash of b.

View file

@ -22,7 +22,8 @@ const (
StateValidator Role = 4 StateValidator Role = 4
Oracle Role = 8 Oracle Role = 8
NeoFSAlphabet Role = 16 NeoFSAlphabet Role = 16
P2PNotary Role = 32 // P2PNotary is an extension of Neo protocol available on specifically configured NeoGo networks.
P2PNotary Role = 32
) )
// GetDesignatedByRole represents `getDesignatedByRole` method of RoleManagement native contract. // GetDesignatedByRole represents `getDesignatedByRole` method of RoleManagement native contract.

View file

@ -44,13 +44,12 @@ const (
) )
var ( var (
errAlreadyConnected = errors.New("already connected") errAlreadyConnected = errors.New("already connected")
errIdenticalID = errors.New("identical node id") errIdenticalID = errors.New("identical node id")
errInvalidNetwork = errors.New("invalid network") errInvalidNetwork = errors.New("invalid network")
errMaxPeers = errors.New("max peers reached") errMaxPeers = errors.New("max peers reached")
errServerShutdown = errors.New("server shutdown") errServerShutdown = errors.New("server shutdown")
errInvalidInvType = errors.New("invalid inventory type") errInvalidInvType = errors.New("invalid inventory type")
errBlocksRequestFailed = errors.New("blocks request failed")
) )
type ( type (
@ -513,17 +512,10 @@ func (s *Server) run() {
if s.peers[drop.peer] { if s.peers[drop.peer] {
delete(s.peers, drop.peer) delete(s.peers, drop.peer)
s.lock.Unlock() s.lock.Unlock()
if errors.Is(drop.reason, errInvalidInvType) || errors.Is(drop.reason, errStateMismatch) || errors.Is(drop.reason, errBlocksRequestFailed) { s.log.Warn("peer disconnected",
s.log.Warn("peer disconnected", zap.Stringer("addr", drop.peer.RemoteAddr()),
zap.Stringer("addr", drop.peer.RemoteAddr()), zap.Error(drop.reason),
zap.Error(drop.reason), zap.Int("peerCount", s.PeerCount()))
zap.Int("peerCount", s.PeerCount()))
} else {
s.log.Info("peer disconnected",
zap.Stringer("addr", drop.peer.RemoteAddr()),
zap.Error(drop.reason),
zap.Int("peerCount", s.PeerCount()))
}
if errors.Is(drop.reason, errIdenticalID) { if errors.Is(drop.reason, errIdenticalID) {
s.discovery.RegisterSelf(drop.peer) s.discovery.RegisterSelf(drop.peer)
} else { } else {
@ -801,7 +793,7 @@ func (s *Server) requestBlocksOrHeaders(p Peer) error {
} }
err := s.requestBlocks(bq, p) err := s.requestBlocks(bq, p)
if err != nil { if err != nil {
return fmt.Errorf("%w: %w", errBlocksRequestFailed, err) return err
} }
if requestMPTNodes { if requestMPTNodes {
return s.requestMPTNodes(p, s.stateSync.GetUnknownMPTNodesBatch(payload.MaxMPTHashesCount)) return s.requestMPTNodes(p, s.stateSync.GetUnknownMPTNodesBatch(payload.MaxMPTHashesCount))
@ -1353,7 +1345,7 @@ func (s *Server) handleMessage(peer Peer, msg *Message) error {
if peer.Handshaked() { if peer.Handshaked() {
if inv, ok := msg.Payload.(*payload.Inventory); ok { if inv, ok := msg.Payload.(*payload.Inventory); ok {
if !inv.Type.Valid(s.chain.P2PSigExtensionsEnabled()) || len(inv.Hashes) == 0 { if !inv.Type.Valid(s.chain.P2PSigExtensionsEnabled()) || len(inv.Hashes) == 0 {
return fmt.Errorf("%w: %s", errInvalidInvType, inv.Type.String()) return errInvalidInvType
} }
} }
switch msg.Command { switch msg.Command {

View file

@ -8,12 +8,13 @@ package for more details on NEP-17 interface.
package gas package gas
import ( import (
"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/state"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17" "github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
) )
// Hash stores the hash of the native GAS contract. // Hash stores the hash of the native GAS contract.
var Hash = nativehashes.GasToken var Hash = state.CreateNativeContractHash(nativenames.Gas)
// NewReader creates a NEP-17 reader for the GAS contract. // NewReader creates a NEP-17 reader for the GAS contract.
func NewReader(invoker nep17.Invoker) *nep17.TokenReader { func NewReader(invoker nep17.Invoker) *nep17.TokenReader {

View file

@ -13,7 +13,7 @@ import (
"math/big" "math/big"
"github.com/google/uuid" "github.com/google/uuid"
"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/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/neorpc/result"
@ -75,7 +75,7 @@ type HashesIterator struct {
} }
// Hash stores the hash of the native ContractManagement contract. // Hash stores the hash of the native ContractManagement contract.
var Hash = nativehashes.ContractManagement var Hash = state.CreateNativeContractHash(nativenames.Management)
// Event is the event emitted on contract deployment/update/destroy. // Event is the event emitted on contract deployment/update/destroy.
// Even though these events are different they all have the same field inside. // Even though these events are different they all have the same field inside.

View file

@ -12,7 +12,7 @@ import (
"math/big" "math/big"
"github.com/google/uuid" "github.com/google/uuid"
"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/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -97,7 +97,7 @@ type ValidatorIterator struct {
} }
// Hash stores the hash of the native NEOToken contract. // Hash stores the hash of the native NEOToken contract.
var Hash = nativehashes.NeoToken var Hash = state.CreateNativeContractHash(nativenames.Neo)
// NewReader creates an instance of ContractReader to get data from the NEO // NewReader creates an instance of ContractReader to get data from the NEO
// contract. // contract.

View file

@ -13,7 +13,8 @@ import (
"math" "math"
"math/big" "math/big"
"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/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
@ -75,7 +76,7 @@ type OnNEP17PaymentData struct {
var _ = stackitem.Convertible(&OnNEP17PaymentData{}) var _ = stackitem.Convertible(&OnNEP17PaymentData{})
// Hash stores the hash of the native Notary contract. // Hash stores the hash of the native Notary contract.
var Hash = nativehashes.Notary var Hash = state.CreateNativeContractHash(nativenames.Notary)
// NewReader creates an instance of ContractReader to get data from the Notary // NewReader creates an instance of ContractReader to get data from the Notary
// contract. // contract.

View file

@ -9,7 +9,8 @@ package oracle
import ( import (
"math/big" "math/big"
"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/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
@ -31,7 +32,7 @@ type Actor interface {
} }
// Hash stores the hash of the native OracleContract contract. // Hash stores the hash of the native OracleContract contract.
var Hash = nativehashes.OracleContract var Hash = state.CreateNativeContractHash(nativenames.Oracle)
const priceSetter = "setPrice" const priceSetter = "setPrice"

View file

@ -7,7 +7,8 @@ various methods to perform PolicyContract state-changing calls.
package policy package policy
import ( import (
"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/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
@ -33,7 +34,7 @@ type Actor interface {
} }
// Hash stores the hash of the native PolicyContract contract. // Hash stores the hash of the native PolicyContract contract.
var Hash = nativehashes.PolicyContract var Hash = state.CreateNativeContractHash(nativenames.Policy)
const ( const (
execFeeSetter = "setExecFeeFactor" execFeeSetter = "setExecFeeFactor"

View file

@ -7,8 +7,9 @@ various methods to perform the only RoleManagement state-changing call.
package rolemgmt package rolemgmt
import ( import (
"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/noderoles" "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/neorpc/result"
@ -31,7 +32,7 @@ type Actor interface {
} }
// Hash stores the hash of the native RoleManagement contract. // Hash stores the hash of the native RoleManagement contract.
var Hash = nativehashes.RoleManagement var Hash = state.CreateNativeContractHash(nativenames.Designation)
const designateMethod = "designateAsRole" const designateMethod = "designateAsRole"

View file

@ -265,8 +265,8 @@ func (c *Client) getContractState(param any) (*state.Contract, error) {
} }
// GetNativeContracts queries information about native contracts. // GetNativeContracts queries information about native contracts.
func (c *Client) GetNativeContracts() ([]state.Contract, error) { func (c *Client) GetNativeContracts() ([]state.NativeContract, error) {
var resp []state.Contract var resp []state.NativeContract
if err := c.performRequest("getnativecontracts", nil, &resp); err != nil { if err := c.performRequest("getnativecontracts", nil, &resp); err != nil {
return resp, err return resp, err
} }

View file

@ -25,24 +25,12 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate" "github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
) )
// Exception is a type used for VM fault messages (aka exceptions). If any of
// unwrapper functions encounters a FAULT VM state it creates an instance of
// this type as an error using exception string. It can be used with [errors.As]
// to get the exact message from VM and compare with known contract-specific
// errors.
type Exception string
// ErrNoSessionID is returned from the SessionIterator when the server does not // ErrNoSessionID is returned from the SessionIterator when the server does not
// have sessions enabled and does not perform automatic iterator expansion. It // have sessions enabled and does not perform automatic iterator expansion. It
// means you have no way to get the data from returned iterators using this // means you have no way to get the data from returned iterators using this
// server, other than expanding it in the VM script. // server, other than expanding it in the VM script.
var ErrNoSessionID = errors.New("server returned iterator ID, but no session ID") var ErrNoSessionID = errors.New("server returned iterator ID, but no session ID")
// Error implements the error interface.
func (e Exception) Error() string {
return string(e)
}
// BigInt expects correct execution (HALT state) with a single stack item // BigInt expects correct execution (HALT state) with a single stack item
// returned. A big.Int is extracted from this item and returned. // returned. A big.Int is extracted from this item and returned.
func BigInt(r *result.Invoke, err error) (*big.Int, error) { func BigInt(r *result.Invoke, err error) (*big.Int, error) {
@ -411,10 +399,10 @@ func checkResOK(r *result.Invoke, err error) error {
return err return err
} }
if r.State != vmstate.Halt.String() { if r.State != vmstate.Halt.String() {
return fmt.Errorf("invocation failed: %w", Exception(r.FaultException)) return fmt.Errorf("invocation failed: %s", r.FaultException)
} }
if r.FaultException != "" { if r.FaultException != "" {
return fmt.Errorf("inconsistent result, HALTed with exception: %w", Exception(r.FaultException)) return fmt.Errorf("inconsistent result, HALTed with exception: %s", r.FaultException)
} }
return nil return nil
} }

View file

@ -95,20 +95,6 @@ func TestStdErrors(t *testing.T) {
for _, f := range funcs { for _, f := range funcs {
_, err := f(&result.Invoke{State: "FAULT", Stack: []stackitem.Item{stackitem.Make(42)}}, nil) _, err := f(&result.Invoke{State: "FAULT", Stack: []stackitem.Item{stackitem.Make(42)}}, nil)
require.Error(t, err) require.Error(t, err)
var fault Exception
require.True(t, errors.As(err, &fault))
require.Equal(t, "", string(fault))
}
})
t.Run("FAULT state with exception", func(t *testing.T) {
for _, f := range funcs {
_, err := f(&result.Invoke{State: "FAULT", FaultException: "something bad", Stack: []stackitem.Item{stackitem.Make(42)}}, nil)
require.Error(t, err)
var fault Exception
require.True(t, errors.As(err, &fault))
require.Equal(t, "something bad", string(fault))
} }
}) })
t.Run("nothing returned", func(t *testing.T) { t.Run("nothing returned", func(t *testing.T) {
@ -221,12 +207,10 @@ func TestItemJSONError(t *testing.T) {
var received result.Invoke var received result.Invoke
require.NoError(t, json.Unmarshal(data, &received)) require.NoError(t, json.Unmarshal(data, &received))
require.True(t, len(received.FaultException) != 0)
_, err = Item(&received, nil) _, err = Item(&received, nil)
var fault Exception require.True(t, len(received.FaultException) != 0)
require.True(t, errors.As(err, &fault)) require.Contains(t, err.Error(), received.FaultException)
require.Equal(t, received.FaultException, string(fault))
} }
func TestUTF8String(t *testing.T) { func TestUTF8String(t *testing.T) {

View file

@ -38,9 +38,8 @@ type (
Oracle struct { Oracle struct {
Config Config
// Native Oracle contract related information that may be updated on Oracle contract // This fields are readonly thus not protected by mutex.
// update. oracleHash util.Uint160
oracleInfoLock sync.RWMutex
oracleResponse []byte oracleResponse []byte
oracleScript []byte oracleScript []byte
verifyOffset int verifyOffset int
@ -278,11 +277,10 @@ drain:
// UpdateNativeContract updates native oracle contract info for tx verification. // UpdateNativeContract updates native oracle contract info for tx verification.
func (o *Oracle) UpdateNativeContract(script, resp []byte, h util.Uint160, verifyOffset int) { func (o *Oracle) UpdateNativeContract(script, resp []byte, h util.Uint160, verifyOffset int) {
o.oracleInfoLock.Lock()
defer o.oracleInfoLock.Unlock()
o.oracleScript = bytes.Clone(script) o.oracleScript = bytes.Clone(script)
o.oracleResponse = bytes.Clone(resp) o.oracleResponse = bytes.Clone(resp)
o.oracleHash = h
o.verifyOffset = verifyOffset o.verifyOffset = verifyOffset
} }

Some files were not shown because too many files have changed in this diff Show more