Compare commits
192 commits
skip-check
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
b66cea5ccc | ||
|
e5eb20bbae | ||
|
cf4d4a2611 | ||
|
7a7a5d0322 | ||
|
4d6333866d | ||
|
4a5e8f8592 | ||
|
b4fdf8c3c9 | ||
|
3c471f0b7e | ||
|
41109f442a | ||
|
5c408f7fe4 | ||
|
cd525a1df5 | ||
|
836183ecb6 | ||
|
3c1c650ddf | ||
|
45b8af359d | ||
|
4945145b09 | ||
|
f48e992a78 | ||
|
0b136c1c9c | ||
|
f4aeaa6387 | ||
|
0ae5e7ea83 | ||
|
228052360e | ||
|
5cbfe215a4 | ||
|
72161fe902 | ||
|
aceaabe9d6 | ||
|
9ba532ce9c | ||
|
2aa3c93acd | ||
|
aa5a0cb49b | ||
|
7868578571 | ||
|
6a5833759c | ||
|
6be757af3e | ||
|
67b6d5da31 | ||
|
b5bb605651 | ||
|
d91a0945df | ||
|
c90f6785b9 | ||
|
c30e7ec8d7 | ||
|
ce442a1942 | ||
|
e92606a7ae | ||
|
df1ed68d98 | ||
|
82a7c1bd9c | ||
|
c43cfae24c | ||
|
2d4993a837 | ||
|
647b8c7fb1 | ||
|
0b69901d1e | ||
|
502f024e7c | ||
|
b1bb12df48 | ||
|
31a99d44eb | ||
|
dc8b2f639a | ||
|
2ad4c86712 | ||
|
9a1075d332 | ||
|
58a086ea91 | ||
|
59c98c4d09 | ||
|
f4731eab91 | ||
|
13020ccd02 | ||
|
bce94dfa66 | ||
|
244ca6f438 | ||
|
a32217fac8 | ||
|
0435551eee | ||
|
0a3bf01a8f | ||
|
0aecddea10 | ||
|
02ecbeb519 | ||
|
e275495850 | ||
|
6e0926e59f | ||
|
988440949b | ||
|
701ea8d5f3 | ||
|
3d1e33a502 | ||
|
5053a073f9 | ||
|
71aa32406d | ||
|
3acb132e9a | ||
|
bd2f9c75e1 | ||
|
34eef47a18 | ||
|
7995229f6b | ||
|
b21db99747 | ||
|
bc158eed51 | ||
|
ac70f069ff | ||
|
b54fcbcdd9 | ||
|
8da7c0a671 | ||
|
956fd08adb | ||
|
1292a00ef9 | ||
|
7c8d2c3ec5 | ||
|
df2a56908b | ||
|
198af7f3ae | ||
|
874ed1ac2e | ||
|
4a8a43b983 | ||
|
6cf785ce54 | ||
|
9b8d579bce | ||
|
36e128516b | ||
|
4ca2686583 | ||
|
235f4398c6 | ||
|
ec6fc54bc6 | ||
|
2d3d52e3d0 | ||
|
82993dab2b | ||
|
5c75ee13d0 | ||
|
3a2e301267 | ||
|
d74dc368e0 | ||
|
73c742a466 | ||
|
d62fad1268 | ||
|
a13dc59bd9 | ||
|
678c1982f9 | ||
|
c84adf856a | ||
|
7345dbcab4 | ||
|
fbe514ca91 | ||
|
83fdcc8568 | ||
|
4b9024fa45 | ||
|
9b688a9ee9 | ||
|
1786136a23 | ||
|
d3993ad54c | ||
|
db37101e34 | ||
|
567f9f9c6e | ||
|
fb4a4f074f | ||
|
97a19df6f0 | ||
|
c5dbecb754 | ||
|
fc79d38ad2 | ||
|
ae3515e819 | ||
|
8913542f93 | ||
|
69bcd4b7d9 | ||
|
51537dfd29 | ||
|
ee1ee56f97 | ||
|
8c1d061446 | ||
|
a28e5b24b2 | ||
|
7aa5983543 | ||
|
fcbfc3b807 | ||
|
cf49e8c4c8 | ||
|
78cefca5c9 | ||
|
f2bb4d455b | ||
|
f553f77d20 | ||
|
700a550973 | ||
|
f84f072a29 | ||
|
927dbb6dc4 | ||
|
e5c919f701 | ||
|
22af33a14e | ||
|
ef3ec190d0 | ||
|
b1a986fba8 | ||
|
f6901806a8 | ||
|
686c77aeea | ||
|
89ef26164c | ||
|
4c288720cd | ||
|
f8c2d269fe | ||
|
698bdc7eea | ||
|
0280ceefe6 | ||
|
b6a9c64c55 | ||
|
be1b97d04e | ||
|
29deba45ca | ||
|
c81ed22698 | ||
|
c5ba53986f | ||
|
fff25bd85c | ||
|
182762af5a | ||
|
e7a0ded65e | ||
|
7202518fcf | ||
|
e0e7fdf810 | ||
|
f95004ad83 | ||
|
309016561d | ||
|
65dbd537ec | ||
|
b947d09552 | ||
|
5c995e71b5 | ||
|
5b30d15f8e | ||
|
57d82c1281 | ||
|
e341e64684 | ||
|
cd215fe096 | ||
|
d7ab7634ef | ||
|
00ac38b545 | ||
|
56e6119f78 | ||
|
d3c8916827 | ||
|
86f16bb931 | ||
|
e27a822d4b | ||
|
687a724d2c | ||
|
8d0d5cb7cd | ||
|
627a0abb57 | ||
|
beee2605a3 | ||
|
708b439f4a | ||
|
3e6dfff503 | ||
|
f8ca51db93 | ||
|
85a2a9a989 | ||
|
37d7a3a2d5 | ||
|
c090628ea5 | ||
|
6d1a22dcb3 | ||
|
1840c057bd | ||
|
fa1c07e7e6 | ||
|
d5a5e4c125 | ||
|
f8ebed2da4 | ||
|
72484a33eb | ||
|
e0328cc1f8 | ||
|
900ef462df | ||
|
d80e14dcbb | ||
|
f409fc36e2 | ||
|
b028c772f2 | ||
|
308475f746 | ||
|
31548dc28f | ||
|
7c2575568d | ||
|
270515de6a | ||
|
a81dc5c795 | ||
|
da4e80e7a0 | ||
|
1a3a494459 | ||
|
a6f52a7180 |
199 changed files with 4934 additions and 1074 deletions
47
.github/workflows/tests.yml
vendored
47
.github/workflows/tests.yml
vendored
|
@ -8,7 +8,7 @@ on:
|
|||
- master
|
||||
types: [opened, synchronize]
|
||||
paths-ignore:
|
||||
- 'scripts/**'
|
||||
- 'scripts/*.sh'
|
||||
- '**/*.md'
|
||||
workflow_dispatch:
|
||||
|
||||
|
@ -26,6 +26,7 @@ jobs:
|
|||
uses: golangci/golangci-lint-action@v4
|
||||
with:
|
||||
version: latest
|
||||
skip-pkg-cache: true # golangci-lint can't work with this cache enabled, ref. https://github.com/golangci/golangci-lint-action/issues/135.
|
||||
|
||||
gomodcheck:
|
||||
name: Check internal dependencies
|
||||
|
@ -38,6 +39,40 @@ jobs:
|
|||
- name: Check dependencies
|
||||
run: |
|
||||
./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:
|
||||
name: Check code generated with 'go generate' is up-to-date
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Install stringer
|
||||
run: go install golang.org/x/tools/cmd/stringer@latest
|
||||
|
||||
- name: Run go generate
|
||||
run: go generate ./...
|
||||
|
||||
- name: Check that autogenerated code is up-to-date
|
||||
run: |
|
||||
if [[ $(git diff --name-only | grep '' -c) != 0 ]]; then
|
||||
echo "Fresh version of autogenerated code should be committed for the following files:";
|
||||
git diff --name-only;
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
codeql:
|
||||
name: CodeQL
|
||||
|
@ -57,7 +92,7 @@ jobs:
|
|||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
|
@ -68,7 +103,7 @@ jobs:
|
|||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
@ -82,7 +117,7 @@ jobs:
|
|||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
test_cover:
|
||||
name: Coverage
|
||||
|
@ -107,10 +142,12 @@ jobs:
|
|||
run: go test -timeout 15m -v ./... -coverprofile=./coverage.txt -covermode=atomic -coverpkg=./pkg...,./cli/...
|
||||
|
||||
- name: Upload coverage results to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
fail_ci_if_error: true # if something is wrong on uploading codecov results, then this job will fail
|
||||
files: ./coverage.txt
|
||||
slug: nspcc-dev/neo-go
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
|
||||
tests:
|
||||
|
|
115
CHANGELOG.md
115
CHANGELOG.md
|
@ -2,6 +2,119 @@
|
|||
|
||||
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)
|
||||
|
||||
This is another v3.6.2-compatible release that fixes mainnet state difference at
|
||||
|
@ -2496,7 +2609,7 @@ Behavior changes:
|
|||
* contracts no longer have single entry point, rather they export a set of
|
||||
methods with specific offsets. Go smart contract compiler has been changed
|
||||
accordingly to add all exported (as in Go) methods to the manifest
|
||||
(but with the first letter being lowercased to match NEP-5 expections,
|
||||
(but with the first letter being lowercased to match NEP-5 expectations,
|
||||
#1228). Please also refer to examples changes to better see how it affects
|
||||
contracts, manifests and configuration files (#1296)
|
||||
* native contracts are now called via Neo.Native.Call syscall (#1191)
|
||||
|
|
20
ROADMAP.md
20
ROADMAP.md
|
@ -7,10 +7,11 @@ functionality.
|
|||
## Versions 0.7X.Y (as needed)
|
||||
* Neo 2.0 support (bug fixes, minor functionality additions)
|
||||
|
||||
## Version 0.106.0 (~February 2023)
|
||||
* extended data types for iterators to be used by RPC wrapper generator
|
||||
## Version 0.107.0 (~Jun-Jul 2024)
|
||||
* protocol updates
|
||||
* test fixes
|
||||
* bug fixes
|
||||
* node resynchronisation from local DB
|
||||
* CLI library upgrade
|
||||
|
||||
## Version 1.0 (2024, TBD)
|
||||
* stable version
|
||||
|
@ -30,15 +31,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
|
||||
formats.
|
||||
|
||||
Removal of Peer unmarshalling with string based ports is scheduled for ~September 2023
|
||||
(~0.105.0 release).
|
||||
Removal of Peer unmarshalling with string based ports is scheduled for Jun-Jul 2024
|
||||
(~0.107.0 release).
|
||||
|
||||
## `NEOBalance` from stack item
|
||||
|
||||
We check struct items count before convert LastGasPerVote to let RPC client be compatible with
|
||||
old versions.
|
||||
|
||||
Removal of this compatiblility code is scheduled for Sep-Oct 2023.
|
||||
Removal of this compatiblility code is scheduled for Jun-Jul 2024.
|
||||
|
||||
## `serv_node_version` Prometheus gauge metric
|
||||
|
||||
|
@ -47,7 +48,7 @@ metrics with proper version formatting. `neogo_version` contains NeoGo version
|
|||
hidden under `version` label and `server_id` contains network server ID hidden
|
||||
under `server_id` label.
|
||||
|
||||
Removal of `serv_node_version` is scheduled for Sep-Oct 2023 (~0.105.0 release).
|
||||
Removal of `serv_node_version` is scheduled for Jun-Jul 2024 (~0.107.0 release).
|
||||
|
||||
## RPC error codes returned by old versions and C#-nodes
|
||||
|
||||
|
@ -55,7 +56,8 @@ NeoGo retains certain deprecated error codes: `neorpc.ErrCompatGeneric`,
|
|||
`neorpc.ErrCompatNoOpenedWallet`. They returned by nodes not compliant with the
|
||||
neo-project/proposals#156 (NeoGo pre-0.102.0 and all known C# versions).
|
||||
|
||||
Removal of the deprecated RPC error codes is planned once all nodes adopt the new error standard.
|
||||
Removal of the deprecated RPC error codes is planned for Jun-Jul 2024 (~0.107.0
|
||||
release).
|
||||
|
||||
## Block based web-socket waiter transaction awaiting
|
||||
|
||||
|
@ -66,4 +68,4 @@ event-based waiter fallbacks to the old way of block monitoring with
|
|||
`block_added` notifications subscription.
|
||||
|
||||
Removal of stale RPC server compatibility code from `waiter.EventWaiter` is
|
||||
scheduled for May-June 2024 (~0.107.0 release).
|
||||
scheduled for Jun-Jul 2024 (~0.107.0 release).
|
|
@ -1,7 +1,6 @@
|
|||
package cmdargs
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -45,7 +44,7 @@ func TestParseCosigner(t *testing.T) {
|
|||
Scopes: transaction.CalledByEntry | transaction.CustomContracts,
|
||||
AllowedContracts: []util.Uint160{c1, c2},
|
||||
},
|
||||
acc.StringLE() + ":CustomGroups:" + hex.EncodeToString(priv.PublicKey().Bytes()): {
|
||||
acc.StringLE() + ":CustomGroups:" + priv.PublicKey().StringCompressed(): {
|
||||
Account: acc,
|
||||
Scopes: transaction.CustomGroups,
|
||||
AllowedGroups: keys.PublicKeys{priv.PublicKey()},
|
||||
|
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/urfave/cli"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"golang.org/x/term"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
|
@ -219,6 +220,7 @@ var (
|
|||
// If logPath is configured -- function creates a dir and a file for logging.
|
||||
// If logPath is configured on Windows -- function returns closer to be
|
||||
// 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) {
|
||||
var (
|
||||
level = zapcore.InfoLevel
|
||||
|
@ -239,7 +241,11 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
|
|||
cc.DisableStacktrace = true
|
||||
cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
|
||||
cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
|
||||
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
if term.IsTerminal(int(os.Stdout.Fd())) {
|
||||
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
} else {
|
||||
cc.EncoderConfig.EncodeTime = func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {}
|
||||
}
|
||||
cc.Encoding = "console"
|
||||
cc.Level = zap.NewAtomicLevelAt(level)
|
||||
cc.Sampling = nil
|
||||
|
|
|
@ -3,7 +3,6 @@ package query
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
@ -204,7 +203,7 @@ func queryCandidates(ctx *cli.Context) error {
|
|||
var res []byte
|
||||
res = fmt.Appendf(res, "Key\tVotes\tCommittee\tConsensus\n")
|
||||
for _, val := range vals {
|
||||
res = fmt.Appendf(res, "%s\t%d\t%t\t%t\n", hex.EncodeToString(val.PublicKey.Bytes()), val.Votes, comm.Contains(&val.PublicKey), val.Active)
|
||||
res = fmt.Appendf(res, "%s\t%d\t%t\t%t\n", val.PublicKey.StringCompressed(), val.Votes, comm.Contains(&val.PublicKey), val.Active)
|
||||
}
|
||||
tw := tabwriter.NewWriter(ctx.App.Writer, 0, 2, 2, ' ', 0)
|
||||
_, err = tw.Write(res)
|
||||
|
@ -235,7 +234,7 @@ func queryCommittee(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
for _, k := range comm {
|
||||
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(k.Bytes()))
|
||||
fmt.Fprintln(ctx.App.Writer, k.StringCompressed())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -306,7 +305,7 @@ func queryVoter(ctx *cli.Context) error {
|
|||
}
|
||||
voted := "null"
|
||||
if st.VoteTo != nil {
|
||||
voted = fmt.Sprintf("%s (%s)", hex.EncodeToString(st.VoteTo.Bytes()), address.Uint160ToString(st.VoteTo.GetScriptHash()))
|
||||
voted = fmt.Sprintf("%s (%s)", st.VoteTo.StringCompressed(), address.Uint160ToString(st.VoteTo.GetScriptHash()))
|
||||
}
|
||||
fmt.Fprintf(ctx.App.Writer, "\tVoted: %s\n", voted)
|
||||
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec)))
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"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/vmstate"
|
||||
|
@ -145,18 +146,7 @@ func Blocks() []*alias.Block {
|
|||
cmd = append(cmd, "--in", ctrPath, "--bindings", bindingsPath)
|
||||
|
||||
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
|
||||
goMod := filepath.Join(ctrPath, "go.mod")
|
||||
data, err := os.ReadFile(goMod)
|
||||
require.NoError(t, err)
|
||||
|
||||
i := bytes.IndexByte(data, '\n')
|
||||
data = append([]byte("module myimport.com/testcontract"), data[i:]...)
|
||||
|
||||
wd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
data = append(data, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "...)
|
||||
data = append(data, filepath.Join(wd, "../../pkg/interop")...)
|
||||
require.NoError(t, os.WriteFile(goMod, data, os.ModePerm))
|
||||
require.NoError(t, updateGoMod(ctrPath, "myimport.com/testcontract", "../../pkg/interop"))
|
||||
|
||||
cmd = append(cmd, "--config", cfgPath,
|
||||
"--out", filepath.Join(tmpDir, "out.nef"),
|
||||
|
@ -176,7 +166,7 @@ func Blocks() []*alias.Block {
|
|||
|
||||
bs, err := os.ReadFile(outPath)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]; DO NOT EDIT.
|
||||
require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||
|
||||
// Package testcontract contains wrappers for testcontract contract.
|
||||
package testcontract
|
||||
|
@ -213,6 +203,84 @@ func ToMap(a []testcontract.MyPair) map[int]string {
|
|||
`, string(bs))
|
||||
}
|
||||
|
||||
// updateGoMod updates the go.mod file located in the specified directory.
|
||||
// It sets the module name and replaces the neo-go interop package path with
|
||||
// the provided one to avoid getting an actual module version.
|
||||
func updateGoMod(dir, moduleName, neoGoPath string) error {
|
||||
goModPath := filepath.Join(dir, "go.mod")
|
||||
data, err := os.ReadFile(goModPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read go.mod: %w", err)
|
||||
}
|
||||
|
||||
i := bytes.IndexByte(data, '\n')
|
||||
if i == -1 {
|
||||
return fmt.Errorf("unexpected go.mod format")
|
||||
}
|
||||
|
||||
updatedData := append([]byte("module "+moduleName), data[i:]...)
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get working directory: %w", err)
|
||||
}
|
||||
|
||||
replacementPath := filepath.Join(wd, neoGoPath)
|
||||
updatedData = append(updatedData, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "+replacementPath+" \n"...)
|
||||
|
||||
if err := os.WriteFile(goModPath, updatedData, os.ModePerm); err != nil {
|
||||
return fmt.Errorf("failed to write updated go.mod: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestDynamicWrapper(t *testing.T) {
|
||||
// For proper contract init. The actual version as it will be replaced.
|
||||
smartcontract.ModVersion = "v0.0.0"
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
e := testcli.NewExecutor(t, true)
|
||||
|
||||
ctrPath := "../smartcontract/testdata"
|
||||
|
||||
verifyHash := testcli.DeployContract(t, e, filepath.Join(ctrPath, "verify.go"), filepath.Join(ctrPath, "verify.yml"), testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
|
||||
|
||||
helperContract := `package testcontract
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
verify "myimport.com/testcontract/bindings"
|
||||
)
|
||||
|
||||
func CallVerifyContract(h interop.Hash160) bool{
|
||||
contractInstance := verify.NewContract(h)
|
||||
return contractInstance.Verify()
|
||||
}`
|
||||
|
||||
helperDir := filepath.Join(tmpDir, "helper")
|
||||
e.Run(t, "neo-go", "contract", "init", "--name", helperDir)
|
||||
|
||||
require.NoError(t, updateGoMod(helperDir, "myimport.com/testcontract", "../../pkg/interop"))
|
||||
require.NoError(t, os.WriteFile(filepath.Join(helperDir, "main.go"), []byte(helperContract), os.ModePerm))
|
||||
require.NoError(t, os.Mkdir(filepath.Join(helperDir, "bindings"), os.ModePerm))
|
||||
|
||||
e.Run(t, "neo-go", "contract", "generate-wrapper",
|
||||
"--config", filepath.Join(ctrPath, "verify.bindings.yml"), "--manifest", filepath.Join(ctrPath, "verify.manifest.json"),
|
||||
"--out", filepath.Join(helperDir, "bindings", "testdata.go"))
|
||||
e.Run(t, "neo-go", "contract", "compile", "--in", filepath.Join(helperDir, "main.go"), "--config", filepath.Join(helperDir, "neo-go.yml"))
|
||||
helperHash := testcli.DeployContract(t, e, filepath.Join(helperDir, "main.go"), filepath.Join(helperDir, "neo-go.yml"), testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
|
||||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "contract", "invokefunction",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--force", "--await", helperHash.StringLE(), "callVerifyContract", verifyHash.StringLE())
|
||||
|
||||
tx, _ := e.CheckTxPersisted(t, "Sent invocation transaction ")
|
||||
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, aer[0].Stack[0].Value().(bool), true)
|
||||
}
|
||||
|
||||
func TestContractInitAndCompile(t *testing.T) {
|
||||
// For proper contract init. The actual version as it will be replaced.
|
||||
smartcontract.ModVersion = "v0.0.0"
|
||||
|
@ -265,15 +333,7 @@ func TestContractInitAndCompile(t *testing.T) {
|
|||
})
|
||||
|
||||
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
|
||||
goMod := filepath.Join(ctrPath, "go.mod")
|
||||
data, err := os.ReadFile(goMod)
|
||||
require.NoError(t, err)
|
||||
|
||||
wd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
data = append(data, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "...)
|
||||
data = append(data, filepath.Join(wd, "../../pkg/interop")...)
|
||||
require.NoError(t, os.WriteFile(goMod, data, os.ModePerm))
|
||||
require.NoError(t, updateGoMod(ctrPath, "myimport.com/testcontract", "../../pkg/interop"))
|
||||
|
||||
cmd = append(cmd, "--config", cfgPath)
|
||||
|
||||
|
|
|
@ -30,17 +30,22 @@ var generatorFlags = []cli.Flag{
|
|||
},
|
||||
cli.StringFlag{
|
||||
Name: "hash",
|
||||
Usage: "Smart-contract hash",
|
||||
Usage: "Smart-contract hash. If not passed, the wrapper will be designed for dynamic hash usage",
|
||||
},
|
||||
}
|
||||
|
||||
var generateWrapperCmd = cli.Command{
|
||||
Name: "generate-wrapper",
|
||||
Usage: "generate wrapper to use in other contracts",
|
||||
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]",
|
||||
Description: ``,
|
||||
Action: contractGenerateWrapper,
|
||||
Flags: generatorFlags,
|
||||
Name: "generate-wrapper",
|
||||
Usage: "generate wrapper to use in other contracts",
|
||||
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
|
||||
Description: `Generates a Go wrapper to use it in other smart contracts. If the
|
||||
--hash flag is provided, CALLT instruction is used for the target contract
|
||||
invocation as an optimization of the wrapper contract code. If omitted, the
|
||||
generated wrapper will be designed for dynamic hash usage, allowing
|
||||
the hash to be specified at runtime.
|
||||
`,
|
||||
Action: contractGenerateWrapper,
|
||||
Flags: generatorFlags,
|
||||
}
|
||||
|
||||
var generateRPCWrapperCmd = cli.Command{
|
||||
|
@ -52,15 +57,15 @@ var generateRPCWrapperCmd = cli.Command{
|
|||
}
|
||||
|
||||
func contractGenerateWrapper(ctx *cli.Context) error {
|
||||
return contractGenerateSomething(ctx, binding.Generate, false)
|
||||
return contractGenerateSomething(ctx, binding.Generate)
|
||||
}
|
||||
|
||||
func contractGenerateRPCWrapper(ctx *cli.Context) error {
|
||||
return contractGenerateSomething(ctx, rpcbinding.Generate, true)
|
||||
return contractGenerateSomething(ctx, rpcbinding.Generate)
|
||||
}
|
||||
|
||||
// contractGenerateSomething reads generator parameters and calls the given callback.
|
||||
func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error, allowEmptyHash bool) error {
|
||||
func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error) error {
|
||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -73,8 +78,6 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error,
|
|||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1)
|
||||
}
|
||||
} else if !allowEmptyHash {
|
||||
return cli.NewExitError("contract hash must be provided via --hash flag", 1)
|
||||
}
|
||||
m, _, err := readManifest(ctx.String("manifest"), h)
|
||||
if err != nil {
|
||||
|
|
|
@ -151,7 +151,7 @@ callflags:
|
|||
"--hash", h.StringLE(),
|
||||
}))
|
||||
|
||||
const expected = `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]; DO NOT EDIT.
|
||||
const expected = `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||
|
||||
// Package wrapper contains wrappers for MyContract contract.
|
||||
package wrapper
|
||||
|
@ -233,6 +233,99 @@ func MyFunc(in map[int]mycontract.Input) []mycontract.Output {
|
|||
data, err := os.ReadFile(outFile)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected, string(data))
|
||||
|
||||
require.NoError(t, app.Run([]string{"", "generate-wrapper",
|
||||
"--manifest", manifestFile,
|
||||
"--config", cfgPath,
|
||||
"--out", outFile,
|
||||
}))
|
||||
expectedWithDynamicHash := `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||
|
||||
// Package wrapper contains wrappers for MyContract contract.
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"github.com/heyitsme/mycontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||
)
|
||||
|
||||
// Contract represents the MyContract smart contract.
|
||||
type Contract struct {
|
||||
Hash interop.Hash160
|
||||
}
|
||||
|
||||
// NewContract returns a new Contract instance with the specified hash.
|
||||
func NewContract(hash interop.Hash160) Contract {
|
||||
return Contract{Hash: hash}
|
||||
}
|
||||
|
||||
// Sum invokes ` + "`sum`" + ` method of contract.
|
||||
func (c Contract) Sum(first int, second int) int {
|
||||
return contract.Call(c.Hash, "sum", contract.All, first, second).(int)
|
||||
}
|
||||
|
||||
// Sum2 invokes ` + "`sum`" + ` method of contract.
|
||||
func (c Contract) Sum2(first int, second int, third int) int {
|
||||
return contract.Call(c.Hash, "sum", contract.All, first, second, third).(int)
|
||||
}
|
||||
|
||||
// Sum3 invokes ` + "`sum3`" + ` method of contract.
|
||||
func (c Contract) Sum3() int {
|
||||
return contract.Call(c.Hash, "sum3", contract.ReadOnly).(int)
|
||||
}
|
||||
|
||||
// Zum invokes ` + "`zum`" + ` method of contract.
|
||||
func (c Contract) Zum(typev int, typev_ int, funcv int) int {
|
||||
return contract.Call(c.Hash, "zum", contract.All, typev, typev_, funcv).(int)
|
||||
}
|
||||
|
||||
// JustExecute invokes ` + "`justExecute`" + ` method of contract.
|
||||
func (c Contract) JustExecute(arr []any) {
|
||||
contract.Call(c.Hash, "justExecute", contract.All, arr)
|
||||
}
|
||||
|
||||
// GetPublicKey invokes ` + "`getPublicKey`" + ` method of contract.
|
||||
func (c Contract) GetPublicKey() interop.PublicKey {
|
||||
return contract.Call(c.Hash, "getPublicKey", contract.All).(interop.PublicKey)
|
||||
}
|
||||
|
||||
// OtherTypes invokes ` + "`otherTypes`" + ` method of contract.
|
||||
func (c Contract) OtherTypes(ctr interop.Hash160, tx interop.Hash256, sig interop.Signature, data any) bool {
|
||||
return contract.Call(c.Hash, "otherTypes", contract.All, ctr, tx, sig, data).(bool)
|
||||
}
|
||||
|
||||
// SearchStorage invokes ` + "`searchStorage`" + ` method of contract.
|
||||
func (c Contract) SearchStorage(ctx storage.Context) iterator.Iterator {
|
||||
return contract.Call(c.Hash, "searchStorage", contract.All, ctx).(iterator.Iterator)
|
||||
}
|
||||
|
||||
// GetFromMap invokes ` + "`getFromMap`" + ` method of contract.
|
||||
func (c Contract) GetFromMap(intMap map[string]int, indices []string) []int {
|
||||
return contract.Call(c.Hash, "getFromMap", contract.All, intMap, indices).([]int)
|
||||
}
|
||||
|
||||
// DoSomething invokes ` + "`doSomething`" + ` method of contract.
|
||||
func (c Contract) DoSomething(bytes []byte, str string) any {
|
||||
return contract.Call(c.Hash, "doSomething", contract.ReadStates, bytes, str).(any)
|
||||
}
|
||||
|
||||
// GetBlockWrapper invokes ` + "`getBlockWrapper`" + ` method of contract.
|
||||
func (c Contract) GetBlockWrapper() ledger.Block {
|
||||
return contract.Call(c.Hash, "getBlockWrapper", contract.All).(ledger.Block)
|
||||
}
|
||||
|
||||
// MyFunc invokes ` + "`myFunc`" + ` method of contract.
|
||||
func (c Contract) MyFunc(in map[int]mycontract.Input) []mycontract.Output {
|
||||
return contract.Call(c.Hash, "myFunc", contract.All, in).([]mycontract.Output)
|
||||
}
|
||||
`
|
||||
data, err = os.ReadFile(outFile)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedWithDynamicHash, string(data))
|
||||
}
|
||||
|
||||
func TestGenerateValidPackageName(t *testing.T) {
|
||||
|
@ -267,7 +360,7 @@ func TestGenerateValidPackageName(t *testing.T) {
|
|||
|
||||
data, err := os.ReadFile(outFile)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]; DO NOT EDIT.
|
||||
require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||
|
||||
// Package myspacecontract contains wrappers for My space contract contract.
|
||||
package myspacecontract
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package smartcontract
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
|
@ -28,10 +27,9 @@ func (p permission) MarshalYAML() (any, error) {
|
|||
&yaml.Node{Kind: yaml.ScalarNode, Value: permHashKey},
|
||||
&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(util.Uint160).StringLE()})
|
||||
case manifest.PermissionGroup:
|
||||
bs := p.Contract.Value.(*keys.PublicKey).Bytes()
|
||||
m.Content = append(m.Content,
|
||||
&yaml.Node{Kind: yaml.ScalarNode, Value: permGroupKey},
|
||||
&yaml.Node{Kind: yaml.ScalarNode, Value: hex.EncodeToString(bs)})
|
||||
&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(*keys.PublicKey).StringCompressed()})
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid permission type: %d", p.Contract.Type)
|
||||
}
|
||||
|
|
|
@ -137,7 +137,8 @@ func NewCommands() []cli.Command {
|
|||
then the output filenames for these flags will be guessed using the contract
|
||||
name or path provided via --in option by trimming/adding corresponding suffixes
|
||||
to the common part of the path. In the latter case the configuration filepath
|
||||
will be guessed from the --in option using the same rule."`,
|
||||
will be guessed from the --in option using the same rule.
|
||||
`,
|
||||
Action: contractCompile,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package smartcontract
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"os"
|
||||
"testing"
|
||||
|
@ -109,7 +108,7 @@ func TestPermissionMarshal(t *testing.T) {
|
|||
p.Methods.Add("abc")
|
||||
p.Methods.Add("lamao")
|
||||
testPermissionMarshal(t, p,
|
||||
"group: "+hex.EncodeToString(priv.PublicKey().Bytes())+"\n"+
|
||||
"group: "+priv.PublicKey().StringCompressed()+"\n"+
|
||||
"methods:\n - abc\n - lamao\n")
|
||||
})
|
||||
}
|
||||
|
@ -118,7 +117,7 @@ func TestPermissionUnmarshalInvalid(t *testing.T) {
|
|||
priv, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
pub := hex.EncodeToString(priv.PublicKey().Bytes())
|
||||
pub := priv.PublicKey().StringCompressed()
|
||||
u160 := random.Uint160().StringLE()
|
||||
testCases := []string{
|
||||
"hash: []\nmethods: '*'\n", // invalid hash type
|
||||
|
|
297
cli/smartcontract/testdata/verify.bindings.yml
vendored
Executable file
297
cli/smartcontract/testdata/verify.bindings.yml
vendored
Executable file
|
@ -0,0 +1,297 @@
|
|||
package: testdata
|
||||
hash: "0x0000000000000000000000000000000000000000"
|
||||
overrides:
|
||||
burnGas.gas: int
|
||||
call: any
|
||||
call.args: '[]any'
|
||||
call.f: any
|
||||
call.method: string
|
||||
call.scriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||
callWithToken: any
|
||||
callWithToken.args: '[]any'
|
||||
callWithToken.flags: int
|
||||
callWithToken.method: string
|
||||
callWithToken.scriptHash: string
|
||||
callWithTokenNoRet.args: '[]any'
|
||||
callWithTokenNoRet.flags: int
|
||||
callWithTokenNoRet.method: string
|
||||
callWithTokenNoRet.scriptHash: string
|
||||
checkWitness: bool
|
||||
checkWitness.hashOrKey: '[]byte'
|
||||
createMultisigAccount: '[]byte'
|
||||
createMultisigAccount.m: int
|
||||
createMultisigAccount.pubs: '[]github.com/nspcc-dev/neo-go/pkg/interop.PublicKey'
|
||||
createStandardAccount: '[]byte'
|
||||
createStandardAccount.pub: github.com/nspcc-dev/neo-go/pkg/interop.PublicKey
|
||||
currentHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
|
||||
currentIndex: int
|
||||
currentSigners: '[]github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.TransactionSigner'
|
||||
equals: bool
|
||||
equals.b: any
|
||||
gasLeft: int
|
||||
getAddressVersion: int
|
||||
getBlock: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Block'
|
||||
getBlock.indexOrHash: any
|
||||
getCallFlags: any
|
||||
getCallingScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||
getEntryScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||
getExecutingScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||
getInvocationCounter: int
|
||||
getNetwork: int
|
||||
getNotifications: '[][]any'
|
||||
getNotifications.h: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||
getRandom: int
|
||||
getScriptContainer: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
|
||||
getTime: int
|
||||
getTransaction: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
|
||||
getTransaction.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
|
||||
getTransactionFromBlock: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
|
||||
getTransactionFromBlock.indexOrHash: any
|
||||
getTransactionFromBlock.txIndex: int
|
||||
getTransactionHeight: int
|
||||
getTransactionHeight.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
|
||||
getTransactionSigners: '[]github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.TransactionSigner'
|
||||
getTransactionSigners.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
|
||||
getTransactionVMState: int
|
||||
getTransactionVMState.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
|
||||
getTrigger: int
|
||||
loadScript: any
|
||||
loadScript.args: '[]any'
|
||||
loadScript.f: any
|
||||
loadScript.script: '[]byte'
|
||||
log.message: string
|
||||
notify.args: '[]any'
|
||||
notify.name: string
|
||||
onNEP11Payment.amount: int
|
||||
onNEP11Payment.data: any
|
||||
onNEP11Payment.from: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||
onNEP11Payment.token: '[]byte'
|
||||
onNEP17Payment.amount: int
|
||||
onNEP17Payment.data: any
|
||||
onNEP17Payment.from: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||
opcode0NoReturn.op: string
|
||||
opcode1: any
|
||||
opcode1NoReturn.arg: any
|
||||
opcode1NoReturn.op: string
|
||||
opcode1.arg: any
|
||||
opcode1.op: string
|
||||
opcode2: any
|
||||
opcode2NoReturn.arg1: any
|
||||
opcode2NoReturn.arg2: any
|
||||
opcode2NoReturn.op: string
|
||||
opcode2.arg1: any
|
||||
opcode2.arg2: any
|
||||
opcode2.op: string
|
||||
opcode3: any
|
||||
opcode3.arg1: any
|
||||
opcode3.arg2: any
|
||||
opcode3.arg3: any
|
||||
opcode3.op: string
|
||||
platform: '[]byte'
|
||||
syscall0: any
|
||||
syscall0NoReturn.name: string
|
||||
syscall0.name: string
|
||||
syscall1: any
|
||||
syscall1NoReturn.arg: any
|
||||
syscall1NoReturn.name: string
|
||||
syscall1.arg: any
|
||||
syscall1.name: string
|
||||
syscall2: any
|
||||
syscall2NoReturn.arg1: any
|
||||
syscall2NoReturn.arg2: any
|
||||
syscall2NoReturn.name: string
|
||||
syscall2.arg1: any
|
||||
syscall2.arg2: any
|
||||
syscall2.name: string
|
||||
syscall3: any
|
||||
syscall3NoReturn.arg1: any
|
||||
syscall3NoReturn.arg2: any
|
||||
syscall3NoReturn.arg3: any
|
||||
syscall3NoReturn.name: string
|
||||
syscall3.arg1: any
|
||||
syscall3.arg2: any
|
||||
syscall3.arg3: any
|
||||
syscall3.name: string
|
||||
syscall4: any
|
||||
syscall4NoReturn.arg1: any
|
||||
syscall4NoReturn.arg2: any
|
||||
syscall4NoReturn.arg3: any
|
||||
syscall4NoReturn.arg4: any
|
||||
syscall4NoReturn.name: string
|
||||
syscall4.arg1: any
|
||||
syscall4.arg2: any
|
||||
syscall4.arg3: any
|
||||
syscall4.arg4: any
|
||||
syscall4.name: string
|
||||
toBlockSR: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.BlockSR'
|
||||
verify: bool
|
||||
namedtypes:
|
||||
ledger.Block:
|
||||
base: Array
|
||||
name: ledger.Block
|
||||
fields:
|
||||
- field: Hash
|
||||
base: Hash256
|
||||
- field: Version
|
||||
base: Integer
|
||||
- field: PrevHash
|
||||
base: Hash256
|
||||
- field: MerkleRoot
|
||||
base: Hash256
|
||||
- field: Timestamp
|
||||
base: Integer
|
||||
- field: Nonce
|
||||
base: Integer
|
||||
- field: Index
|
||||
base: Integer
|
||||
- field: NextConsensus
|
||||
base: Hash160
|
||||
- field: TransactionsLength
|
||||
base: Integer
|
||||
ledger.BlockSR:
|
||||
base: Array
|
||||
name: ledger.BlockSR
|
||||
fields:
|
||||
- field: Hash
|
||||
base: Hash256
|
||||
- field: Version
|
||||
base: Integer
|
||||
- field: PrevHash
|
||||
base: Hash256
|
||||
- field: MerkleRoot
|
||||
base: Hash256
|
||||
- field: Timestamp
|
||||
base: Integer
|
||||
- field: Nonce
|
||||
base: Integer
|
||||
- field: Index
|
||||
base: Integer
|
||||
- field: NextConsensus
|
||||
base: Hash160
|
||||
- field: TransactionsLength
|
||||
base: Integer
|
||||
- field: PrevStateRoot
|
||||
base: Hash256
|
||||
ledger.Transaction:
|
||||
base: Array
|
||||
name: ledger.Transaction
|
||||
fields:
|
||||
- field: Hash
|
||||
base: Hash256
|
||||
- field: Version
|
||||
base: Integer
|
||||
- field: Nonce
|
||||
base: Integer
|
||||
- field: Sender
|
||||
base: Hash160
|
||||
- field: SysFee
|
||||
base: Integer
|
||||
- field: NetFee
|
||||
base: Integer
|
||||
- field: ValidUntilBlock
|
||||
base: Integer
|
||||
- field: Script
|
||||
base: ByteArray
|
||||
ledger.TransactionSigner:
|
||||
base: Array
|
||||
name: ledger.TransactionSigner
|
||||
fields:
|
||||
- field: Account
|
||||
base: Hash160
|
||||
- field: Scopes
|
||||
base: Integer
|
||||
- field: AllowedContracts
|
||||
base: Array
|
||||
value:
|
||||
base: Hash160
|
||||
- field: AllowedGroups
|
||||
base: Array
|
||||
value:
|
||||
base: PublicKey
|
||||
- field: Rules
|
||||
base: Array
|
||||
value:
|
||||
base: Array
|
||||
name: ledger.WitnessRule
|
||||
ledger.WitnessCondition:
|
||||
base: Array
|
||||
name: ledger.WitnessCondition
|
||||
fields:
|
||||
- field: Type
|
||||
base: Integer
|
||||
- field: Value
|
||||
base: Any
|
||||
ledger.WitnessRule:
|
||||
base: Array
|
||||
name: ledger.WitnessRule
|
||||
fields:
|
||||
- field: Action
|
||||
base: Integer
|
||||
- field: Condition
|
||||
base: Array
|
||||
name: ledger.WitnessCondition
|
||||
types:
|
||||
call.args:
|
||||
base: Array
|
||||
value:
|
||||
base: Any
|
||||
call.f:
|
||||
base: InteropInterface
|
||||
interface: iterator
|
||||
callWithToken.args:
|
||||
base: Array
|
||||
value:
|
||||
base: Any
|
||||
callWithTokenNoRet.args:
|
||||
base: Array
|
||||
value:
|
||||
base: Any
|
||||
createMultisigAccount.pubs:
|
||||
base: Array
|
||||
value:
|
||||
base: PublicKey
|
||||
currentSigners:
|
||||
base: Array
|
||||
value:
|
||||
base: Array
|
||||
name: ledger.TransactionSigner
|
||||
getBlock:
|
||||
base: Array
|
||||
name: ledger.Block
|
||||
getCallFlags:
|
||||
base: InteropInterface
|
||||
interface: iterator
|
||||
getNotifications:
|
||||
base: Array
|
||||
value:
|
||||
base: Array
|
||||
value:
|
||||
base: Any
|
||||
getScriptContainer:
|
||||
base: Array
|
||||
name: ledger.Transaction
|
||||
getTransaction:
|
||||
base: Array
|
||||
name: ledger.Transaction
|
||||
getTransactionFromBlock:
|
||||
base: Array
|
||||
name: ledger.Transaction
|
||||
getTransactionSigners:
|
||||
base: Array
|
||||
value:
|
||||
base: Array
|
||||
name: ledger.TransactionSigner
|
||||
loadScript.args:
|
||||
base: Array
|
||||
value:
|
||||
base: Any
|
||||
loadScript.f:
|
||||
base: InteropInterface
|
||||
interface: iterator
|
||||
notify.args:
|
||||
base: Array
|
||||
value:
|
||||
base: Any
|
||||
toBlockSR:
|
||||
base: Array
|
||||
name: ledger.BlockSR
|
1
cli/testdata/wallet1_solo.json
vendored
1
cli/testdata/wallet1_solo.json
vendored
|
@ -65,7 +65,6 @@
|
|||
"key": "6PYSATFztBa3CHjSR6sLAKungUEAbQUCVE16KzmaQQ38gLeYGZ9Knd5mGv",
|
||||
"label": "verify",
|
||||
"contract": {
|
||||
"script": "VwEAEUBXAANA",
|
||||
"parameters": [],
|
||||
"deployed": true
|
||||
},
|
||||
|
|
|
@ -75,7 +75,7 @@ func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *tr
|
|||
}
|
||||
waitTime := time.Since(promptTime)
|
||||
// Compensate for confirmation waiting.
|
||||
tx.ValidUntilBlock += uint32((waitTime.Milliseconds() / int64(ver.Protocol.MillisecondsPerBlock))) + 1
|
||||
tx.ValidUntilBlock += uint32(waitTime.Milliseconds()/int64(ver.Protocol.MillisecondsPerBlock)) + 2
|
||||
}
|
||||
var (
|
||||
resTx util.Uint256
|
||||
|
|
|
@ -52,7 +52,7 @@ func cancelTx(ctx *cli.Context) error {
|
|||
|
||||
mainTx, _ := c.GetRawTransactionVerbose(txHash)
|
||||
if mainTx != nil && !mainTx.Blockhash.Equals(util.Uint256{}) {
|
||||
return cli.NewExitError(fmt.Errorf("transaction %s is already accepted at block %s", txHash, mainTx.Blockhash.StringLE()), 1)
|
||||
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted at block %s", txHash, mainTx.Blockhash.StringLE()), 1)
|
||||
}
|
||||
|
||||
if mainTx != nil && !mainTx.HasSigner(acc.ScriptHash()) {
|
||||
|
@ -76,10 +76,7 @@ func cancelTx(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to send conflicting transaction: %w", err), 1)
|
||||
}
|
||||
var (
|
||||
acceptedH = resHash
|
||||
res *state.AppExecResult
|
||||
)
|
||||
var res *state.AppExecResult
|
||||
if ctx.Bool("await") {
|
||||
res, err = a.WaitAny(gctx, resVub, txHash, resHash)
|
||||
if err != nil {
|
||||
|
@ -93,12 +90,14 @@ func cancelTx(ctx *cli.Context) error {
|
|||
return cli.NewExitError(fmt.Errorf("failed to await target/ conflicting transaction %s/ %s: %w", txHash.StringLE(), resHash.StringLE(), err), 1)
|
||||
}
|
||||
if txHash.Equals(res.Container) {
|
||||
fmt.Fprintln(ctx.App.Writer, "Target transaction accepted")
|
||||
acceptedH = txHash
|
||||
} else {
|
||||
fmt.Fprintln(ctx.App.Writer, "Conflicting transaction accepted")
|
||||
tx, err := c.GetRawTransactionVerbose(txHash)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted", txHash), 1)
|
||||
}
|
||||
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted at block %s", txHash, tx.Blockhash.StringLE()), 1)
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, "Conflicting transaction accepted")
|
||||
}
|
||||
txctx.DumpTransactionInfo(ctx.App.Writer, acceptedH, res)
|
||||
txctx.DumpTransactionInfo(ctx.App.Writer, resHash, res)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -69,7 +69,8 @@ func NewCommands() []cli.Command {
|
|||
NetworkFee calculations are performed based on the calculatenetworkfee RPC request. If the --gas
|
||||
flag is included, the specified value is added to the resulting conflicting transaction network fee
|
||||
in both scenarios. When the --await flag is included, the command waits for one of the conflicting
|
||||
or target transactions to be included in a block.`,
|
||||
or target transactions to be included in a block.
|
||||
`,
|
||||
Action: cancelTx,
|
||||
Flags: txCancelFlags,
|
||||
},
|
||||
|
@ -83,7 +84,8 @@ func NewCommands() []cli.Command {
|
|||
the output. This command expects a ContractParametersContext JSON file for input, it can't handle
|
||||
binary (or hex- or base64-encoded) transactions. If --rpc-endpoint flag is specified the result
|
||||
of the given script after running it true the VM will be printed. Otherwise only transaction will
|
||||
be printed.`,
|
||||
be printed.
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "ops",
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
package util_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -167,13 +170,23 @@ func TestAwaitUtilCancelTx(t *testing.T) {
|
|||
_, ok := e.Chain.GetMemPool().TryGetValue(txHash)
|
||||
require.True(t, ok)
|
||||
|
||||
// Allow both cases: either target or conflicting tx acceptance.
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, append(args, txHash.StringLE())...)
|
||||
e.CheckNextLine(t, "Conflicting transaction accepted")
|
||||
resHash, _ := e.CheckAwaitableTxPersisted(t)
|
||||
|
||||
require.Eventually(t, func() bool {
|
||||
_, aerErr := e.Chain.GetAppExecResults(resHash.Hash(), trigger.Application)
|
||||
return aerErr == nil
|
||||
}, time.Second*2, time.Millisecond*50)
|
||||
err = e.RunUnchecked(t, append(args, txHash.StringLE())...)
|
||||
switch {
|
||||
case err == nil:
|
||||
response := e.GetNextLine(t)
|
||||
require.Equal(t, "Conflicting transaction accepted", response)
|
||||
resHash, _ := e.CheckAwaitableTxPersisted(t)
|
||||
require.NotEqual(t, resHash, txHash)
|
||||
case strings.Contains(err.Error(), fmt.Sprintf("target transaction %s is accepted", txHash)) ||
|
||||
strings.Contains(err.Error(), fmt.Sprintf("failed to send conflicting transaction: Invalid transaction attribute (-507) - invalid attribute: conflicting transaction %s is already on chain", txHash)):
|
||||
tx, _ := e.GetTransaction(t, txHash)
|
||||
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(aer))
|
||||
require.Equal(t, vmstate.Halt, aer[0].VMState)
|
||||
default:
|
||||
t.Fatal(fmt.Errorf("unexpected error: %w", err))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1105,7 +1105,7 @@ func handleRun(c *cli.Context) error {
|
|||
breaks := v.Context().BreakPoints() // We ensure that there's a context loaded.
|
||||
ic.ReuseVM(v)
|
||||
v.GasLimit = gasLimit
|
||||
v.LoadNEFMethod(&cs.NEF, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil)
|
||||
v.LoadNEFMethod(&cs.NEF, &cs.Manifest, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil)
|
||||
for _, bp := range breaks {
|
||||
v.AddBreakPoint(bp)
|
||||
}
|
||||
|
|
|
@ -134,6 +134,10 @@ func newTestVMClIWithState(t *testing.T) *executor {
|
|||
}
|
||||
bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, store)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Save config for future usage.
|
||||
protoCfg := bc.GetConfig()
|
||||
|
||||
go bc.Run()
|
||||
e := neotest.NewExecutor(t, bc, validators, committee)
|
||||
basicchain.InitSimple(t, "../../", e)
|
||||
|
@ -145,7 +149,9 @@ func newTestVMClIWithState(t *testing.T) *executor {
|
|||
require.NoError(t, err)
|
||||
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
|
||||
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions = opts
|
||||
cfg.ProtocolConfiguration.StateRootInHeader = true
|
||||
cfg.ProtocolConfiguration.StateRootInHeader = protoCfg.StateRootInHeader
|
||||
cfg.ProtocolConfiguration.P2PStateExchangeExtensions = protoCfg.P2PStateExchangeExtensions
|
||||
cfg.ProtocolConfiguration.Hardforks = protoCfg.Hardforks
|
||||
return newTestVMCLIWithLogoAndCustomConfig(t, false, &cfg)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package wallet_test
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
@ -18,7 +17,7 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
|
||||
validatorAddress := testcli.ValidatorPriv.Address()
|
||||
validatorPublic := testcli.ValidatorPriv.PublicKey()
|
||||
validatorHex := hex.EncodeToString(validatorPublic.Bytes())
|
||||
validatorHex := validatorPublic.StringCompressed()
|
||||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package wallet_test
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
@ -45,9 +44,9 @@ func TestSignMultisigTx(t *testing.T) {
|
|||
"--wallet", w,
|
||||
"--wif", wif,
|
||||
"--min", "2",
|
||||
hex.EncodeToString(pubs[0].Bytes()),
|
||||
hex.EncodeToString(pubs[1].Bytes()),
|
||||
hex.EncodeToString(pubs[2].Bytes()))
|
||||
pubs[0].StringCompressed(),
|
||||
pubs[1].StringCompressed(),
|
||||
pubs[2].StringCompressed())
|
||||
}
|
||||
addAccount(wallet1Path, privs[0].WIF())
|
||||
addAccount(wallet2Path, privs[1].WIF())
|
||||
|
|
|
@ -651,7 +651,8 @@ func importDeployed(ctx *cli.Context) error {
|
|||
return cli.NewExitError("contract has no `verify` method with boolean return", 1)
|
||||
}
|
||||
acc.Address = address.Uint160ToString(cs.Hash)
|
||||
acc.Contract.Script = cs.NEF.Script
|
||||
// Explicitly overwrite single signature script of the provided WIF since the contract is known to be deployed.
|
||||
acc.Contract.Script = nil
|
||||
acc.Contract.Parameters = acc.Contract.Parameters[:0]
|
||||
for _, p := range md.Parameters {
|
||||
acc.Contract.Parameters = append(acc.Contract.Parameters, wallet.ContractParam{
|
||||
|
@ -948,14 +949,14 @@ func createAccount(wall *wallet.Wallet, pass *string) error {
|
|||
func openWallet(ctx *cli.Context, canUseWalletConfig bool) (*wallet.Wallet, *string, error) {
|
||||
path, pass, err := getWalletPathAndPass(ctx, canUseWalletConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, cli.NewExitError(fmt.Errorf("failed to get wallet path or password: %w", err), 1)
|
||||
}
|
||||
if path == "-" {
|
||||
return nil, nil, errNoStdin
|
||||
}
|
||||
w, err := wallet.NewWalletFromFile(path)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, cli.NewExitError(fmt.Errorf("failed to read wallet: %w", err), 1)
|
||||
}
|
||||
return w, pass, nil
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package wallet_test
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"os"
|
||||
|
@ -437,16 +436,16 @@ func TestWalletInit(t *testing.T) {
|
|||
"--wallet", walletPath,
|
||||
"--min", "2"}
|
||||
t.Run("invalid pub encoding", func(t *testing.T) {
|
||||
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()),
|
||||
hex.EncodeToString(pubs[1].Bytes()),
|
||||
hex.EncodeToString(pubs[2].Bytes()),
|
||||
e.RunWithError(t, append(cmd, pubs[1].StringCompressed(),
|
||||
pubs[1].StringCompressed(),
|
||||
pubs[2].StringCompressed(),
|
||||
"not-a-pub")...)
|
||||
})
|
||||
t.Run("missing WIF", func(t *testing.T) {
|
||||
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
|
||||
hex.EncodeToString(pubs[1].Bytes()),
|
||||
hex.EncodeToString(pubs[2].Bytes()),
|
||||
hex.EncodeToString(pubs[3].Bytes()))...)
|
||||
e.RunWithError(t, append(cmd, pubs[0].StringCompressed(),
|
||||
pubs[1].StringCompressed(),
|
||||
pubs[2].StringCompressed(),
|
||||
pubs[3].StringCompressed())...)
|
||||
})
|
||||
cmd = append(cmd, "--wif", privs[0].WIF())
|
||||
t.Run("InvalidPublicKeys", func(t *testing.T) {
|
||||
|
@ -455,18 +454,18 @@ func TestWalletInit(t *testing.T) {
|
|||
e.In.WriteString("multipass\r")
|
||||
defer e.In.Reset()
|
||||
|
||||
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()),
|
||||
hex.EncodeToString(pubs[1].Bytes()),
|
||||
hex.EncodeToString(pubs[2].Bytes()),
|
||||
hex.EncodeToString(pubs[3].Bytes()))...)
|
||||
e.RunWithError(t, append(cmd, pubs[1].StringCompressed(),
|
||||
pubs[1].StringCompressed(),
|
||||
pubs[2].StringCompressed(),
|
||||
pubs[3].StringCompressed())...)
|
||||
})
|
||||
e.In.WriteString("multiacc\r")
|
||||
e.In.WriteString("multipass\r")
|
||||
e.In.WriteString("multipass\r")
|
||||
e.Run(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
|
||||
hex.EncodeToString(pubs[1].Bytes()),
|
||||
hex.EncodeToString(pubs[2].Bytes()),
|
||||
hex.EncodeToString(pubs[3].Bytes()))...)
|
||||
e.Run(t, append(cmd, pubs[0].StringCompressed(),
|
||||
pubs[1].StringCompressed(),
|
||||
pubs[2].StringCompressed(),
|
||||
pubs[3].StringCompressed())...)
|
||||
|
||||
script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs)
|
||||
require.NoError(t, err)
|
||||
|
@ -482,10 +481,10 @@ func TestWalletInit(t *testing.T) {
|
|||
e.In.WriteString("multiacc\r")
|
||||
e.In.WriteString("multipass\r")
|
||||
e.In.WriteString("multipass\r")
|
||||
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
|
||||
hex.EncodeToString(pubs[1].Bytes()),
|
||||
hex.EncodeToString(pubs[2].Bytes()),
|
||||
hex.EncodeToString(pubs[3].Bytes()))...)
|
||||
e.RunWithError(t, append(cmd, pubs[0].StringCompressed(),
|
||||
pubs[1].StringCompressed(),
|
||||
pubs[2].StringCompressed(),
|
||||
pubs[3].StringCompressed())...)
|
||||
})
|
||||
|
||||
privs, pubs = testcli.GenerateKeys(t, 3)
|
||||
|
@ -508,9 +507,9 @@ func TestWalletInit(t *testing.T) {
|
|||
e.Run(t, "neo-go", "wallet", "import-multisig",
|
||||
"--wallet", walletPath,
|
||||
"--min", "2",
|
||||
hex.EncodeToString(pubs[0].Bytes()), // Public key of the already imported account
|
||||
hex.EncodeToString(pubs[1].Bytes()),
|
||||
hex.EncodeToString(pubs[2].Bytes()))
|
||||
pubs[0].StringCompressed(), // Public key of the already imported account
|
||||
pubs[1].StringCompressed(),
|
||||
pubs[2].StringCompressed())
|
||||
|
||||
w, err := wallet.NewWalletFromFile(walletPath)
|
||||
require.NoError(t, err)
|
||||
|
@ -530,9 +529,9 @@ func TestWalletInit(t *testing.T) {
|
|||
e.RunWithError(t, "neo-go", "wallet", "import-multisig",
|
||||
"--wallet", walletPath,
|
||||
"--min", "2",
|
||||
hex.EncodeToString(pubsNew[0].Bytes()),
|
||||
hex.EncodeToString(pubsNew[1].Bytes()),
|
||||
hex.EncodeToString(pubsNew[2].Bytes()))
|
||||
pubsNew[0].StringCompressed(),
|
||||
pubsNew[1].StringCompressed(),
|
||||
pubsNew[2].StringCompressed())
|
||||
|
||||
w, err := wallet.NewWalletFromFile(walletPath)
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -26,6 +26,7 @@ ProtocolConfiguration:
|
|||
Hardforks:
|
||||
Aspidochelone: 3000000
|
||||
Basilisk: 4500000
|
||||
Cockatrice: 5800000
|
||||
|
||||
ApplicationConfiguration:
|
||||
SkipBlockVerification: false
|
||||
|
|
|
@ -38,6 +38,7 @@ ProtocolConfiguration:
|
|||
Hardforks:
|
||||
Aspidochelone: 1730000
|
||||
Basilisk: 4120000
|
||||
Cockatrice: 5450000
|
||||
|
||||
ApplicationConfiguration:
|
||||
SkipBlockVerification: false
|
||||
|
|
|
@ -41,6 +41,7 @@ ProtocolConfiguration:
|
|||
Hardforks:
|
||||
Aspidochelone: 210000
|
||||
Basilisk: 2680000
|
||||
Cockatrice: 3967000
|
||||
|
||||
ApplicationConfiguration:
|
||||
SkipBlockVerification: false
|
||||
|
|
|
@ -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. |
|
||||
| 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. |
|
||||
| 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)). |
|
||||
| Magic | `uint32` | `0` | Magic number which uniquely identifies Neo network. |
|
||||
| MaxBlockSize | `uint32` | `262144` | Maximum block size in bytes. |
|
||||
| MaxBlockSystemFee | `int64` | `900000000000` | Maximum overall transactions system fee per block. |
|
||||
|
@ -345,7 +345,7 @@ protocol-related settings described in the table below.
|
|||
| P2PStateExchangeExtensions | `bool` | `false` | Enables the following P2P MPT state data exchange logic: <br>• `StateSyncInterval` protocol setting <br>• P2P commands `GetMPTDataCMD` and `MPTDataCMD` | Not supported by the C# node, thus may affect heterogeneous networks functionality. Can be supported either on MPT-complete node (`KeepOnlyLatestState`=`false`) or on light GC-enabled node (`RemoveUntraceableBlocks=true`) in which case `KeepOnlyLatestState` setting doesn't change the behavior, an appropriate set of MPTs is always stored (see `RemoveUntraceableBlocks`). |
|
||||
| ReservedAttributes | `bool` | `false` | Allows to have reserved attributes range for experimental or private purposes. |
|
||||
| SeedList | `[]string` | [] | List of initial nodes addresses used to establish connectivity. |
|
||||
| StandbyCommittee | `[]string` | [] | List of public keys of standby committee validators are chosen from. |
|
||||
| StandbyCommittee | `[]string` | [] | List of public keys of standby committee validators are chosen from. | The list of keys is not required to be sorted, but it must be exactly the same within the configuration files of all the nodes in the network. |
|
||||
| StateRootInHeader | `bool` | `false` | Enables storing state root in block header. | Experimental protocol extension! |
|
||||
| StateSyncInterval | `int` | `40000` | The number of blocks between state heights available for MPT state data synchronization. | `P2PStateExchangeExtensions` should be enabled to use this setting. |
|
||||
| TimePerBlock | `Duration` | `15s` | Minimal (and targeted for) time interval between blocks. Must be an integer number of milliseconds. |
|
||||
|
|
|
@ -388,7 +388,7 @@ subpackage with an example written in Go doc.
|
|||
configuration (just a simple `RET` script by default), pack both transactions
|
||||
into a P2PNotaryRequest and submit it to the RPC node. It returns hashes of
|
||||
the main and fallback transactions as well as their `ValidUntilBlock` value.
|
||||
If you need more control over fallback transction use `Actor` options or
|
||||
If you need more control over fallback transaction use `Actor` options or
|
||||
[func (*Actor) SendRequest](https://pkg.go.dev/github.com/nspcc-dev/neo-go/pkg/rpcclient/notary#Actor.SendRequest)
|
||||
API.
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ These should run successfully:
|
|||
* unit-tests
|
||||
* lint
|
||||
* privnet with consensus nodes
|
||||
* mainnet synchronization
|
||||
* testnet and mainnet synchronization
|
||||
* NeoFS testnet and mainnet synchronisation and containers compatibility tests
|
||||
|
||||
## Update CHANGELOG and ROADMAP
|
||||
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -4,7 +4,7 @@ go 1.20
|
|||
|
||||
require (
|
||||
github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
github.com/stretchr/testify v1.8.4
|
||||
)
|
||||
|
||||
|
|
|
@ -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/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/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -33,7 +33,7 @@ require (
|
|||
github.com/mmcloughlin/addchain v0.4.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/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 // indirect
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d // indirect
|
||||
github.com/nspcc-dev/rfc6979 v0.2.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.13.0 // indirect
|
||||
|
|
|
@ -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/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/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/zkp/xor
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
25
go.mod
25
go.mod
|
@ -14,10 +14,10 @@ require (
|
|||
github.com/holiman/uint256 v1.2.4
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/mr-tron/base58 v1.2.0
|
||||
github.com/nspcc-dev/dbft v0.0.0-20230515113611-25db6ba61d5c
|
||||
github.com/nspcc-dev/dbft v0.2.0
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12
|
||||
github.com/nspcc-dev/rfc6979 v0.2.1
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
|
@ -51,25 +51,22 @@ require (
|
|||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||
github.com/nspcc-dev/hrw v1.0.9 // indirect
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 // indirect
|
||||
github.com/nspcc-dev/neofs-crypto v0.4.0 // indirect
|
||||
github.com/nspcc-dev/tzhash v1.7.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/nspcc-dev/hrw/v2 v2.0.1 // indirect
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 // indirect
|
||||
github.com/nspcc-dev/tzhash v1.7.2 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/rs/zerolog v1.30.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
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
|
||||
golang.org/x/mod v0.16.0 // indirect
|
||||
golang.org/x/net v0.22.0 // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect
|
||||
google.golang.org/grpc v1.57.1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
)
|
||||
|
|
56
go.sum
56
go.sum
|
@ -26,7 +26,6 @@ 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/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||
|
@ -88,25 +87,22 @@ github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqky
|
|||
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/nspcc-dev/dbft v0.0.0-20230515113611-25db6ba61d5c h1:uyK5aLbAhrnZtnvobJLN24gGUrlxIJAAFqiWl+liZuo=
|
||||
github.com/nspcc-dev/dbft v0.0.0-20230515113611-25db6ba61d5c/go.mod h1:kjBC9F8L25GR+kIHy/1KgG/KfcoGnVwIiyovgq1uszk=
|
||||
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/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/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y=
|
||||
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-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.0/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM=
|
||||
github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4=
|
||||
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/hrw/v2 v2.0.1 h1:CxYUkBeJvNfMEn2lHhrV6FjY8pZPceSxXUtMVq0BUOU=
|
||||
github.com/nspcc-dev/hrw/v2 v2.0.1/go.mod h1:iZAs5hT2q47EGq6AZ0FjaUI6ggntOi7vrY4utfzk5VA=
|
||||
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-20240521091047-78685785716d/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.1-0.20240305074711-35bc78d84dc4/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12 h1:mdxtlSU2I4oVZ/7AXTLKyz8uUPbDWikZw4DM8gvrddA=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12/go.mod h1:JdsEM1qgNukrWqgOBDChcYp8oY4XUzidcKaxY4hNJvQ=
|
||||
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/tzhash v1.7.0 h1:/+aL33NC7y5OIGnY2kYgjZt8mg7LVGFMdj/KAJLndnk=
|
||||
github.com/nspcc-dev/tzhash v1.7.0/go.mod h1:Dnx9LUlOLr5paL2Rtc96x0PPs8D9eIkUtowt1n+KQus=
|
||||
github.com/nspcc-dev/tzhash v1.7.2 h1:iRXoa9TJqH/DQO7FFcqpq9BdruF9E7/xnFGlIghl5J4=
|
||||
github.com/nspcc-dev/tzhash v1.7.2/go.mod h1:oHiH0qwmTsZkeVs7pvCS5cVXUaLhXxSFvnmnZ++ijm4=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
|
@ -119,7 +115,6 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
|
|||
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
|
@ -140,11 +135,6 @@ 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/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
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/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs=
|
||||
|
@ -157,26 +147,25 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
|||
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/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/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
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/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||
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/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -208,10 +197,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-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 h1:eSaPbMR4T7WfH9FvABk36NBMacoTUKdWCvV0dx+KfOg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I=
|
||||
google.golang.org/grpc v1.57.1 h1:upNTNqv0ES+2ZOOqACwVtS3Il8M12/+Hz41RCPzAjQg=
|
||||
google.golang.org/grpc v1.57.1/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
|
||||
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
|
||||
google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
|
||||
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-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -231,7 +220,6 @@ 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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
|
||||
|
|
|
@ -196,7 +196,7 @@ func Init(t *testing.T, rootpath string, e *neotest.Executor) {
|
|||
require.NoError(t, ntr.Accounts[0].Decrypt("one", ntr.Scrypt))
|
||||
designateSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
|
||||
int64(noderoles.P2PNotary), []any{ntr.Accounts[0].PublicKey().Bytes()})
|
||||
t.Logf("Designated Notary node: %s", hex.EncodeToString(ntr.Accounts[0].PublicKey().Bytes()))
|
||||
t.Logf("Designated Notary node: %s", ntr.Accounts[0].PublicKey().StringCompressed())
|
||||
|
||||
// Block #10: push verification contract with arguments into the chain.
|
||||
verifyPath = filepath.Join(testDataPrefix, "verify_args", "verification_with_args_contract.go")
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/internal/examples/oracle
|
|||
|
||||
go 1.20
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0 h1:N+dMIBmteXjJpkH6UZ7HmNftuFxkqszfGLbhsEctnv0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231127165613-b35f351f0ba0/go.mod h1:J/Mk6+nKeKSW4wygkZQFLQ6SkLOSGX5Ga0RuuuktEag=
|
||||
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-20240521091047-78685785716d/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
|
|
|
@ -99,7 +99,7 @@ func (*FakeChain) IsExtensibleAllowed(uint160 util.Uint160) bool {
|
|||
}
|
||||
|
||||
// GetNatives implements the blockchainer.Blockchainer interface.
|
||||
func (*FakeChain) GetNatives() []state.NativeContract {
|
||||
func (*FakeChain) GetNatives() []state.Contract {
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
|
|
|
@ -286,6 +286,20 @@ func (e *Executor) Run(t *testing.T, args ...string) {
|
|||
require.NoError(t, e.run(args...))
|
||||
checkExit(t, ch, 0)
|
||||
}
|
||||
|
||||
// RunUnchecked runs command and ensures that proper exit code is set (0 if no error is returned, 1 is an error is returned).
|
||||
// The resulting error is returned (if so).
|
||||
func (e *Executor) RunUnchecked(t *testing.T, args ...string) error {
|
||||
ch := setExitFunc()
|
||||
err := e.run(args...)
|
||||
if err != nil {
|
||||
checkExit(t, ch, 1)
|
||||
} else {
|
||||
checkExit(t, ch, 0)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Executor) run(args ...string) error {
|
||||
e.Out.Reset()
|
||||
e.Err.Reset()
|
||||
|
|
|
@ -522,6 +522,19 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl, pkg *types.
|
|||
}
|
||||
}
|
||||
|
||||
// Emit defaults for named returns.
|
||||
if decl.Type.Results.NumFields() != 0 {
|
||||
for _, arg := range decl.Type.Results.List {
|
||||
for _, id := range arg.Names {
|
||||
if id.Name != "_" {
|
||||
i := c.scope.newLocal(id.Name)
|
||||
c.emitDefault(c.typeOf(arg.Type))
|
||||
c.emitStoreByIndex(varLocal, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast.Walk(c, decl.Body)
|
||||
|
||||
// If we have reached the end of the function without encountering `return` statement,
|
||||
|
@ -763,7 +776,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
for i := len(results.List) - 1; i >= 0; i-- {
|
||||
names := results.List[i].Names
|
||||
for j := len(names) - 1; j >= 0; j-- {
|
||||
c.emitLoadVar("", names[j].Name)
|
||||
if names[j].Name == "_" {
|
||||
c.emitDefault(c.typeOf(results.List[i].Type))
|
||||
} else {
|
||||
c.emitLoadVar("", names[j].Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2396,7 +2413,7 @@ func (c *codegen) writeJumps(b []byte) ([]byte, error) {
|
|||
for _, f := range c.funcs {
|
||||
f.rng.Start, f.rng.End = correctRange(f.rng.Start, f.rng.End, nopOffsets)
|
||||
}
|
||||
return removeNOPs(b, nopOffsets), nil
|
||||
return removeNOPs(b, nopOffsets, c.sequencePoints), nil
|
||||
}
|
||||
|
||||
func correctRange(start, end uint16, offsets []int) (uint16, uint16) {
|
||||
|
@ -2438,9 +2455,10 @@ func (c *codegen) replaceLabelWithOffset(ip int, arg []byte) (int, error) {
|
|||
// This is done in 2 passes:
|
||||
// 1. Alter jump offsets taking into account parts to be removed.
|
||||
// 2. Perform actual removal of jump targets.
|
||||
// 3. Reevaluate debug sequence points offsets.
|
||||
// Note: after jump offsets altering, there can appear new candidates for conversion.
|
||||
// These are ignored for now.
|
||||
func removeNOPs(b []byte, nopOffsets []int) []byte {
|
||||
func removeNOPs(b []byte, nopOffsets []int, sequencePoints map[string][]DebugSeqPoint) []byte {
|
||||
if len(nopOffsets) == 0 {
|
||||
return b
|
||||
}
|
||||
|
@ -2502,6 +2520,20 @@ func removeNOPs(b []byte, nopOffsets []int) []byte {
|
|||
copy(b[start-copyOffset:], b[start+1:end])
|
||||
copyOffset++
|
||||
}
|
||||
|
||||
// 3. Reevaluate debug sequence points.
|
||||
for _, seqPoints := range sequencePoints {
|
||||
for i := range seqPoints {
|
||||
diff := 0
|
||||
for _, offset := range nopOffsets {
|
||||
if offset < seqPoints[i].Opcode {
|
||||
diff++
|
||||
}
|
||||
}
|
||||
seqPoints[i].Opcode -= diff
|
||||
}
|
||||
}
|
||||
|
||||
return b[:len(b)-copyOffset]
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"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/native"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
|
||||
"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/transaction"
|
||||
|
@ -610,7 +610,7 @@ func TestCallWithVersion(t *testing.T) {
|
|||
e.DeployContract(t, ctr, nil)
|
||||
c := e.CommitteeInvoker(ctr.Hash)
|
||||
|
||||
policyH := state.CreateNativeContractHash(nativenames.Policy)
|
||||
policyH := nativehashes.PolicyContract
|
||||
t.Run("good", func(t *testing.T) {
|
||||
c.Invoke(t, e.Chain.GetBaseExecFee(), "callWithVersion", policyH.BytesBE(), 0, "getExecFeeFactor")
|
||||
})
|
||||
|
|
|
@ -7,16 +7,17 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func testShortenJumps(t *testing.T, before, after []opcode.Opcode, indices []int) {
|
||||
func testShortenJumps(t *testing.T, before, after []opcode.Opcode, indices []int, spBefore, spAfter map[string][]DebugSeqPoint) {
|
||||
prog := make([]byte, len(before))
|
||||
for i := range before {
|
||||
prog[i] = byte(before[i])
|
||||
}
|
||||
raw := removeNOPs(prog, indices)
|
||||
raw := removeNOPs(prog, indices, spBefore)
|
||||
actual := make([]opcode.Opcode, len(raw))
|
||||
for i := range raw {
|
||||
actual[i] = opcode.Opcode(raw[i])
|
||||
}
|
||||
require.Equal(t, spAfter, spBefore)
|
||||
require.Equal(t, after, actual)
|
||||
}
|
||||
|
||||
|
@ -45,18 +46,32 @@ func TestShortenJumps(t *testing.T) {
|
|||
op, 3, 12, 0, 0, opcode.PUSH1, opcode.NOP,
|
||||
sop, 249, sop, 0xFF - 2,
|
||||
}
|
||||
testShortenJumps(t, before, after, []int{2, 3, 4, 16, 17, 18, 21, 22, 23})
|
||||
spBefore := map[string][]DebugSeqPoint{
|
||||
"test": {
|
||||
DebugSeqPoint{Opcode: 0}, DebugSeqPoint{Opcode: 5},
|
||||
DebugSeqPoint{Opcode: 7}, DebugSeqPoint{Opcode: 12},
|
||||
DebugSeqPoint{Opcode: 14}, DebugSeqPoint{Opcode: 19},
|
||||
},
|
||||
}
|
||||
spAfter := map[string][]DebugSeqPoint{
|
||||
"test": {
|
||||
DebugSeqPoint{Opcode: 0}, DebugSeqPoint{Opcode: 2},
|
||||
DebugSeqPoint{Opcode: 4}, DebugSeqPoint{Opcode: 9},
|
||||
DebugSeqPoint{Opcode: 11}, DebugSeqPoint{Opcode: 13},
|
||||
},
|
||||
}
|
||||
testShortenJumps(t, before, after, []int{2, 3, 4, 16, 17, 18, 21, 22, 23}, spBefore, spAfter)
|
||||
})
|
||||
}
|
||||
t.Run("NoReplace", func(t *testing.T) {
|
||||
b := []byte{0, 1, 2, 3, 4, 5}
|
||||
expected := []byte{0, 1, 2, 3, 4, 5}
|
||||
require.Equal(t, expected, removeNOPs(b, nil))
|
||||
require.Equal(t, expected, removeNOPs(b, nil, map[string][]DebugSeqPoint{}))
|
||||
})
|
||||
t.Run("InvalidIndex", func(t *testing.T) {
|
||||
before := []byte{byte(opcode.PUSH1), 0, 0, 0, 0}
|
||||
require.Panics(t, func() {
|
||||
removeNOPs(before, []int{0})
|
||||
removeNOPs(before, []int{0}, map[string][]DebugSeqPoint{})
|
||||
})
|
||||
})
|
||||
t.Run("SideConditions", func(t *testing.T) {
|
||||
|
@ -69,7 +84,19 @@ func TestShortenJumps(t *testing.T) {
|
|||
opcode.JMP, 2,
|
||||
opcode.JMP, 2,
|
||||
}
|
||||
testShortenJumps(t, before, after, []int{2, 3, 4, 7, 8, 9})
|
||||
spBefore := map[string][]DebugSeqPoint{
|
||||
"test": {
|
||||
DebugSeqPoint{Opcode: 0},
|
||||
DebugSeqPoint{Opcode: 5},
|
||||
},
|
||||
}
|
||||
spAfter := map[string][]DebugSeqPoint{
|
||||
"test": {
|
||||
DebugSeqPoint{Opcode: 0},
|
||||
DebugSeqPoint{Opcode: 2},
|
||||
},
|
||||
}
|
||||
testShortenJumps(t, before, after, []int{2, 3, 4, 7, 8, 9}, spBefore, spAfter)
|
||||
})
|
||||
t.Run("Backwards", func(t *testing.T) {
|
||||
before := []opcode.Opcode{
|
||||
|
@ -82,7 +109,21 @@ func TestShortenJumps(t *testing.T) {
|
|||
opcode.JMP, 0xFF - 1,
|
||||
opcode.JMP, 0xFF - 1,
|
||||
}
|
||||
testShortenJumps(t, before, after, []int{2, 3, 4, 7, 8, 9, 12, 13, 14})
|
||||
spBefore := map[string][]DebugSeqPoint{
|
||||
"test": {
|
||||
DebugSeqPoint{Opcode: 0},
|
||||
DebugSeqPoint{Opcode: 5},
|
||||
DebugSeqPoint{Opcode: 10},
|
||||
},
|
||||
}
|
||||
spAfter := map[string][]DebugSeqPoint{
|
||||
"test": {
|
||||
DebugSeqPoint{Opcode: 0},
|
||||
DebugSeqPoint{Opcode: 2},
|
||||
DebugSeqPoint{Opcode: 4},
|
||||
},
|
||||
}
|
||||
testShortenJumps(t, before, after, []int{2, 3, 4, 7, 8, 9, 12, 13, 14}, spBefore, spAfter)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -100,6 +141,17 @@ func TestWriteJumps(t *testing.T) {
|
|||
"main": {rng: DebugRange{Start: 4, End: 9}},
|
||||
"method": {rng: DebugRange{Start: 10, End: 11}},
|
||||
}
|
||||
c.sequencePoints = map[string][]DebugSeqPoint{
|
||||
"init": {
|
||||
DebugSeqPoint{Opcode: 1}, DebugSeqPoint{Opcode: 3},
|
||||
},
|
||||
"main": {
|
||||
DebugSeqPoint{Opcode: 4}, DebugSeqPoint{Opcode: 9},
|
||||
},
|
||||
"method": {
|
||||
DebugSeqPoint{Opcode: 10}, DebugSeqPoint{Opcode: 11},
|
||||
},
|
||||
}
|
||||
|
||||
expProg := []byte{
|
||||
byte(opcode.NOP), byte(opcode.JMP), 2, byte(opcode.RET),
|
||||
|
@ -111,11 +163,23 @@ func TestWriteJumps(t *testing.T) {
|
|||
"main": {rng: DebugRange{Start: 4, End: 6}},
|
||||
"method": {rng: DebugRange{Start: 7, End: 8}},
|
||||
}
|
||||
expSeqPoints := map[string][]DebugSeqPoint{
|
||||
"init": {
|
||||
DebugSeqPoint{Opcode: 1}, DebugSeqPoint{Opcode: 3},
|
||||
},
|
||||
"main": {
|
||||
DebugSeqPoint{Opcode: 4}, DebugSeqPoint{Opcode: 6},
|
||||
},
|
||||
"method": {
|
||||
DebugSeqPoint{Opcode: 7}, DebugSeqPoint{Opcode: 8},
|
||||
},
|
||||
}
|
||||
|
||||
buf, err := c.writeJumps(before)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expProg, buf)
|
||||
require.Equal(t, expFuncs, c.funcs)
|
||||
require.Equal(t, expSeqPoints, c.sequencePoints)
|
||||
}
|
||||
|
||||
func TestWriteJumpsLastJump(t *testing.T) {
|
||||
|
|
|
@ -74,8 +74,10 @@ func TestRoleManagementRole(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCryptoLibNamedCurve(t *testing.T) {
|
||||
require.EqualValues(t, native.Secp256k1, crypto.Secp256k1)
|
||||
require.EqualValues(t, native.Secp256r1, crypto.Secp256r1)
|
||||
require.EqualValues(t, native.Secp256k1Sha256, crypto.Secp256k1Sha256)
|
||||
require.EqualValues(t, native.Secp256r1Sha256, crypto.Secp256r1Sha256)
|
||||
require.EqualValues(t, native.Secp256k1Keccak256, crypto.Secp256k1Keccak256)
|
||||
require.EqualValues(t, native.Secp256r1Keccak256, crypto.Secp256r1Keccak256)
|
||||
}
|
||||
|
||||
func TestOracleContractValues(t *testing.T) {
|
||||
|
@ -163,6 +165,7 @@ func TestNativeHelpersCompile(t *testing.T) {
|
|||
{"getAllCandidates", nil},
|
||||
{"getCandidateVote", []string{pub}},
|
||||
{"getCommittee", nil},
|
||||
{"getCommitteeAddress", nil},
|
||||
{"getGasPerBlock", nil},
|
||||
{"getNextBlockValidators", nil},
|
||||
{"getRegisterPrice", nil},
|
||||
|
@ -232,13 +235,14 @@ func TestNativeHelpersCompile(t *testing.T) {
|
|||
{"sha256", []string{"[]byte{1, 2, 3}"}},
|
||||
{"ripemd160", []string{"[]byte{1, 2, 3}"}},
|
||||
{"murmur32", []string{"[]byte{1, 2, 3}", "123"}},
|
||||
{"verifyWithECDsa", []string{"[]byte{1, 2, 3}", pub, sig, "crypto.Secp256k1"}},
|
||||
{"verifyWithECDsa", []string{"[]byte{1, 2, 3}", pub, sig, "crypto.Secp256k1Sha256"}},
|
||||
{"bls12381Serialize", []string{"crypto.Bls12381Point{}"}},
|
||||
{"bls12381Deserialize", []string{"[]byte{1, 2, 3}"}},
|
||||
{"bls12381Equal", []string{"crypto.Bls12381Point{}", "crypto.Bls12381Point{}"}},
|
||||
{"bls12381Add", []string{"crypto.Bls12381Point{}", "crypto.Bls12381Point{}"}},
|
||||
{"bls12381Mul", []string{"crypto.Bls12381Point{}", "[]byte{1, 2, 3}", "true"}},
|
||||
{"bls12381Pairing", []string{"crypto.Bls12381Point{}", "crypto.Bls12381Point{}"}},
|
||||
{"keccak256", []string{"[]byte{1, 2, 3}"}},
|
||||
})
|
||||
runNativeTestCases(t, cs.Std.ContractMD, "std", []nativeTestCase{
|
||||
{"serialize", []string{"[]byte{1, 2, 3}"}},
|
||||
|
@ -286,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.MethodAndPrice {
|
||||
func getMethod(t *testing.T, ctr interop.ContractMD, name string, params []string) interop.HFSpecificMethodAndPrice {
|
||||
paramLen := len(params)
|
||||
|
||||
switch {
|
||||
|
@ -306,8 +310,10 @@ func getMethod(t *testing.T, ctr interop.ContractMD, name string, params []strin
|
|||
name = strings.TrimSuffix(name, "WithData")
|
||||
}
|
||||
|
||||
md, ok := ctr.GetMethod(name, paramLen)
|
||||
require.True(t, ok, ctr.Manifest.Name, name, paramLen)
|
||||
latestHF := config.LatestHardfork()
|
||||
cMD := ctr.HFSpecificContractMD(&latestHF)
|
||||
md, ok := cMD.GetMethod(name, paramLen)
|
||||
require.True(t, ok, cMD.Manifest.Name, name, paramLen)
|
||||
return md
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,19 @@ func TestNamedReturn(t *testing.T) {
|
|||
t.Run("AnotherVariable", runCase("b, c", big.NewInt(5)))
|
||||
}
|
||||
|
||||
func TestNamedReturnDefault(t *testing.T) {
|
||||
src := `package foo
|
||||
func Main() int {
|
||||
a, b, c := f()
|
||||
return a + b + c
|
||||
}
|
||||
func f() (_ int, b int, c int) {
|
||||
b += 1
|
||||
return
|
||||
}`
|
||||
eval(t, src, big.NewInt(1))
|
||||
}
|
||||
|
||||
func TestTypeAssertReturn(t *testing.T) {
|
||||
src := `
|
||||
package main
|
||||
|
|
|
@ -5,6 +5,13 @@ package config
|
|||
// Hardfork represents the application hard-fork identifier.
|
||||
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 (
|
||||
// HFAspidochelone represents hard-fork introduced in #2469 (ported from
|
||||
// https://github.com/neo-project/neo/pull/2712) and #2519 (ported from
|
||||
|
@ -15,6 +22,11 @@ const (
|
|||
// https://github.com/neo-project/neo/pull/2883) and #3085 (ported from
|
||||
// https://github.com/neo-project/neo/pull/2810).
|
||||
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
|
||||
// before hfLast.
|
||||
hfLast
|
||||
|
@ -36,9 +48,38 @@ 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
|
||||
// Hardfork name.
|
||||
func IsHardforkValid(s string) bool {
|
||||
_, ok := hardforks[s]
|
||||
return ok
|
||||
}
|
||||
|
||||
// LatestHardfork returns latest known hardfork.
|
||||
func LatestHardfork() Hardfork {
|
||||
return hfLast >> 1
|
||||
}
|
||||
|
|
|
@ -8,27 +8,31 @@ func _() {
|
|||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[HFDefault-0]
|
||||
_ = x[HFAspidochelone-1]
|
||||
_ = x[HFBasilisk-2]
|
||||
_ = x[hfLast-4]
|
||||
_ = x[HFCockatrice-4]
|
||||
_ = x[hfLast-8]
|
||||
}
|
||||
|
||||
const (
|
||||
_Hardfork_name_0 = "AspidocheloneBasilisk"
|
||||
_Hardfork_name_1 = "hfLast"
|
||||
_Hardfork_name_0 = "DefaultAspidocheloneBasilisk"
|
||||
_Hardfork_name_1 = "Cockatrice"
|
||||
_Hardfork_name_2 = "hfLast"
|
||||
)
|
||||
|
||||
var (
|
||||
_Hardfork_index_0 = [...]uint8{0, 13, 21}
|
||||
_Hardfork_index_0 = [...]uint8{0, 7, 20, 28}
|
||||
)
|
||||
|
||||
func (i Hardfork) String() string {
|
||||
switch {
|
||||
case 1 <= i && i <= 2:
|
||||
i -= 1
|
||||
case i <= 2:
|
||||
return _Hardfork_name_0[_Hardfork_index_0[i]:_Hardfork_index_0[i+1]]
|
||||
case i == 4:
|
||||
return _Hardfork_name_1
|
||||
case i == 8:
|
||||
return _Hardfork_name_2
|
||||
default:
|
||||
return "Hardfork(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package config
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
@ -320,7 +319,7 @@ func TestGenesisExtensionsMarshalYAML(t *testing.T) {
|
|||
|
||||
t.Run("unmarshal config", func(t *testing.T) {
|
||||
t.Run("good", func(t *testing.T) {
|
||||
pubStr := hex.EncodeToString(pub.Bytes())
|
||||
pubStr := pub.StringCompressed()
|
||||
script := []byte{1, 2, 3, 4}
|
||||
cfgYml := fmt.Sprintf(`ProtocolConfiguration:
|
||||
Genesis:
|
||||
|
@ -354,7 +353,7 @@ func TestGenesisExtensionsMarshalYAML(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("unknown role", func(t *testing.T) {
|
||||
pubStr := hex.EncodeToString(pub.Bytes())
|
||||
pubStr := pub.StringCompressed()
|
||||
cfgYml := fmt.Sprintf(`ProtocolConfiguration:
|
||||
Genesis:
|
||||
Roles:
|
||||
|
@ -367,7 +366,7 @@ func TestGenesisExtensionsMarshalYAML(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("last role", func(t *testing.T) {
|
||||
pubStr := hex.EncodeToString(pub.Bytes())
|
||||
pubStr := pub.StringCompressed()
|
||||
cfgYml := fmt.Sprintf(`ProtocolConfiguration:
|
||||
Genesis:
|
||||
Roles:
|
||||
|
|
|
@ -3,8 +3,7 @@ package consensus
|
|||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nspcc-dev/dbft/block"
|
||||
"github.com/nspcc-dev/dbft/crypto"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
coreb "github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
|
@ -20,10 +19,10 @@ type neoBlock struct {
|
|||
signature []byte
|
||||
}
|
||||
|
||||
var _ block.Block = (*neoBlock)(nil)
|
||||
var _ dbft.Block[util.Uint256] = (*neoBlock)(nil)
|
||||
|
||||
// Sign implements the block.Block interface.
|
||||
func (n *neoBlock) Sign(key crypto.PrivateKey) error {
|
||||
func (n *neoBlock) Sign(key dbft.PrivateKey) error {
|
||||
k := key.(*privateKey)
|
||||
sig := k.PrivateKey.SignHashable(uint32(n.network), &n.Block)
|
||||
n.signature = sig
|
||||
|
@ -31,7 +30,7 @@ func (n *neoBlock) Sign(key crypto.PrivateKey) error {
|
|||
}
|
||||
|
||||
// Verify implements the block.Block interface.
|
||||
func (n *neoBlock) Verify(key crypto.PublicKey, sign []byte) error {
|
||||
func (n *neoBlock) Verify(key dbft.PublicKey, sign []byte) error {
|
||||
k := key.(*publicKey)
|
||||
if k.PublicKey.VerifyHashable(sign, uint32(n.network), &n.Block) {
|
||||
return nil
|
||||
|
@ -40,8 +39,8 @@ func (n *neoBlock) Verify(key crypto.PublicKey, sign []byte) error {
|
|||
}
|
||||
|
||||
// Transactions implements the block.Block interface.
|
||||
func (n *neoBlock) Transactions() []block.Transaction {
|
||||
txes := make([]block.Transaction, len(n.Block.Transactions))
|
||||
func (n *neoBlock) Transactions() []dbft.Transaction[util.Uint256] {
|
||||
txes := make([]dbft.Transaction[util.Uint256], len(n.Block.Transactions))
|
||||
for i, tx := range n.Block.Transactions {
|
||||
txes[i] = tx
|
||||
}
|
||||
|
@ -50,16 +49,13 @@ func (n *neoBlock) Transactions() []block.Transaction {
|
|||
}
|
||||
|
||||
// SetTransactions implements the block.Block interface.
|
||||
func (n *neoBlock) SetTransactions(txes []block.Transaction) {
|
||||
func (n *neoBlock) SetTransactions(txes []dbft.Transaction[util.Uint256]) {
|
||||
n.Block.Transactions = make([]*transaction.Transaction, len(txes))
|
||||
for i, tx := range txes {
|
||||
n.Block.Transactions[i] = tx.(*transaction.Transaction)
|
||||
}
|
||||
}
|
||||
|
||||
// Version implements the block.Block interface.
|
||||
func (n *neoBlock) Version() uint32 { return n.Block.Version }
|
||||
|
||||
// PrevHash implements the block.Block interface.
|
||||
func (n *neoBlock) PrevHash() util.Uint256 { return n.Block.PrevHash }
|
||||
|
||||
|
@ -72,11 +68,5 @@ func (n *neoBlock) Timestamp() uint64 { return n.Block.Timestamp * nsInMs }
|
|||
// Index implements the block.Block interface.
|
||||
func (n *neoBlock) Index() uint32 { return n.Block.Index }
|
||||
|
||||
// ConsensusData implements the block.Block interface.
|
||||
func (n *neoBlock) ConsensusData() uint64 { return n.Block.Nonce }
|
||||
|
||||
// NextConsensus implements the block.Block interface.
|
||||
func (n *neoBlock) NextConsensus() util.Uint160 { return n.Block.NextConsensus }
|
||||
|
||||
// Signature implements the block.Block interface.
|
||||
func (n *neoBlock) Signature() []byte { return n.signature }
|
||||
|
|
|
@ -3,7 +3,7 @@ package consensus
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/dbft/block"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"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/util"
|
||||
|
@ -22,9 +22,6 @@ func TestNeoBlock_Sign(t *testing.T) {
|
|||
func TestNeoBlock_Setters(t *testing.T) {
|
||||
b := new(neoBlock)
|
||||
|
||||
b.Block.Version = 1
|
||||
require.EqualValues(t, 1, b.Version())
|
||||
|
||||
b.Block.Index = 12
|
||||
require.EqualValues(t, 12, b.Index())
|
||||
|
||||
|
@ -35,13 +32,10 @@ func TestNeoBlock_Setters(t *testing.T) {
|
|||
b.Block.MerkleRoot = util.Uint256{1, 2, 3, 4}
|
||||
require.Equal(t, util.Uint256{1, 2, 3, 4}, b.MerkleRoot())
|
||||
|
||||
b.Block.NextConsensus = util.Uint160{9, 2}
|
||||
require.Equal(t, util.Uint160{9, 2}, b.NextConsensus())
|
||||
|
||||
b.Block.PrevHash = util.Uint256{9, 8, 7}
|
||||
require.Equal(t, util.Uint256{9, 8, 7}, b.PrevHash())
|
||||
|
||||
txx := []block.Transaction{transaction.New([]byte{byte(opcode.PUSH1)}, 1)}
|
||||
txx := []dbft.Transaction[util.Uint256]{transaction.New([]byte{byte(opcode.PUSH1)}, 1)}
|
||||
b.SetTransactions(txx)
|
||||
require.Equal(t, txx, b.Transactions())
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package consensus
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/neo-go/internal/random"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -52,8 +51,8 @@ func getDifferentPayloads(t *testing.T, n int) (payloads []Payload) {
|
|||
var sign [signatureSize]byte
|
||||
random.Fill(sign[:])
|
||||
|
||||
payloads[i].SetValidatorIndex(uint16(i))
|
||||
payloads[i].SetType(payload.MessageType(commitType))
|
||||
payloads[i].message.ValidatorIndex = byte(i)
|
||||
payloads[i].message.Type = commitType
|
||||
payloads[i].payload = &commit{
|
||||
signature: sign,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package consensus
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
)
|
||||
|
||||
|
@ -9,10 +9,10 @@ import (
|
|||
type changeView struct {
|
||||
newViewNumber byte
|
||||
timestamp uint64
|
||||
reason payload.ChangeViewReason
|
||||
reason dbft.ChangeViewReason
|
||||
}
|
||||
|
||||
var _ payload.ChangeView = (*changeView)(nil)
|
||||
var _ dbft.ChangeView = (*changeView)(nil)
|
||||
|
||||
// EncodeBinary implements the io.Serializable interface.
|
||||
func (c *changeView) EncodeBinary(w *io.BinWriter) {
|
||||
|
@ -23,23 +23,11 @@ func (c *changeView) EncodeBinary(w *io.BinWriter) {
|
|||
// DecodeBinary implements the io.Serializable interface.
|
||||
func (c *changeView) DecodeBinary(r *io.BinReader) {
|
||||
c.timestamp = r.ReadU64LE()
|
||||
c.reason = payload.ChangeViewReason(r.ReadB())
|
||||
c.reason = dbft.ChangeViewReason(r.ReadB())
|
||||
}
|
||||
|
||||
// NewViewNumber implements the payload.ChangeView interface.
|
||||
func (c changeView) NewViewNumber() byte { return c.newViewNumber }
|
||||
|
||||
// SetNewViewNumber implements the payload.ChangeView interface.
|
||||
func (c *changeView) SetNewViewNumber(view byte) { c.newViewNumber = view }
|
||||
|
||||
// Timestamp implements the payload.ChangeView interface.
|
||||
func (c changeView) Timestamp() uint64 { return c.timestamp * nsInMs }
|
||||
|
||||
// SetTimestamp implements the payload.ChangeView interface.
|
||||
func (c *changeView) SetTimestamp(ts uint64) { c.timestamp = ts / nsInMs }
|
||||
|
||||
// Reason implements the payload.ChangeView interface.
|
||||
func (c changeView) Reason() payload.ChangeViewReason { return c.reason }
|
||||
|
||||
// SetReason implements the payload.ChangeView interface.
|
||||
func (c *changeView) SetReason(reason payload.ChangeViewReason) { c.reason = reason }
|
||||
func (c changeView) Reason() dbft.ChangeViewReason { return c.reason }
|
||||
|
|
|
@ -3,15 +3,16 @@ package consensus
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestChangeView_Setters(t *testing.T) {
|
||||
var c changeView
|
||||
func TestChangeView_Getters(t *testing.T) {
|
||||
var c = &changeView{
|
||||
newViewNumber: 2,
|
||||
reason: dbft.CVTimeout,
|
||||
}
|
||||
|
||||
c.SetTimestamp(123 * nsInMs)
|
||||
require.EqualValues(t, 123*nsInMs, c.Timestamp())
|
||||
|
||||
c.SetNewViewNumber(2)
|
||||
require.EqualValues(t, 2, c.NewViewNumber())
|
||||
require.EqualValues(t, dbft.CVTimeout, c.Reason())
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package consensus
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
)
|
||||
|
||||
|
@ -14,7 +14,7 @@ type commit struct {
|
|||
// without a leading byte (0x04, uncompressed).
|
||||
const signatureSize = 64
|
||||
|
||||
var _ payload.Commit = (*commit)(nil)
|
||||
var _ dbft.Commit = (*commit)(nil)
|
||||
|
||||
// EncodeBinary implements the io.Serializable interface.
|
||||
func (c *commit) EncodeBinary(w *io.BinWriter) {
|
||||
|
@ -28,8 +28,3 @@ func (c *commit) DecodeBinary(r *io.BinReader) {
|
|||
|
||||
// Signature implements the payload.Commit interface.
|
||||
func (c commit) Signature() []byte { return c.signature[:] }
|
||||
|
||||
// SetSignature implements the payload.Commit interface.
|
||||
func (c *commit) SetSignature(signature []byte) {
|
||||
copy(c.signature[:], signature)
|
||||
}
|
||||
|
|
|
@ -7,11 +7,12 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCommit_Setters(t *testing.T) {
|
||||
func TestCommit_Getters(t *testing.T) {
|
||||
var sign [signatureSize]byte
|
||||
random.Fill(sign[:])
|
||||
|
||||
var c commit
|
||||
c.SetSignature(sign[:])
|
||||
var c = &commit{
|
||||
signature: sign,
|
||||
}
|
||||
require.Equal(t, sign[:], c.Signature())
|
||||
}
|
||||
|
|
|
@ -8,9 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/dbft/block"
|
||||
"github.com/nspcc-dev/dbft/crypto"
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft/timer"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
coreb "github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
|
@ -88,7 +86,7 @@ type service struct {
|
|||
log *zap.Logger
|
||||
// txx is a fifo cache which stores miner transactions.
|
||||
txx *relayCache
|
||||
dbft *dbft.DBFT
|
||||
dbft *dbft.DBFT[util.Uint256]
|
||||
// messages and transactions are channels needed to process
|
||||
// everything in single thread.
|
||||
messages chan Payload
|
||||
|
@ -181,48 +179,46 @@ func NewService(cfg Config) (Service, error) {
|
|||
}
|
||||
}
|
||||
|
||||
srv.dbft = dbft.New(
|
||||
dbft.WithLogger(srv.log),
|
||||
dbft.WithSecondsPerBlock(cfg.TimePerBlock),
|
||||
dbft.WithGetKeyPair(srv.getKeyPair),
|
||||
srv.dbft, err = dbft.New[util.Uint256](
|
||||
dbft.WithTimer[util.Uint256](timer.New()),
|
||||
dbft.WithLogger[util.Uint256](srv.log),
|
||||
dbft.WithSecondsPerBlock[util.Uint256](cfg.TimePerBlock),
|
||||
dbft.WithGetKeyPair[util.Uint256](srv.getKeyPair),
|
||||
dbft.WithRequestTx(cfg.RequestTx),
|
||||
dbft.WithStopTxFlow(cfg.StopTxFlow),
|
||||
dbft.WithGetTx(srv.getTx),
|
||||
dbft.WithGetVerified(srv.getVerifiedTx),
|
||||
dbft.WithBroadcast(srv.broadcast),
|
||||
dbft.WithProcessBlock(srv.processBlock),
|
||||
dbft.WithVerifyBlock(srv.verifyBlock),
|
||||
dbft.WithGetBlock(srv.getBlock),
|
||||
dbft.WithWatchOnly(func() bool { return false }),
|
||||
dbft.WithNewBlockFromContext(srv.newBlockFromContext),
|
||||
dbft.WithCurrentHeight(cfg.Chain.BlockHeight),
|
||||
dbft.WithStopTxFlow[util.Uint256](cfg.StopTxFlow),
|
||||
dbft.WithGetTx[util.Uint256](srv.getTx),
|
||||
dbft.WithGetVerified[util.Uint256](srv.getVerifiedTx),
|
||||
dbft.WithBroadcast[util.Uint256](srv.broadcast),
|
||||
dbft.WithProcessBlock[util.Uint256](srv.processBlock),
|
||||
dbft.WithVerifyBlock[util.Uint256](srv.verifyBlock),
|
||||
dbft.WithGetBlock[util.Uint256](srv.getBlock),
|
||||
dbft.WithWatchOnly[util.Uint256](func() bool { return false }),
|
||||
dbft.WithNewBlockFromContext[util.Uint256](srv.newBlockFromContext),
|
||||
dbft.WithCurrentHeight[util.Uint256](cfg.Chain.BlockHeight),
|
||||
dbft.WithCurrentBlockHash(cfg.Chain.CurrentBlockHash),
|
||||
dbft.WithGetValidators(srv.getValidators),
|
||||
dbft.WithGetConsensusAddress(srv.getConsensusAddress),
|
||||
dbft.WithGetValidators[util.Uint256](srv.getValidators),
|
||||
|
||||
dbft.WithNewConsensusPayload(srv.newPayload),
|
||||
dbft.WithNewPrepareRequest(srv.newPrepareRequest),
|
||||
dbft.WithNewPrepareResponse(func() payload.PrepareResponse { return new(prepareResponse) }),
|
||||
dbft.WithNewChangeView(func() payload.ChangeView { return new(changeView) }),
|
||||
dbft.WithNewCommit(func() payload.Commit { return new(commit) }),
|
||||
dbft.WithNewRecoveryRequest(func() payload.RecoveryRequest { return new(recoveryRequest) }),
|
||||
dbft.WithNewRecoveryMessage(func() payload.RecoveryMessage {
|
||||
return &recoveryMessage{stateRootEnabled: srv.ProtocolConfiguration.StateRootInHeader}
|
||||
}),
|
||||
dbft.WithVerifyPrepareRequest(srv.verifyRequest),
|
||||
dbft.WithVerifyPrepareResponse(func(_ payload.ConsensusPayload) error { return nil }),
|
||||
dbft.WithNewConsensusPayload[util.Uint256](srv.newPayload),
|
||||
dbft.WithNewPrepareRequest[util.Uint256](srv.newPrepareRequest),
|
||||
dbft.WithNewPrepareResponse[util.Uint256](srv.newPrepareResponse),
|
||||
dbft.WithNewChangeView[util.Uint256](srv.newChangeView),
|
||||
dbft.WithNewCommit[util.Uint256](srv.newCommit),
|
||||
dbft.WithNewRecoveryRequest[util.Uint256](srv.newRecoveryRequest),
|
||||
dbft.WithNewRecoveryMessage[util.Uint256](srv.newRecoveryMessage),
|
||||
dbft.WithVerifyPrepareRequest[util.Uint256](srv.verifyRequest),
|
||||
dbft.WithVerifyPrepareResponse[util.Uint256](srv.verifyResponse),
|
||||
)
|
||||
|
||||
if srv.dbft == nil {
|
||||
return nil, errors.New("can't initialize dBFT")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't initialize dBFT: %w", err)
|
||||
}
|
||||
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
var (
|
||||
_ block.Transaction = (*transaction.Transaction)(nil)
|
||||
_ block.Block = (*neoBlock)(nil)
|
||||
_ dbft.Transaction[util.Uint256] = (*transaction.Transaction)(nil)
|
||||
_ dbft.Block[util.Uint256] = (*neoBlock)(nil)
|
||||
)
|
||||
|
||||
// NewPayload creates a new consensus payload for the provided network.
|
||||
|
@ -238,17 +234,17 @@ func NewPayload(m netmode.Magic, stateRootEnabled bool) *Payload {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *service) newPayload(c *dbft.Context, t payload.MessageType, msg any) payload.ConsensusPayload {
|
||||
func (s *service) newPayload(c *dbft.Context[util.Uint256], t dbft.MessageType, msg any) dbft.ConsensusPayload[util.Uint256] {
|
||||
cp := NewPayload(s.ProtocolConfiguration.Magic, s.ProtocolConfiguration.StateRootInHeader)
|
||||
cp.SetHeight(c.BlockIndex)
|
||||
cp.SetValidatorIndex(uint16(c.MyIndex))
|
||||
cp.SetViewNumber(c.ViewNumber)
|
||||
cp.SetType(t)
|
||||
cp.BlockIndex = c.BlockIndex
|
||||
cp.message.ValidatorIndex = byte(c.MyIndex)
|
||||
cp.message.ViewNumber = c.ViewNumber
|
||||
cp.message.Type = messageType(t)
|
||||
if pr, ok := msg.(*prepareRequest); ok {
|
||||
pr.SetPrevHash(s.dbft.PrevHash)
|
||||
pr.SetVersion(s.dbft.Version)
|
||||
pr.prevHash = s.dbft.PrevHash
|
||||
pr.version = coreb.VersionInitial
|
||||
}
|
||||
cp.SetPayload(msg)
|
||||
cp.payload = msg.(io.Serializable)
|
||||
|
||||
cp.Extensible.ValidBlockStart = 0
|
||||
cp.Extensible.ValidBlockEnd = c.BlockIndex
|
||||
|
@ -257,8 +253,12 @@ func (s *service) newPayload(c *dbft.Context, t payload.MessageType, msg any) pa
|
|||
return cp
|
||||
}
|
||||
|
||||
func (s *service) newPrepareRequest() payload.PrepareRequest {
|
||||
r := new(prepareRequest)
|
||||
func (s *service) newPrepareRequest(ts uint64, nonce uint64, transactionsHashes []util.Uint256) dbft.PrepareRequest[util.Uint256] {
|
||||
r := &prepareRequest{
|
||||
timestamp: ts / nsInMs,
|
||||
nonce: nonce,
|
||||
transactionHashes: transactionsHashes,
|
||||
}
|
||||
if s.ProtocolConfiguration.StateRootInHeader {
|
||||
r.stateRootEnabled = true
|
||||
if sr, err := s.Chain.GetStateRoot(s.dbft.BlockIndex - 1); err == nil {
|
||||
|
@ -270,6 +270,38 @@ func (s *service) newPrepareRequest() payload.PrepareRequest {
|
|||
return r
|
||||
}
|
||||
|
||||
func (s *service) newPrepareResponse(preparationHash util.Uint256) dbft.PrepareResponse[util.Uint256] {
|
||||
return &prepareResponse{
|
||||
preparationHash: preparationHash,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) newChangeView(newViewNumber byte, reason dbft.ChangeViewReason, ts uint64) dbft.ChangeView {
|
||||
return &changeView{
|
||||
newViewNumber: newViewNumber,
|
||||
timestamp: ts / nsInMs,
|
||||
reason: reason,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) newCommit(signature []byte) dbft.Commit {
|
||||
c := new(commit)
|
||||
copy(c.signature[:], signature)
|
||||
return c
|
||||
}
|
||||
|
||||
func (s *service) newRecoveryRequest(ts uint64) dbft.RecoveryRequest {
|
||||
return &recoveryRequest{
|
||||
timestamp: ts / nsInMs,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) newRecoveryMessage() dbft.RecoveryMessage[util.Uint256] {
|
||||
return &recoveryMessage{
|
||||
stateRootEnabled: s.ProtocolConfiguration.StateRootInHeader,
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns service name.
|
||||
func (s *service) Name() string {
|
||||
return "consensus"
|
||||
|
@ -315,18 +347,18 @@ events:
|
|||
s.Chain.UnsubscribeFromBlocks(s.blockEvents)
|
||||
break events
|
||||
case <-s.dbft.Timer.C():
|
||||
hv := s.dbft.Timer.HV()
|
||||
h, v := s.dbft.Timer.Height(), s.dbft.Timer.View()
|
||||
s.log.Debug("timer fired",
|
||||
zap.Uint32("height", hv.Height),
|
||||
zap.Uint("view", uint(hv.View)))
|
||||
s.dbft.OnTimeout(hv)
|
||||
zap.Uint32("height", h),
|
||||
zap.Uint("view", uint(v)))
|
||||
s.dbft.OnTimeout(h, v)
|
||||
case msg := <-s.messages:
|
||||
fields := []zap.Field{
|
||||
zap.Uint8("from", msg.message.ValidatorIndex),
|
||||
zap.Stringer("type", msg.Type()),
|
||||
}
|
||||
|
||||
if msg.Type() == payload.RecoveryMessageType {
|
||||
if msg.Type() == dbft.RecoveryMessageType {
|
||||
rec := msg.GetRecoveryMessage().(*recoveryMessage)
|
||||
if rec.preparationHash == nil {
|
||||
req := rec.GetPrepareRequest(&msg, s.dbft.Validators, uint16(s.dbft.PrimaryIndex))
|
||||
|
@ -389,7 +421,7 @@ func (s *service) handleChainBlock(b *coreb.Block) {
|
|||
zap.Uint32("dbft index", s.dbft.BlockIndex),
|
||||
zap.Uint32("chain index", s.Chain.BlockHeight()))
|
||||
s.postBlock(b)
|
||||
s.dbft.InitializeConsensus(0, b.Timestamp*nsInMs)
|
||||
s.dbft.Reset(b.Timestamp * nsInMs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,7 +436,7 @@ func (s *service) validatePayload(p *Payload) bool {
|
|||
return p.Sender == h
|
||||
}
|
||||
|
||||
func (s *service) getKeyPair(pubs []crypto.PublicKey) (int, crypto.PrivateKey, crypto.PublicKey) {
|
||||
func (s *service) getKeyPair(pubs []dbft.PublicKey) (int, dbft.PrivateKey, dbft.PublicKey) {
|
||||
if s.wallet != nil {
|
||||
for i := range pubs {
|
||||
sh := pubs[i].(*publicKey).GetScriptHash()
|
||||
|
@ -466,7 +498,7 @@ func (s *service) OnTransaction(tx *transaction.Transaction) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *service) broadcast(p payload.ConsensusPayload) {
|
||||
func (s *service) broadcast(p dbft.ConsensusPayload[util.Uint256]) {
|
||||
if err := p.(*Payload).Sign(s.dbft.Priv.(*privateKey)); err != nil {
|
||||
s.log.Warn("can't sign consensus payload", zap.Error(err))
|
||||
}
|
||||
|
@ -475,7 +507,7 @@ func (s *service) broadcast(p payload.ConsensusPayload) {
|
|||
s.Config.Broadcast(ep)
|
||||
}
|
||||
|
||||
func (s *service) getTx(h util.Uint256) block.Transaction {
|
||||
func (s *service) getTx(h util.Uint256) dbft.Transaction[util.Uint256] {
|
||||
if tx := s.txx.Get(h); tx != nil {
|
||||
return tx.(*transaction.Transaction)
|
||||
}
|
||||
|
@ -491,7 +523,7 @@ func (s *service) getTx(h util.Uint256) block.Transaction {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *service) verifyBlock(b block.Block) bool {
|
||||
func (s *service) verifyBlock(b dbft.Block[util.Uint256]) bool {
|
||||
coreb := &b.(*neoBlock).Block
|
||||
|
||||
if s.Chain.BlockHeight() >= coreb.Index {
|
||||
|
@ -558,12 +590,12 @@ var (
|
|||
errInvalidTransactionsCount = errors.New("invalid transactions count")
|
||||
)
|
||||
|
||||
func (s *service) verifyRequest(p payload.ConsensusPayload) error {
|
||||
func (s *service) verifyRequest(p dbft.ConsensusPayload[util.Uint256]) error {
|
||||
req := p.GetPrepareRequest().(*prepareRequest)
|
||||
if req.prevHash != s.dbft.PrevHash {
|
||||
return errInvalidPrevHash
|
||||
}
|
||||
if req.version != s.dbft.Version {
|
||||
if req.version != coreb.VersionInitial {
|
||||
return errInvalidVersion
|
||||
}
|
||||
if s.ProtocolConfiguration.StateRootInHeader {
|
||||
|
@ -583,7 +615,11 @@ func (s *service) verifyRequest(p payload.ConsensusPayload) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *service) processBlock(b block.Block) {
|
||||
func (s *service) verifyResponse(p dbft.ConsensusPayload[util.Uint256]) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) processBlock(b dbft.Block[util.Uint256]) {
|
||||
bb := &b.(*neoBlock).Block
|
||||
bb.Script = *(s.getBlockWitness(bb))
|
||||
|
||||
|
@ -638,7 +674,7 @@ func (s *service) getBlockWitness(b *coreb.Block) *transaction.Witness {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *service) getBlock(h util.Uint256) block.Block {
|
||||
func (s *service) getBlock(h util.Uint256) dbft.Block[util.Uint256] {
|
||||
b, err := s.Chain.GetBlock(h)
|
||||
if err != nil {
|
||||
return nil
|
||||
|
@ -647,7 +683,7 @@ func (s *service) getBlock(h util.Uint256) block.Block {
|
|||
return &neoBlock{network: s.ProtocolConfiguration.Magic, Block: *b}
|
||||
}
|
||||
|
||||
func (s *service) getVerifiedTx() []block.Transaction {
|
||||
func (s *service) getVerifiedTx() []dbft.Transaction[util.Uint256] {
|
||||
pool := s.Config.Chain.GetMemPool()
|
||||
|
||||
var txx []*transaction.Transaction
|
||||
|
@ -671,7 +707,7 @@ func (s *service) getVerifiedTx() []block.Transaction {
|
|||
txx = s.Config.Chain.ApplyPolicyToTxSet(txx)
|
||||
}
|
||||
|
||||
res := make([]block.Transaction, len(txx))
|
||||
res := make([]dbft.Transaction[util.Uint256], len(txx))
|
||||
for i := range txx {
|
||||
res[i] = txx[i]
|
||||
}
|
||||
|
@ -679,7 +715,7 @@ func (s *service) getVerifiedTx() []block.Transaction {
|
|||
return res
|
||||
}
|
||||
|
||||
func (s *service) getValidators(txes ...block.Transaction) []crypto.PublicKey {
|
||||
func (s *service) getValidators(txes ...dbft.Transaction[util.Uint256]) []dbft.PublicKey {
|
||||
var (
|
||||
pKeys []*keys.PublicKey
|
||||
err error
|
||||
|
@ -699,7 +735,7 @@ func (s *service) getValidators(txes ...block.Transaction) []crypto.PublicKey {
|
|||
s.log.Error("error while trying to get validators", zap.Error(err))
|
||||
}
|
||||
|
||||
pubs := make([]crypto.PublicKey, len(pKeys))
|
||||
pubs := make([]dbft.PublicKey, len(pKeys))
|
||||
for i := range pKeys {
|
||||
pubs[i] = &publicKey{PublicKey: pKeys[i]}
|
||||
}
|
||||
|
@ -707,11 +743,7 @@ func (s *service) getValidators(txes ...block.Transaction) []crypto.PublicKey {
|
|||
return pubs
|
||||
}
|
||||
|
||||
func (s *service) getConsensusAddress(validators ...crypto.PublicKey) util.Uint160 {
|
||||
return util.Uint160{}
|
||||
}
|
||||
|
||||
func convertKeys(validators []crypto.PublicKey) (pubs []*keys.PublicKey) {
|
||||
func convertKeys(validators []dbft.PublicKey) (pubs []*keys.PublicKey) {
|
||||
pubs = make([]*keys.PublicKey, len(validators))
|
||||
for i, k := range validators {
|
||||
pubs[i] = k.(*publicKey).PublicKey
|
||||
|
@ -720,7 +752,7 @@ func convertKeys(validators []crypto.PublicKey) (pubs []*keys.PublicKey) {
|
|||
return
|
||||
}
|
||||
|
||||
func (s *service) newBlockFromContext(ctx *dbft.Context) block.Block {
|
||||
func (s *service) newBlockFromContext(ctx *dbft.Context[util.Uint256]) dbft.Block[util.Uint256] {
|
||||
block := &neoBlock{network: s.ProtocolConfiguration.Magic}
|
||||
|
||||
block.Block.Timestamp = ctx.Timestamp / nsInMs
|
||||
|
@ -750,9 +782,9 @@ func (s *service) newBlockFromContext(ctx *dbft.Context) block.Block {
|
|||
if err != nil {
|
||||
s.log.Fatal(fmt.Sprintf("failed to create multisignature script: %s", err.Error()))
|
||||
}
|
||||
block.Block.NextConsensus = crypto.Hash160(script)
|
||||
block.Block.NextConsensus = hash.Hash160(script)
|
||||
block.Block.PrevHash = ctx.PrevHash
|
||||
block.Block.Version = ctx.Version
|
||||
block.Block.Version = coreb.VersionInitial
|
||||
|
||||
primaryIndex := byte(ctx.PrimaryIndex)
|
||||
block.Block.PrimaryIndex = primaryIndex
|
||||
|
|
|
@ -4,9 +4,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/dbft/block"
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft/timer"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/internal/random"
|
||||
"github.com/nspcc-dev/neo-go/internal/testchain"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
|
@ -38,7 +36,7 @@ func TestNewService(t *testing.T) {
|
|||
signTx(t, srv.Chain, tx)
|
||||
require.NoError(t, srv.Chain.PoolTx(tx))
|
||||
|
||||
var txx []block.Transaction
|
||||
var txx []dbft.Transaction[util.Uint256]
|
||||
require.NotPanics(t, func() { txx = srv.getVerifiedTx() })
|
||||
require.Len(t, txx, 1)
|
||||
require.Equal(t, tx, txx[0])
|
||||
|
@ -65,10 +63,10 @@ func TestNewWatchingService(t *testing.T) {
|
|||
|
||||
func collectBlock(t *testing.T, bc *core.Blockchain, srv *service) {
|
||||
h := bc.BlockHeight()
|
||||
srv.dbft.OnTimeout(timer.HV{Height: srv.dbft.Context.BlockIndex}) // Collect and add block to the chain.
|
||||
srv.dbft.OnTimeout(srv.dbft.Context.BlockIndex, 0) // Collect and add block to the chain.
|
||||
header, err := bc.GetHeader(bc.GetHeaderHash(h + 1))
|
||||
require.NoError(t, err)
|
||||
srv.dbft.InitializeConsensus(0, header.Timestamp*nsInMs) // Init consensus manually at the next height, as we don't run the consensus service.
|
||||
srv.dbft.Reset(header.Timestamp * nsInMs) // Init consensus manually at the next height, as we don't run the consensus service.
|
||||
}
|
||||
|
||||
func initServiceNextConsensus(t *testing.T, newAcc *wallet.Account, offset uint32) (*service, *wallet.Account) {
|
||||
|
@ -102,7 +100,7 @@ func initServiceNextConsensus(t *testing.T, newAcc *wallet.Account, offset uint3
|
|||
srv.dbft.Start(0)
|
||||
header, err := bc.GetHeader(bc.GetHeaderHash(h + 1))
|
||||
require.NoError(t, err)
|
||||
srv.dbft.InitializeConsensus(0, header.Timestamp*nsInMs) // Init consensus manually at the next height, as we don't run the consensus service.
|
||||
srv.dbft.Reset(header.Timestamp * nsInMs) // Init consensus manually at the next height, as we don't run the consensus service.
|
||||
|
||||
// Register new candidate.
|
||||
b.Reset()
|
||||
|
@ -214,14 +212,14 @@ func TestService_GetVerified(t *testing.T) {
|
|||
p := new(Payload)
|
||||
// One PrepareRequest and three ChangeViews.
|
||||
if i == 1 {
|
||||
p.SetType(payload.PrepareRequestType)
|
||||
p.SetPayload(&prepareRequest{prevHash: srv.Chain.CurrentBlockHash(), transactionHashes: hashes})
|
||||
p.message.Type = messageType(dbft.PrepareRequestType)
|
||||
p.payload = &prepareRequest{prevHash: srv.Chain.CurrentBlockHash(), transactionHashes: hashes}
|
||||
} else {
|
||||
p.SetType(payload.ChangeViewType)
|
||||
p.SetPayload(&changeView{newViewNumber: 1, timestamp: uint64(time.Now().UnixNano() / nsInMs)})
|
||||
p.message.Type = messageType(dbft.ChangeViewType)
|
||||
p.payload = &changeView{newViewNumber: 1, timestamp: uint64(time.Now().UnixNano() / nsInMs)}
|
||||
}
|
||||
p.SetHeight(1)
|
||||
p.SetValidatorIndex(uint16(i))
|
||||
p.BlockIndex = 1
|
||||
p.message.ValidatorIndex = byte(i)
|
||||
|
||||
priv, _ := getTestValidator(i)
|
||||
require.NoError(t, p.Sign(priv))
|
||||
|
@ -255,10 +253,10 @@ func TestService_ValidatePayload(t *testing.T) {
|
|||
priv, _ := getTestValidator(1)
|
||||
p := new(Payload)
|
||||
p.Sender = priv.GetScriptHash()
|
||||
p.SetPayload(&prepareRequest{})
|
||||
p.payload = &prepareRequest{}
|
||||
|
||||
t.Run("invalid validator index", func(t *testing.T) {
|
||||
p.SetValidatorIndex(11)
|
||||
p.message.ValidatorIndex = 11
|
||||
require.NoError(t, p.Sign(priv))
|
||||
|
||||
var ok bool
|
||||
|
@ -267,20 +265,20 @@ func TestService_ValidatePayload(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("wrong validator index", func(t *testing.T) {
|
||||
p.SetValidatorIndex(2)
|
||||
p.message.ValidatorIndex = 2
|
||||
require.NoError(t, p.Sign(priv))
|
||||
require.False(t, srv.validatePayload(p))
|
||||
})
|
||||
|
||||
t.Run("invalid sender", func(t *testing.T) {
|
||||
p.SetValidatorIndex(1)
|
||||
p.message.ValidatorIndex = 1
|
||||
p.Sender = util.Uint160{}
|
||||
require.NoError(t, p.Sign(priv))
|
||||
require.False(t, srv.validatePayload(p))
|
||||
})
|
||||
|
||||
t.Run("normal case", func(t *testing.T) {
|
||||
p.SetValidatorIndex(1)
|
||||
p.message.ValidatorIndex = 1
|
||||
p.Sender = priv.GetScriptHash()
|
||||
require.NoError(t, p.Sign(priv))
|
||||
require.True(t, srv.validatePayload(p))
|
||||
|
@ -330,12 +328,12 @@ func TestService_PrepareRequest(t *testing.T) {
|
|||
|
||||
priv, _ := getTestValidator(1)
|
||||
p := new(Payload)
|
||||
p.SetValidatorIndex(1)
|
||||
p.message.ValidatorIndex = 1
|
||||
|
||||
prevHash := srv.Chain.CurrentBlockHash()
|
||||
|
||||
checkRequest := func(t *testing.T, expectedErr error, req *prepareRequest) {
|
||||
p.SetPayload(req)
|
||||
p.payload = req
|
||||
require.NoError(t, p.Sign(priv))
|
||||
err := srv.verifyRequest(p)
|
||||
if expectedErr == nil {
|
||||
|
@ -377,8 +375,8 @@ func TestService_OnPayload(t *testing.T) {
|
|||
|
||||
priv, _ := getTestValidator(1)
|
||||
p := new(Payload)
|
||||
p.SetValidatorIndex(1)
|
||||
p.SetPayload(&prepareRequest{})
|
||||
p.message.ValidatorIndex = 1
|
||||
p.payload = &prepareRequest{}
|
||||
p.encodeData()
|
||||
|
||||
// sender is invalid
|
||||
|
@ -386,9 +384,9 @@ func TestService_OnPayload(t *testing.T) {
|
|||
shouldNotReceive(t, srv.messages)
|
||||
|
||||
p = new(Payload)
|
||||
p.SetValidatorIndex(1)
|
||||
p.message.ValidatorIndex = 1
|
||||
p.Sender = priv.GetScriptHash()
|
||||
p.SetPayload(&prepareRequest{})
|
||||
p.payload = &prepareRequest{}
|
||||
require.NoError(t, p.Sign(priv))
|
||||
require.NoError(t, srv.OnPayload(&p.Extensible))
|
||||
shouldReceive(t, srv.messages)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"crypto/sha256"
|
||||
"errors"
|
||||
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
)
|
||||
|
||||
|
@ -13,6 +14,8 @@ type privateKey struct {
|
|||
*keys.PrivateKey
|
||||
}
|
||||
|
||||
var _ dbft.PrivateKey = &privateKey{}
|
||||
|
||||
// Sign implements the dbft's crypto.PrivateKey interface.
|
||||
func (p *privateKey) Sign(data []byte) ([]byte, error) {
|
||||
return p.PrivateKey.Sign(data), nil
|
||||
|
@ -24,6 +27,8 @@ type publicKey struct {
|
|||
*keys.PublicKey
|
||||
}
|
||||
|
||||
var _ dbft.PublicKey = &publicKey{}
|
||||
|
||||
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
||||
func (p publicKey) MarshalBinary() (data []byte, err error) {
|
||||
return p.PublicKey.Bytes(), nil
|
||||
|
|
|
@ -3,7 +3,7 @@ package consensus
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
npayload "github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||
|
@ -44,6 +44,8 @@ const (
|
|||
payloadGasLimit = 2000000 // 0.02 GAS
|
||||
)
|
||||
|
||||
var _ dbft.ConsensusPayload[util.Uint256] = &Payload{}
|
||||
|
||||
// ViewNumber implements the payload.ConsensusPayload interface.
|
||||
func (p Payload) ViewNumber() byte {
|
||||
return p.message.ViewNumber
|
||||
|
@ -55,13 +57,8 @@ func (p *Payload) SetViewNumber(view byte) {
|
|||
}
|
||||
|
||||
// Type implements the payload.ConsensusPayload interface.
|
||||
func (p Payload) Type() payload.MessageType {
|
||||
return payload.MessageType(p.message.Type)
|
||||
}
|
||||
|
||||
// SetType implements the payload.ConsensusPayload interface.
|
||||
func (p *Payload) SetType(t payload.MessageType) {
|
||||
p.message.Type = messageType(t)
|
||||
func (p Payload) Type() dbft.MessageType {
|
||||
return dbft.MessageType(p.message.Type)
|
||||
}
|
||||
|
||||
// Payload implements the payload.ConsensusPayload interface.
|
||||
|
@ -69,35 +66,30 @@ func (p Payload) Payload() any {
|
|||
return p.payload
|
||||
}
|
||||
|
||||
// SetPayload implements the payload.ConsensusPayload interface.
|
||||
func (p *Payload) SetPayload(pl any) {
|
||||
p.payload = pl.(io.Serializable)
|
||||
}
|
||||
|
||||
// GetChangeView implements the payload.ConsensusPayload interface.
|
||||
func (p Payload) GetChangeView() payload.ChangeView { return p.payload.(payload.ChangeView) }
|
||||
func (p Payload) GetChangeView() dbft.ChangeView { return p.payload.(dbft.ChangeView) }
|
||||
|
||||
// GetPrepareRequest implements the payload.ConsensusPayload interface.
|
||||
func (p Payload) GetPrepareRequest() payload.PrepareRequest {
|
||||
return p.payload.(payload.PrepareRequest)
|
||||
func (p Payload) GetPrepareRequest() dbft.PrepareRequest[util.Uint256] {
|
||||
return p.payload.(dbft.PrepareRequest[util.Uint256])
|
||||
}
|
||||
|
||||
// GetPrepareResponse implements the payload.ConsensusPayload interface.
|
||||
func (p Payload) GetPrepareResponse() payload.PrepareResponse {
|
||||
return p.payload.(payload.PrepareResponse)
|
||||
func (p Payload) GetPrepareResponse() dbft.PrepareResponse[util.Uint256] {
|
||||
return p.payload.(dbft.PrepareResponse[util.Uint256])
|
||||
}
|
||||
|
||||
// GetCommit implements the payload.ConsensusPayload interface.
|
||||
func (p Payload) GetCommit() payload.Commit { return p.payload.(payload.Commit) }
|
||||
func (p Payload) GetCommit() dbft.Commit { return p.payload.(dbft.Commit) }
|
||||
|
||||
// GetRecoveryRequest implements the payload.ConsensusPayload interface.
|
||||
func (p Payload) GetRecoveryRequest() payload.RecoveryRequest {
|
||||
return p.payload.(payload.RecoveryRequest)
|
||||
func (p Payload) GetRecoveryRequest() dbft.RecoveryRequest {
|
||||
return p.payload.(dbft.RecoveryRequest)
|
||||
}
|
||||
|
||||
// GetRecoveryMessage implements the payload.ConsensusPayload interface.
|
||||
func (p Payload) GetRecoveryMessage() payload.RecoveryMessage {
|
||||
return p.payload.(payload.RecoveryMessage)
|
||||
func (p Payload) GetRecoveryMessage() dbft.RecoveryMessage[util.Uint256] {
|
||||
return p.payload.(dbft.RecoveryMessage[util.Uint256])
|
||||
}
|
||||
|
||||
// ValidatorIndex implements the payload.ConsensusPayload interface.
|
||||
|
@ -115,11 +107,6 @@ func (p Payload) Height() uint32 {
|
|||
return p.message.BlockIndex
|
||||
}
|
||||
|
||||
// SetHeight implements the payload.ConsensusPayload interface.
|
||||
func (p *Payload) SetHeight(h uint32) {
|
||||
p.message.BlockIndex = h
|
||||
}
|
||||
|
||||
// EncodeBinary implements the io.Serializable interface.
|
||||
func (p *Payload) EncodeBinary(w *io.BinWriter) {
|
||||
p.encodeData()
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/internal/random"
|
||||
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
|
@ -29,50 +29,45 @@ var messageTypes = []messageType{
|
|||
recoveryMessageType,
|
||||
}
|
||||
|
||||
func TestConsensusPayload_Setters(t *testing.T) {
|
||||
var p Payload
|
||||
func TestConsensusPayload_Getters(t *testing.T) {
|
||||
var p = &Payload{
|
||||
Extensible: npayload.Extensible{},
|
||||
message: message{
|
||||
Type: prepareRequestType,
|
||||
BlockIndex: 11,
|
||||
ValidatorIndex: 4,
|
||||
ViewNumber: 2,
|
||||
},
|
||||
}
|
||||
|
||||
//p.SetVersion(1)
|
||||
//assert.EqualValues(t, 1, p.Version())
|
||||
|
||||
//p.SetPrevHash(util.Uint256{1, 2, 3})
|
||||
//assert.Equal(t, util.Uint256{1, 2, 3}, p.PrevHash())
|
||||
|
||||
p.SetValidatorIndex(4)
|
||||
assert.EqualValues(t, 4, p.ValidatorIndex())
|
||||
|
||||
p.SetHeight(11)
|
||||
assert.EqualValues(t, 11, p.Height())
|
||||
|
||||
p.SetViewNumber(2)
|
||||
assert.EqualValues(t, 2, p.ViewNumber())
|
||||
|
||||
p.SetType(payload.PrepareRequestType)
|
||||
assert.Equal(t, payload.PrepareRequestType, p.Type())
|
||||
assert.Equal(t, dbft.PrepareRequestType, p.Type())
|
||||
|
||||
pl := randomMessage(t, prepareRequestType)
|
||||
p.SetPayload(pl)
|
||||
p.payload = pl
|
||||
require.Equal(t, pl, p.Payload())
|
||||
require.Equal(t, pl, p.GetPrepareRequest())
|
||||
|
||||
pl = randomMessage(t, prepareResponseType)
|
||||
p.SetPayload(pl)
|
||||
p.payload = pl
|
||||
require.Equal(t, pl, p.GetPrepareResponse())
|
||||
|
||||
pl = randomMessage(t, commitType)
|
||||
p.SetPayload(pl)
|
||||
p.payload = pl
|
||||
require.Equal(t, pl, p.GetCommit())
|
||||
|
||||
pl = randomMessage(t, changeViewType)
|
||||
p.SetPayload(pl)
|
||||
p.payload = pl
|
||||
require.Equal(t, pl, p.GetChangeView())
|
||||
|
||||
pl = randomMessage(t, recoveryRequestType)
|
||||
p.SetPayload(pl)
|
||||
p.payload = pl
|
||||
require.Equal(t, pl, p.GetRecoveryRequest())
|
||||
|
||||
pl = randomMessage(t, recoveryMessageType)
|
||||
p.SetPayload(pl)
|
||||
p.payload = pl
|
||||
require.Equal(t, pl, p.GetRecoveryMessage())
|
||||
}
|
||||
|
||||
|
@ -290,7 +285,7 @@ func TestPayload_DecodeFromPrivnet(t *testing.T) {
|
|||
p := NewPayload(netmode.PrivNet, false)
|
||||
p.DecodeBinary(buf)
|
||||
require.NoError(t, buf.Err)
|
||||
require.Equal(t, payload.CommitType, p.Type())
|
||||
require.Equal(t, dbft.CommitType, p.Type())
|
||||
require.Equal(t, uint32(2), p.Height())
|
||||
require.Equal(t, uint16(3), p.ValidatorIndex())
|
||||
require.Equal(t, byte(0), p.ViewNumber())
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package consensus
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -18,7 +18,7 @@ type prepareRequest struct {
|
|||
stateRoot util.Uint256
|
||||
}
|
||||
|
||||
var _ payload.PrepareRequest = (*prepareRequest)(nil)
|
||||
var _ dbft.PrepareRequest[util.Uint256] = (*prepareRequest)(nil)
|
||||
|
||||
// EncodeBinary implements the io.Serializable interface.
|
||||
func (p *prepareRequest) EncodeBinary(w *io.BinWriter) {
|
||||
|
@ -47,46 +47,11 @@ func (p *prepareRequest) DecodeBinary(r *io.BinReader) {
|
|||
}
|
||||
}
|
||||
|
||||
// Version implements the payload.PrepareRequest interface.
|
||||
func (p prepareRequest) Version() uint32 {
|
||||
return p.version
|
||||
}
|
||||
|
||||
// SetVersion implements the payload.PrepareRequest interface.
|
||||
func (p *prepareRequest) SetVersion(v uint32) {
|
||||
p.version = v
|
||||
}
|
||||
|
||||
// PrevHash implements the payload.PrepareRequest interface.
|
||||
func (p prepareRequest) PrevHash() util.Uint256 {
|
||||
return p.prevHash
|
||||
}
|
||||
|
||||
// SetPrevHash implements the payload.PrepareRequest interface.
|
||||
func (p *prepareRequest) SetPrevHash(h util.Uint256) {
|
||||
p.prevHash = h
|
||||
}
|
||||
|
||||
// Timestamp implements the payload.PrepareRequest interface.
|
||||
func (p *prepareRequest) Timestamp() uint64 { return p.timestamp * nsInMs }
|
||||
|
||||
// SetTimestamp implements the payload.PrepareRequest interface.
|
||||
func (p *prepareRequest) SetTimestamp(ts uint64) { p.timestamp = ts / nsInMs }
|
||||
|
||||
// Nonce implements the payload.PrepareRequest interface.
|
||||
func (p *prepareRequest) Nonce() uint64 { return p.nonce }
|
||||
|
||||
// SetNonce implements the payload.PrepareRequest interface.
|
||||
func (p *prepareRequest) SetNonce(nonce uint64) { p.nonce = nonce }
|
||||
|
||||
// TransactionHashes implements the payload.PrepareRequest interface.
|
||||
func (p *prepareRequest) TransactionHashes() []util.Uint256 { return p.transactionHashes }
|
||||
|
||||
// SetTransactionHashes implements the payload.PrepareRequest interface.
|
||||
func (p *prepareRequest) SetTransactionHashes(hs []util.Uint256) { p.transactionHashes = hs }
|
||||
|
||||
// NextConsensus implements the payload.PrepareRequest interface.
|
||||
func (p *prepareRequest) NextConsensus() util.Uint160 { return util.Uint160{} }
|
||||
|
||||
// SetNextConsensus implements the payload.PrepareRequest interface.
|
||||
func (p *prepareRequest) SetNextConsensus(_ util.Uint160) {}
|
||||
|
|
|
@ -10,24 +10,17 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPrepareRequest_Setters(t *testing.T) {
|
||||
var p prepareRequest
|
||||
func TestPrepareRequest_Getters(t *testing.T) {
|
||||
hashes := []util.Uint256{random.Uint256(), random.Uint256()}
|
||||
var p = &prepareRequest{
|
||||
version: 123,
|
||||
prevHash: util.Uint256{1, 2, 3},
|
||||
timestamp: 123,
|
||||
transactionHashes: hashes,
|
||||
}
|
||||
|
||||
p.SetTimestamp(123)
|
||||
// 123ns -> 0ms -> 0ns
|
||||
require.EqualValues(t, 0, p.Timestamp())
|
||||
|
||||
p.SetTimestamp(1230000)
|
||||
// 1230000ns -> 1ms -> 1000000ns
|
||||
require.EqualValues(t, 1000000, p.Timestamp())
|
||||
|
||||
p.SetNextConsensus(util.Uint160{5, 6, 7})
|
||||
require.Equal(t, util.Uint160{}, p.NextConsensus())
|
||||
|
||||
hashes := [2]util.Uint256{random.Uint256(), random.Uint256()}
|
||||
|
||||
p.SetTransactionHashes(hashes[:])
|
||||
require.Equal(t, hashes[:], p.TransactionHashes())
|
||||
require.EqualValues(t, 123000000, p.Timestamp())
|
||||
require.Equal(t, hashes, p.TransactionHashes())
|
||||
}
|
||||
|
||||
func TestPrepareRequest_EncodeDecodeBinary(t *testing.T) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package consensus
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
@ -11,7 +11,7 @@ type prepareResponse struct {
|
|||
preparationHash util.Uint256
|
||||
}
|
||||
|
||||
var _ payload.PrepareResponse = (*prepareResponse)(nil)
|
||||
var _ dbft.PrepareResponse[util.Uint256] = (*prepareResponse)(nil)
|
||||
|
||||
// EncodeBinary implements the io.Serializable interface.
|
||||
func (p *prepareResponse) EncodeBinary(w *io.BinWriter) {
|
||||
|
@ -25,6 +25,3 @@ func (p *prepareResponse) DecodeBinary(r *io.BinReader) {
|
|||
|
||||
// PreparationHash implements the payload.PrepareResponse interface.
|
||||
func (p *prepareResponse) PreparationHash() util.Uint256 { return p.preparationHash }
|
||||
|
||||
// SetPreparationHash implements the payload.PrepareResponse interface.
|
||||
func (p *prepareResponse) SetPreparationHash(h util.Uint256) { p.preparationHash = h }
|
||||
|
|
|
@ -8,8 +8,9 @@ import (
|
|||
)
|
||||
|
||||
func TestPrepareResponse_Setters(t *testing.T) {
|
||||
var p prepareResponse
|
||||
var p = prepareResponse{
|
||||
preparationHash: util.Uint256{1, 2, 3},
|
||||
}
|
||||
|
||||
p.SetPreparationHash(util.Uint256{1, 2, 3})
|
||||
require.Equal(t, util.Uint256{1, 2, 3}, p.PreparationHash())
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@ package consensus
|
|||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nspcc-dev/dbft/crypto"
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
npayload "github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -41,7 +40,7 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
var _ payload.RecoveryMessage = (*recoveryMessage)(nil)
|
||||
var _ dbft.RecoveryMessage[util.Uint256] = (*recoveryMessage)(nil)
|
||||
|
||||
// DecodeBinary implements the io.Serializable interface.
|
||||
func (m *recoveryMessage) DecodeBinary(r *io.BinReader) {
|
||||
|
@ -139,11 +138,11 @@ func (p *preparationCompact) EncodeBinary(w *io.BinWriter) {
|
|||
}
|
||||
|
||||
// AddPayload implements the payload.RecoveryMessage interface.
|
||||
func (m *recoveryMessage) AddPayload(p payload.ConsensusPayload) {
|
||||
func (m *recoveryMessage) AddPayload(p dbft.ConsensusPayload[util.Uint256]) {
|
||||
validator := uint8(p.ValidatorIndex())
|
||||
|
||||
switch p.Type() {
|
||||
case payload.PrepareRequestType:
|
||||
case dbft.PrepareRequestType:
|
||||
m.prepareRequest = &message{
|
||||
Type: prepareRequestType,
|
||||
ViewNumber: p.ViewNumber(),
|
||||
|
@ -156,24 +155,24 @@ func (m *recoveryMessage) AddPayload(p payload.ConsensusPayload) {
|
|||
ValidatorIndex: validator,
|
||||
InvocationScript: p.(*Payload).Witness.InvocationScript,
|
||||
})
|
||||
case payload.PrepareResponseType:
|
||||
case dbft.PrepareResponseType:
|
||||
m.preparationPayloads = append(m.preparationPayloads, &preparationCompact{
|
||||
ValidatorIndex: validator,
|
||||
InvocationScript: p.(*Payload).Witness.InvocationScript,
|
||||
})
|
||||
|
||||
if m.preparationHash == nil {
|
||||
h := p.GetPrepareResponse().PreparationHash()
|
||||
h := p.GetPrepareResponse().(*prepareResponse).preparationHash
|
||||
m.preparationHash = &h
|
||||
}
|
||||
case payload.ChangeViewType:
|
||||
case dbft.ChangeViewType:
|
||||
m.changeViewPayloads = append(m.changeViewPayloads, &changeViewCompact{
|
||||
ValidatorIndex: validator,
|
||||
OriginalViewNumber: p.ViewNumber(),
|
||||
Timestamp: p.GetChangeView().Timestamp() / nsInMs,
|
||||
Timestamp: p.GetChangeView().(*changeView).timestamp,
|
||||
InvocationScript: p.(*Payload).Witness.InvocationScript,
|
||||
})
|
||||
case payload.CommitType:
|
||||
case dbft.CommitType:
|
||||
m.commitPayloads = append(m.commitPayloads, &commitCompact{
|
||||
ValidatorIndex: validator,
|
||||
ViewNumber: p.ViewNumber(),
|
||||
|
@ -184,7 +183,7 @@ func (m *recoveryMessage) AddPayload(p payload.ConsensusPayload) {
|
|||
}
|
||||
|
||||
// GetPrepareRequest implements the payload.RecoveryMessage interface.
|
||||
func (m *recoveryMessage) GetPrepareRequest(p payload.ConsensusPayload, validators []crypto.PublicKey, primary uint16) payload.ConsensusPayload {
|
||||
func (m *recoveryMessage) GetPrepareRequest(p dbft.ConsensusPayload[util.Uint256], validators []dbft.PublicKey, primary uint16) dbft.ConsensusPayload[util.Uint256] {
|
||||
if m.prepareRequest == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -202,7 +201,7 @@ func (m *recoveryMessage) GetPrepareRequest(p payload.ConsensusPayload, validato
|
|||
}
|
||||
|
||||
req := fromPayload(prepareRequestType, p.(*Payload), m.prepareRequest.payload)
|
||||
req.SetValidatorIndex(primary)
|
||||
req.message.ValidatorIndex = byte(primary)
|
||||
req.Sender = validators[primary].(*publicKey).GetScriptHash()
|
||||
req.Witness.InvocationScript = compact.InvocationScript
|
||||
req.Witness.VerificationScript = getVerificationScript(uint8(primary), validators)
|
||||
|
@ -211,18 +210,18 @@ func (m *recoveryMessage) GetPrepareRequest(p payload.ConsensusPayload, validato
|
|||
}
|
||||
|
||||
// GetPrepareResponses implements the payload.RecoveryMessage interface.
|
||||
func (m *recoveryMessage) GetPrepareResponses(p payload.ConsensusPayload, validators []crypto.PublicKey) []payload.ConsensusPayload {
|
||||
func (m *recoveryMessage) GetPrepareResponses(p dbft.ConsensusPayload[util.Uint256], validators []dbft.PublicKey) []dbft.ConsensusPayload[util.Uint256] {
|
||||
if m.preparationHash == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ps := make([]payload.ConsensusPayload, len(m.preparationPayloads))
|
||||
ps := make([]dbft.ConsensusPayload[util.Uint256], len(m.preparationPayloads))
|
||||
|
||||
for i, resp := range m.preparationPayloads {
|
||||
r := fromPayload(prepareResponseType, p.(*Payload), &prepareResponse{
|
||||
preparationHash: *m.preparationHash,
|
||||
})
|
||||
r.SetValidatorIndex(uint16(resp.ValidatorIndex))
|
||||
r.message.ValidatorIndex = resp.ValidatorIndex
|
||||
r.Sender = validators[resp.ValidatorIndex].(*publicKey).GetScriptHash()
|
||||
r.Witness.InvocationScript = resp.InvocationScript
|
||||
r.Witness.VerificationScript = getVerificationScript(resp.ValidatorIndex, validators)
|
||||
|
@ -234,8 +233,8 @@ func (m *recoveryMessage) GetPrepareResponses(p payload.ConsensusPayload, valida
|
|||
}
|
||||
|
||||
// GetChangeViews implements the payload.RecoveryMessage interface.
|
||||
func (m *recoveryMessage) GetChangeViews(p payload.ConsensusPayload, validators []crypto.PublicKey) []payload.ConsensusPayload {
|
||||
ps := make([]payload.ConsensusPayload, len(m.changeViewPayloads))
|
||||
func (m *recoveryMessage) GetChangeViews(p dbft.ConsensusPayload[util.Uint256], validators []dbft.PublicKey) []dbft.ConsensusPayload[util.Uint256] {
|
||||
ps := make([]dbft.ConsensusPayload[util.Uint256], len(m.changeViewPayloads))
|
||||
|
||||
for i, cv := range m.changeViewPayloads {
|
||||
c := fromPayload(changeViewType, p.(*Payload), &changeView{
|
||||
|
@ -243,7 +242,7 @@ func (m *recoveryMessage) GetChangeViews(p payload.ConsensusPayload, validators
|
|||
timestamp: cv.Timestamp,
|
||||
})
|
||||
c.message.ViewNumber = cv.OriginalViewNumber
|
||||
c.SetValidatorIndex(uint16(cv.ValidatorIndex))
|
||||
c.message.ValidatorIndex = cv.ValidatorIndex
|
||||
c.Sender = validators[cv.ValidatorIndex].(*publicKey).GetScriptHash()
|
||||
c.Witness.InvocationScript = cv.InvocationScript
|
||||
c.Witness.VerificationScript = getVerificationScript(cv.ValidatorIndex, validators)
|
||||
|
@ -255,12 +254,12 @@ func (m *recoveryMessage) GetChangeViews(p payload.ConsensusPayload, validators
|
|||
}
|
||||
|
||||
// GetCommits implements the payload.RecoveryMessage interface.
|
||||
func (m *recoveryMessage) GetCommits(p payload.ConsensusPayload, validators []crypto.PublicKey) []payload.ConsensusPayload {
|
||||
ps := make([]payload.ConsensusPayload, len(m.commitPayloads))
|
||||
func (m *recoveryMessage) GetCommits(p dbft.ConsensusPayload[util.Uint256], validators []dbft.PublicKey) []dbft.ConsensusPayload[util.Uint256] {
|
||||
ps := make([]dbft.ConsensusPayload[util.Uint256], len(m.commitPayloads))
|
||||
|
||||
for i, c := range m.commitPayloads {
|
||||
cc := fromPayload(commitType, p.(*Payload), &commit{signature: c.Signature})
|
||||
cc.SetValidatorIndex(uint16(c.ValidatorIndex))
|
||||
cc.message.ValidatorIndex = c.ValidatorIndex
|
||||
cc.Sender = validators[c.ValidatorIndex].(*publicKey).GetScriptHash()
|
||||
cc.Witness.InvocationScript = c.InvocationScript
|
||||
cc.Witness.VerificationScript = getVerificationScript(c.ValidatorIndex, validators)
|
||||
|
@ -276,12 +275,7 @@ func (m *recoveryMessage) PreparationHash() *util.Uint256 {
|
|||
return m.preparationHash
|
||||
}
|
||||
|
||||
// SetPreparationHash implements the payload.RecoveryMessage interface.
|
||||
func (m *recoveryMessage) SetPreparationHash(h *util.Uint256) {
|
||||
m.preparationHash = h
|
||||
}
|
||||
|
||||
func getVerificationScript(i uint8, validators []crypto.PublicKey) []byte {
|
||||
func getVerificationScript(i uint8, validators []dbft.PublicKey) []byte {
|
||||
if int(i) >= len(validators) {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@ package consensus
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/dbft/crypto"
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/internal/testchain"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -23,7 +22,7 @@ func TestRecoveryMessageSetters(t *testing.T) {
|
|||
func testRecoveryMessageSetters(t *testing.T, enableStateRoot bool) {
|
||||
srv := newTestServiceWithState(t, enableStateRoot)
|
||||
privs := make([]*privateKey, testchain.Size())
|
||||
pubs := make([]crypto.PublicKey, testchain.Size())
|
||||
pubs := make([]dbft.PublicKey, testchain.Size())
|
||||
for i := 0; i < testchain.Size(); i++ {
|
||||
privs[i], pubs[i] = getTestValidator(i)
|
||||
}
|
||||
|
@ -32,9 +31,9 @@ func testRecoveryMessageSetters(t *testing.T, enableStateRoot bool) {
|
|||
|
||||
r := &recoveryMessage{stateRootEnabled: enableStateRoot}
|
||||
p := NewPayload(netmode.UnitTestNet, enableStateRoot)
|
||||
p.SetType(payload.RecoveryMessageType)
|
||||
p.SetHeight(msgHeight)
|
||||
p.SetPayload(r)
|
||||
p.message.Type = messageType(dbft.RecoveryMessageType)
|
||||
p.BlockIndex = msgHeight
|
||||
p.payload = r
|
||||
// sign payload to have verification script
|
||||
require.NoError(t, p.Sign(privs[0]))
|
||||
|
||||
|
@ -44,21 +43,21 @@ func testRecoveryMessageSetters(t *testing.T, enableStateRoot bool) {
|
|||
stateRootEnabled: enableStateRoot,
|
||||
}
|
||||
p1 := NewPayload(netmode.UnitTestNet, enableStateRoot)
|
||||
p1.SetType(payload.PrepareRequestType)
|
||||
p1.SetHeight(msgHeight)
|
||||
p1.SetPayload(req)
|
||||
p1.SetValidatorIndex(0)
|
||||
p1.message.Type = messageType(dbft.PrepareRequestType)
|
||||
p1.BlockIndex = msgHeight
|
||||
p1.payload = req
|
||||
p1.message.ValidatorIndex = 0
|
||||
p1.Sender = privs[0].GetScriptHash()
|
||||
require.NoError(t, p1.Sign(privs[0]))
|
||||
|
||||
t.Run("prepare response is added", func(t *testing.T) {
|
||||
p2 := NewPayload(netmode.UnitTestNet, enableStateRoot)
|
||||
p2.SetType(payload.PrepareResponseType)
|
||||
p2.SetHeight(msgHeight)
|
||||
p2.SetPayload(&prepareResponse{
|
||||
p2.message.Type = messageType(dbft.PrepareResponseType)
|
||||
p2.BlockIndex = msgHeight
|
||||
p2.payload = &prepareResponse{
|
||||
preparationHash: p1.Hash(),
|
||||
})
|
||||
p2.SetValidatorIndex(1)
|
||||
}
|
||||
p2.message.ValidatorIndex = 1
|
||||
p2.Sender = privs[1].GetScriptHash()
|
||||
require.NoError(t, p2.Sign(privs[1]))
|
||||
|
||||
|
@ -91,13 +90,13 @@ func testRecoveryMessageSetters(t *testing.T, enableStateRoot bool) {
|
|||
|
||||
t.Run("change view is added", func(t *testing.T) {
|
||||
p3 := NewPayload(netmode.UnitTestNet, enableStateRoot)
|
||||
p3.SetType(payload.ChangeViewType)
|
||||
p3.SetHeight(msgHeight)
|
||||
p3.SetPayload(&changeView{
|
||||
p3.message.Type = messageType(dbft.ChangeViewType)
|
||||
p3.BlockIndex = msgHeight
|
||||
p3.payload = &changeView{
|
||||
newViewNumber: 1,
|
||||
timestamp: 12345,
|
||||
})
|
||||
p3.SetValidatorIndex(3)
|
||||
}
|
||||
p3.message.ValidatorIndex = 3
|
||||
p3.Sender = privs[3].GetScriptHash()
|
||||
require.NoError(t, p3.Sign(privs[3]))
|
||||
|
||||
|
@ -115,10 +114,10 @@ func testRecoveryMessageSetters(t *testing.T, enableStateRoot bool) {
|
|||
|
||||
t.Run("commit is added", func(t *testing.T) {
|
||||
p4 := NewPayload(netmode.UnitTestNet, enableStateRoot)
|
||||
p4.SetType(payload.CommitType)
|
||||
p4.SetHeight(msgHeight)
|
||||
p4.SetPayload(randomMessage(t, commitType))
|
||||
p4.SetValidatorIndex(3)
|
||||
p4.message.Type = messageType(dbft.CommitType)
|
||||
p4.BlockIndex = msgHeight
|
||||
p4.payload = randomMessage(t, commitType)
|
||||
p4.message.ValidatorIndex = 3
|
||||
p4.Sender = privs[3].GetScriptHash()
|
||||
require.NoError(t, p4.Sign(privs[3]))
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package consensus
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/dbft"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
)
|
||||
|
||||
|
@ -10,7 +10,7 @@ type recoveryRequest struct {
|
|||
timestamp uint64
|
||||
}
|
||||
|
||||
var _ payload.RecoveryRequest = (*recoveryRequest)(nil)
|
||||
var _ dbft.RecoveryRequest = (*recoveryRequest)(nil)
|
||||
|
||||
// DecodeBinary implements the io.Serializable interface.
|
||||
func (m *recoveryRequest) DecodeBinary(r *io.BinReader) {
|
||||
|
@ -24,6 +24,3 @@ func (m *recoveryRequest) EncodeBinary(w *io.BinWriter) {
|
|||
|
||||
// Timestamp implements the payload.RecoveryRequest interface.
|
||||
func (m *recoveryRequest) Timestamp() uint64 { return m.timestamp * nsInMs }
|
||||
|
||||
// SetTimestamp implements the payload.RecoveryRequest interface.
|
||||
func (m *recoveryRequest) SetTimestamp(ts uint64) { m.timestamp = ts / nsInMs }
|
||||
|
|
|
@ -6,9 +6,10 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRecoveryRequest_Setters(t *testing.T) {
|
||||
var r recoveryRequest
|
||||
func TestRecoveryRequest_Getters(t *testing.T) {
|
||||
var r = &recoveryRequest{
|
||||
timestamp: 123,
|
||||
}
|
||||
|
||||
r.SetTimestamp(123 * nsInMs)
|
||||
require.EqualValues(t, 123*nsInMs, r.Timestamp())
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// VersionInitial is the default Neo block version.
|
||||
const VersionInitial uint32 = 0
|
||||
|
||||
// Header holds the base info of a block.
|
||||
type Header struct {
|
||||
// Version of the block.
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"sync/atomic"
|
||||
"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/limits"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
|
@ -44,7 +45,7 @@ import (
|
|||
|
||||
// Tuning parameters.
|
||||
const (
|
||||
version = "0.2.10"
|
||||
version = "0.2.12"
|
||||
|
||||
// DefaultInitialGAS is the default amount of GAS emitted to the standby validators
|
||||
// multisignature account during native GAS contract initialization.
|
||||
|
@ -288,7 +289,7 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
|
|||
cfg.Hardforks[hf.String()] = 0
|
||||
}
|
||||
log.Info("Hardforks are not set, using default value")
|
||||
} else {
|
||||
} else if len(cfg.Hardforks) != 0 {
|
||||
// Explicitly set the height of all old omitted hardforks to 0 for proper
|
||||
// IsHardforkEnabled behaviour.
|
||||
for _, hf := range config.Hardforks {
|
||||
|
@ -341,16 +342,36 @@ func (bc *Blockchain) GetDesignatedByRole(r noderoles.Role) (keys.PublicKeys, ui
|
|||
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.
|
||||
// To unregister Oracle service use SetOracle(nil).
|
||||
func (bc *Blockchain) SetOracle(mod native.OracleService) {
|
||||
orc := bc.contracts.Oracle
|
||||
currentHF := bc.getCurrentHF()
|
||||
if mod != nil {
|
||||
md, ok := orc.GetMethod(manifest.MethodVerify, -1)
|
||||
orcMd := orc.HFSpecificContractMD(¤tHF)
|
||||
md, ok := orcMd.GetMethod(manifest.MethodVerify, -1)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("%s method not found", manifest.MethodVerify))
|
||||
}
|
||||
mod.UpdateNativeContract(orc.NEF.Script, orc.GetOracleResponseScript(),
|
||||
mod.UpdateNativeContract(orcMd.NEF.Script, orc.GetOracleResponseScript(),
|
||||
orc.Hash, md.MD.Offset)
|
||||
keys, _, err := bc.GetDesignatedByRole(noderoles.Oracle)
|
||||
if err != nil {
|
||||
|
@ -487,6 +508,7 @@ func (bc *Blockchain) init() error {
|
|||
// 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
|
||||
// contract state from DAO via high-level bc API.
|
||||
var current = bc.getCurrentHF()
|
||||
for _, c := range bc.contracts.Contracts {
|
||||
md := c.Metadata()
|
||||
storedCS := bc.GetContractState(md.Hash)
|
||||
|
@ -504,8 +526,9 @@ func (bc *Blockchain) init() error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to check native %s state against autogenerated one: %w", md.Name, err)
|
||||
}
|
||||
hfMD := md.HFSpecificContractMD(¤t)
|
||||
autogenCS := &state.Contract{
|
||||
ContractBase: md.ContractBase,
|
||||
ContractBase: hfMD.ContractBase,
|
||||
UpdateCounter: storedCS.UpdateCounter, // it can be restored only from the DB, so use the stored value.
|
||||
}
|
||||
autogenCSBytes, err := stackitem.SerializeConvertible(autogenCS)
|
||||
|
@ -513,8 +536,10 @@ func (bc *Blockchain) init() error {
|
|||
return fmt.Errorf("failed to check native %s state against autogenerated one: %w", md.Name, err)
|
||||
}
|
||||
if !bytes.Equal(storedCSBytes, autogenCSBytes) {
|
||||
return fmt.Errorf("native %s: version mismatch (stored contract state differs from autogenerated one), "+
|
||||
"try to resynchronize the node from the genesis", md.Name)
|
||||
storedJ, _ := json.Marshal(storedCS)
|
||||
autogenJ, _ := json.Marshal(autogenCS)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1490,8 +1515,11 @@ func (bc *Blockchain) AddBlock(block *block.Block) error {
|
|||
} else {
|
||||
err = bc.verifyAndPoolTx(tx, mp, bc)
|
||||
}
|
||||
if err != nil && bc.config.VerifyTransactions {
|
||||
return fmt.Errorf("transaction %s failed to verify: %w", tx.Hash().StringLE(), err)
|
||||
if err != nil {
|
||||
if bc.config.VerifyTransactions {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2267,10 +2295,19 @@ func (bc *Blockchain) GetNativeContractScriptHash(name string) (util.Uint160, er
|
|||
}
|
||||
|
||||
// GetNatives returns list of native contracts.
|
||||
func (bc *Blockchain) GetNatives() []state.NativeContract {
|
||||
res := make([]state.NativeContract, 0, len(bc.contracts.Contracts))
|
||||
func (bc *Blockchain) GetNatives() []state.Contract {
|
||||
res := make([]state.Contract, 0, len(bc.contracts.Contracts))
|
||||
current := bc.getCurrentHF()
|
||||
for _, c := range bc.contracts.Contracts {
|
||||
res = append(res, c.Metadata().NativeContract)
|
||||
activeIn := c.ActiveIn()
|
||||
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
|
||||
}
|
||||
|
@ -2891,7 +2928,7 @@ func (bc *Blockchain) InitVerificationContext(ic *interop.Context, hash util.Uin
|
|||
initOffset = md.Offset
|
||||
}
|
||||
ic.Invocations[cs.Hash]++
|
||||
ic.VM.LoadNEFMethod(&cs.NEF, util.Uint160{}, hash, callflag.ReadOnly,
|
||||
ic.VM.LoadNEFMethod(&cs.NEF, &cs.Manifest, util.Uint160{}, hash, callflag.ReadOnly,
|
||||
true, verifyOffset, initOffset, nil)
|
||||
}
|
||||
if len(witness.InvocationScript) != 0 {
|
||||
|
@ -2980,12 +3017,7 @@ func (bc *Blockchain) verifyTxWitnesses(t *transaction.Transaction, block *block
|
|||
|
||||
// verifyHeaderWitnesses is a block-specific implementation of VerifyWitnesses logic.
|
||||
func (bc *Blockchain) verifyHeaderWitnesses(currHeader, prevHeader *block.Header) error {
|
||||
var hash util.Uint160
|
||||
if prevHeader == nil && currHeader.PrevHash.Equals(util.Uint256{}) {
|
||||
hash = currHeader.Script.ScriptHash()
|
||||
} else {
|
||||
hash = prevHeader.NextConsensus
|
||||
}
|
||||
hash := prevHeader.NextConsensus
|
||||
_, err := bc.VerifyWitness(hash, currHeader, &currHeader.Script, HeaderVerificationGasLimit)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -361,16 +361,24 @@ func TestBlockchain_IsRunning(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNewBlockchain_InitHardforks(t *testing.T) {
|
||||
t.Run("empty set", func(t *testing.T) {
|
||||
t.Run("nil set", func(t *testing.T) {
|
||||
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
|
||||
c.ProtocolConfiguration.Hardforks = map[string]uint32{}
|
||||
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) {
|
||||
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
|
||||
c.ProtocolConfiguration.Hardforks = map[string]uint32{}
|
||||
require.NoError(t, c.ProtocolConfiguration.Validate())
|
||||
})
|
||||
require.Equal(t, map[string]uint32{}, bc.GetConfig().Hardforks)
|
||||
})
|
||||
t.Run("missing old", func(t *testing.T) {
|
||||
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
|
||||
c.ProtocolConfiguration.Hardforks = map[string]uint32{config.HFBasilisk.String(): 5}
|
||||
|
@ -392,12 +400,13 @@ func TestNewBlockchain_InitHardforks(t *testing.T) {
|
|||
})
|
||||
t.Run("all present", func(t *testing.T) {
|
||||
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
|
||||
c.ProtocolConfiguration.Hardforks = map[string]uint32{config.HFAspidochelone.String(): 5, config.HFBasilisk.String(): 10}
|
||||
c.ProtocolConfiguration.Hardforks = map[string]uint32{config.HFAspidochelone.String(): 5, config.HFBasilisk.String(): 10, config.HFCockatrice.String(): 15}
|
||||
require.NoError(t, c.ProtocolConfiguration.Validate())
|
||||
})
|
||||
require.Equal(t, map[string]uint32{
|
||||
config.HFAspidochelone.String(): 5,
|
||||
config.HFBasilisk.String(): 10,
|
||||
config.HFCockatrice.String(): 15,
|
||||
}, bc.GetConfig().Hardforks)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -24,6 +25,7 @@ import (
|
|||
"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/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/nativeprices"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
||||
|
@ -269,7 +271,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
|
|||
|
||||
_, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
|
||||
require.Error(t, err)
|
||||
require.True(t, strings.Contains(err.Error(), fmt.Sprintf("native %s: version mismatch (stored contract state differs from autogenerated one)", nativenames.CryptoLib)), 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)
|
||||
})
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
|
@ -315,6 +317,92 @@ 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
|
||||
// Notary cache initialization is performed before that height on node restart.
|
||||
/*
|
||||
|
@ -2460,7 +2548,7 @@ func TestBlockchain_GenesisTransactionExtension(t *testing.T) {
|
|||
emit.Syscall(script.BinWriter, interopnames.SystemRuntimeCheckWitness)
|
||||
emit.Bytes(script.BinWriter, to.BytesBE())
|
||||
emit.Syscall(script.BinWriter, interopnames.SystemRuntimeCheckWitness)
|
||||
emit.AppCall(script.BinWriter, state.CreateNativeContractHash(nativenames.Neo), "transfer", callflag.All, from, to, amount, nil)
|
||||
emit.AppCall(script.BinWriter, nativehashes.NeoToken, "transfer", callflag.All, from, to, amount, nil)
|
||||
emit.Opcodes(script.BinWriter, opcode.ASSERT)
|
||||
|
||||
var sysFee int64 = 1_0000_0000
|
||||
|
@ -2479,3 +2567,56 @@ func TestBlockchain_GenesisTransactionExtension(t *testing.T) {
|
|||
require.Equal(t, int64(amount), actualNeo.Int64())
|
||||
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))
|
||||
}
|
||||
|
|
|
@ -35,6 +35,11 @@ var (
|
|||
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.
|
||||
type Simple struct {
|
||||
Version Version
|
||||
|
@ -323,7 +328,7 @@ func (dao *Simple) GetTxExecResult(hash util.Uint256) (uint32, *transaction.Tran
|
|||
// decodeTxAndExecResult decodes transaction, its height and execution result from
|
||||
// the given executable bytes. It performs no executable prefix check.
|
||||
func decodeTxAndExecResult(buf []byte) (uint32, *transaction.Transaction, *state.AppExecResult, error) {
|
||||
if len(buf) >= 6 && buf[5] == transaction.DummyVersion {
|
||||
if len(buf) == conflictRecordValueLen { // conflict record stub.
|
||||
return 0, nil, nil, storage.ErrKeyNotFound
|
||||
}
|
||||
r := io.NewBinReaderFromBuf(buf)
|
||||
|
@ -605,7 +610,7 @@ func (dao *Simple) DeleteHeaderHashes(since uint32, batchSize int) {
|
|||
}
|
||||
|
||||
// GetTransaction returns Transaction and its height by the given hash
|
||||
// if it exists in the store. It does not return dummy transactions.
|
||||
// if it exists in the store. It does not return conflict record stubs.
|
||||
func (dao *Simple) GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error) {
|
||||
key := dao.makeExecutableKey(hash)
|
||||
b, err := dao.Store.Get(key)
|
||||
|
@ -619,7 +624,7 @@ func (dao *Simple) GetTransaction(hash util.Uint256) (*transaction.Transaction,
|
|||
// It may be a block.
|
||||
return nil, 0, storage.ErrKeyNotFound
|
||||
}
|
||||
if len(b) == 1+4 { // storage.ExecTransaction + index
|
||||
if len(b) == conflictRecordValueLen {
|
||||
// It's a conflict record stub.
|
||||
return nil, 0, storage.ErrKeyNotFound
|
||||
}
|
||||
|
@ -699,10 +704,16 @@ func (dao *Simple) HasTransaction(hash util.Uint256, signers []transaction.Signe
|
|||
return nil
|
||||
}
|
||||
|
||||
if len(bytes) < 5 { // (storage.ExecTransaction + index) for conflict record
|
||||
if len(bytes) < conflictRecordValueLen { // (storage.ExecTransaction + index) for conflict record
|
||||
return nil
|
||||
}
|
||||
if len(bytes) != 5 {
|
||||
if bytes[0] != storage.ExecTransaction {
|
||||
// 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
|
||||
}
|
||||
if len(signers) == 0 {
|
||||
|
@ -778,6 +789,10 @@ func (dao *Simple) DeleteBlock(h util.Uint256) error {
|
|||
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)
|
||||
}
|
||||
// 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:])
|
||||
// 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
|
||||
|
@ -838,8 +853,9 @@ func (dao *Simple) StoreAsCurrentBlock(block *block.Block) {
|
|||
dao.Store.Put(dao.mkKeyPrefix(storage.SYSCurrentBlock), buf.Bytes())
|
||||
}
|
||||
|
||||
// StoreAsTransaction stores the given TX as DataTransaction. It also stores transactions
|
||||
// the given tx has conflicts with as DataTransaction with dummy version. It can reuse the given
|
||||
// StoreAsTransaction stores the given TX as DataTransaction. It also stores conflict records
|
||||
// (hashes of transactions the given tx has conflicts with) as DataTransaction with value containing
|
||||
// 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.
|
||||
func (dao *Simple) StoreAsTransaction(tx *transaction.Transaction, index uint32, aer *state.AppExecResult) error {
|
||||
key := dao.makeExecutableKey(tx.Hash())
|
||||
|
@ -857,12 +873,23 @@ func (dao *Simple) StoreAsTransaction(tx *transaction.Transaction, index uint32,
|
|||
val := buf.Bytes()
|
||||
dao.Store.Put(key, val)
|
||||
|
||||
val = val[:5] // storage.ExecTransaction (1 byte) + index (4 bytes)
|
||||
val = val[:conflictRecordValueLen] // storage.ExecTransaction (1 byte) + index (4 bytes)
|
||||
attrs := tx.GetAttributes(transaction.ConflictsT)
|
||||
for _, attr := range attrs {
|
||||
// Conflict record stub.
|
||||
hash := attr.Value.(*transaction.Conflicts).Hash
|
||||
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)
|
||||
|
||||
// Conflicting signers.
|
||||
|
|
|
@ -242,6 +242,53 @@ func TestStoreAsTransaction(t *testing.T) {
|
|||
}
|
||||
err = dao.StoreAsTransaction(tx2, blockIndex, aer2)
|
||||
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)
|
||||
require.ErrorIs(t, err, ErrAlreadyExists)
|
||||
err = dao.HasTransaction(hash2, nil, 0, 0)
|
||||
|
@ -280,6 +327,29 @@ func TestStoreAsTransaction(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(gotAppExecResult))
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -140,8 +140,15 @@ type Function struct {
|
|||
// Method is a signature for a native method.
|
||||
type Method = func(ic *Context, args []stackitem.Item) stackitem.Item
|
||||
|
||||
// MethodAndPrice is a native-contract method descriptor.
|
||||
// MethodAndPrice is a generic hardfork-independent native contract method descriptor.
|
||||
type MethodAndPrice struct {
|
||||
HFSpecificMethodAndPrice
|
||||
ActiveFrom *config.Hardfork
|
||||
ActiveTill *config.Hardfork
|
||||
}
|
||||
|
||||
// HFSpecificMethodAndPrice is a hardfork-specific native contract method descriptor.
|
||||
type HFSpecificMethodAndPrice struct {
|
||||
Func Method
|
||||
MD *manifest.Method
|
||||
CPUFee int64
|
||||
|
@ -150,10 +157,24 @@ type MethodAndPrice struct {
|
|||
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.
|
||||
type Contract interface {
|
||||
Initialize(*Context) error
|
||||
// ActiveIn returns the hardfork native contract is active from or nil in case
|
||||
// Initialize performs native contract initialization on contract deploy or update.
|
||||
// Active hardfork is passed as the second argument.
|
||||
Initialize(*Context, *config.Hardfork, *HFSpecificContractMD) error
|
||||
// ActiveIn returns the hardfork native contract is active starting from or nil in case
|
||||
// it's always active.
|
||||
ActiveIn() *config.Hardfork
|
||||
// InitializeCache aimed to initialize contract's cache when the contract has
|
||||
|
@ -161,53 +182,176 @@ type Contract interface {
|
|||
// It should be called each time after node restart iff the contract was
|
||||
// deployed and no Initialize method was called.
|
||||
InitializeCache(blockHeight uint32, d *dao.Simple) error
|
||||
// Metadata returns generic native contract metadata.
|
||||
Metadata() *ContractMD
|
||||
OnPersist(*Context) error
|
||||
PostPersist(*Context) error
|
||||
}
|
||||
|
||||
// ContractMD represents a native contract instance.
|
||||
// ContractMD represents a generic hardfork-independent native contract instance.
|
||||
type ContractMD struct {
|
||||
state.NativeContract
|
||||
Name string
|
||||
Methods []MethodAndPrice
|
||||
ID int32
|
||||
Hash util.Uint160
|
||||
Name string
|
||||
// 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)
|
||||
}
|
||||
|
||||
// NewContractMD returns Contract with the specified list of methods.
|
||||
func NewContractMD(name string, id int32) *ContractMD {
|
||||
// HFSpecificContractMD is a hardfork-specific native contract descriptor.
|
||||
type HFSpecificContractMD struct {
|
||||
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}
|
||||
if len(onManifestConstruction) != 0 {
|
||||
c.onManifestConstruction = onManifestConstruction[0]
|
||||
}
|
||||
|
||||
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.Manifest = *manifest.DefaultManifest(name)
|
||||
c.ActiveHFs = make(map[config.Hardfork]struct{})
|
||||
c.mdCache = make(map[config.Hardfork]*HFSpecificContractMD)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// UpdateHash creates a native contract script and updates hash.
|
||||
func (c *ContractMD) UpdateHash() {
|
||||
// HFSpecificContractMD returns hardfork-specific native contract metadata, i.e. with methods, events and script
|
||||
// corresponding to the specified hardfork. If hardfork is not specified, then default metadata will be returned
|
||||
// (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()
|
||||
for i := range c.Methods {
|
||||
offset := w.Len()
|
||||
c.Methods[i].MD.Offset = offset
|
||||
c.Manifest.ABI.Methods[i].Offset = offset
|
||||
for i := range c.methods {
|
||||
m := c.methods[i]
|
||||
if !(m.ActiveFrom == nil || (hf != config.HFDefault && (*m.ActiveFrom).Cmp(hf) >= 0)) ||
|
||||
(m.ActiveTill != nil && (*m.ActiveTill).Cmp(hf) <= 0) {
|
||||
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)
|
||||
c.Methods[i].SyscallOffset = w.Len()
|
||||
m.SyscallOffset = w.Len()
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemContractCallNative)
|
||||
emit.Opcodes(w.BinWriter, opcode.RET)
|
||||
|
||||
abiMethods = append(abiMethods, *m.MD)
|
||||
methods = append(methods, m.HFSpecificMethodAndPrice)
|
||||
}
|
||||
if w.Err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
c.NEF.Script = w.Bytes()
|
||||
c.NEF.Checksum = c.NEF.CalculateChecksum()
|
||||
abiEvents = append(abiEvents, *e.MD)
|
||||
events = append(events, e.HFSpecificEvent)
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -215,36 +359,38 @@ func (c *ContractMD) AddMethod(md *MethodAndPrice, desc *manifest.Method) {
|
|||
md.MD = desc
|
||||
desc.Safe = md.RequiredFlags&(callflag.All^callflag.ReadOnly) == 0
|
||||
|
||||
index := sort.Search(len(c.Manifest.ABI.Methods), func(i int) bool {
|
||||
md := c.Manifest.ABI.Methods[i]
|
||||
index := sort.Search(len(c.methods), func(i int) bool {
|
||||
md := c.methods[i].MD
|
||||
if md.Name != desc.Name {
|
||||
return md.Name >= desc.Name
|
||||
}
|
||||
return len(md.Parameters) > len(desc.Parameters)
|
||||
})
|
||||
c.Manifest.ABI.Methods = append(c.Manifest.ABI.Methods, manifest.Method{})
|
||||
copy(c.Manifest.ABI.Methods[index+1:], c.Manifest.ABI.Methods[index:])
|
||||
c.Manifest.ABI.Methods[index] = *desc
|
||||
c.methods = append(c.methods, MethodAndPrice{})
|
||||
copy(c.methods[index+1:], c.methods[index:])
|
||||
c.methods[index] = *md
|
||||
|
||||
// Cache follows the same order.
|
||||
c.Methods = append(c.Methods, MethodAndPrice{})
|
||||
copy(c.Methods[index+1:], c.Methods[index:])
|
||||
c.Methods[index] = *md
|
||||
if md.ActiveFrom != nil {
|
||||
c.ActiveHFs[*md.ActiveFrom] = struct{}{}
|
||||
}
|
||||
if md.ActiveTill != nil {
|
||||
c.ActiveHFs[*md.ActiveTill] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// GetMethodByOffset returns method with the provided offset.
|
||||
// Offset is offset of `System.Contract.CallNative` syscall.
|
||||
func (c *ContractMD) GetMethodByOffset(offset int) (MethodAndPrice, bool) {
|
||||
func (c *HFSpecificContractMD) GetMethodByOffset(offset int) (HFSpecificMethodAndPrice, bool) {
|
||||
for k := range c.Methods {
|
||||
if c.Methods[k].SyscallOffset == offset {
|
||||
return c.Methods[k], true
|
||||
}
|
||||
}
|
||||
return MethodAndPrice{}, false
|
||||
return HFSpecificMethodAndPrice{}, false
|
||||
}
|
||||
|
||||
// GetMethod returns method `name` with the specified number of parameters.
|
||||
func (c *ContractMD) GetMethod(name string, paramCount int) (MethodAndPrice, bool) {
|
||||
func (c *HFSpecificContractMD) GetMethod(name string, paramCount int) (HFSpecificMethodAndPrice, bool) {
|
||||
index := sort.Search(len(c.Methods), func(i int) bool {
|
||||
md := c.Methods[i]
|
||||
res := strings.Compare(name, md.MD.Name)
|
||||
|
@ -261,15 +407,19 @@ func (c *ContractMD) GetMethod(name string, paramCount int) (MethodAndPrice, boo
|
|||
return md, true
|
||||
}
|
||||
}
|
||||
return MethodAndPrice{}, false
|
||||
return HFSpecificMethodAndPrice{}, false
|
||||
}
|
||||
|
||||
// AddEvent adds a new event to the native contract.
|
||||
func (c *ContractMD) AddEvent(name string, ps ...manifest.Parameter) {
|
||||
c.Manifest.ABI.Events = append(c.Manifest.ABI.Events, manifest.Event{
|
||||
Name: name,
|
||||
Parameters: ps,
|
||||
})
|
||||
func (c *ContractMD) AddEvent(md Event) {
|
||||
c.events = append(c.events, md)
|
||||
|
||||
if md.ActiveFrom != nil {
|
||||
c.ActiveHFs[*md.ActiveFrom] = struct{}{}
|
||||
}
|
||||
if md.ActiveTill != nil {
|
||||
c.ActiveHFs[*md.ActiveTill] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort sorts interop functions by id.
|
||||
|
|
|
@ -144,7 +144,7 @@ func callExFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contra
|
|||
}
|
||||
return nil
|
||||
}
|
||||
ic.VM.LoadNEFMethod(&cs.NEF, caller, cs.Hash, f,
|
||||
ic.VM.LoadNEFMethod(&cs.NEF, &cs.Manifest, caller, cs.Hash, f,
|
||||
hasReturn, methodOff, initOff, onUnload)
|
||||
|
||||
for e, i := ic.VM.Estack(), len(args)-1; i >= 0; i-- {
|
||||
|
|
|
@ -18,14 +18,14 @@ import (
|
|||
func ECDSASecp256r1CheckMultisig(ic *interop.Context) error {
|
||||
pkeys, err := ic.VM.Estack().PopSigElements()
|
||||
if err != nil {
|
||||
return fmt.Errorf("wrong parameters: %w", err)
|
||||
return fmt.Errorf("wrong key parameters: %w", err)
|
||||
}
|
||||
if !ic.VM.AddGas(ic.BaseExecFee() * fee.ECDSAVerifyPrice * int64(len(pkeys))) {
|
||||
return errors.New("gas limit exceeded")
|
||||
}
|
||||
sigs, err := ic.VM.Estack().PopSigElements()
|
||||
if err != nil {
|
||||
return fmt.Errorf("wrong parameters: %w", err)
|
||||
return fmt.Errorf("wrong signature parameters: %w", err)
|
||||
}
|
||||
// It's ok to have more keys than there are signatures (it would
|
||||
// just mean that some keys didn't sign), but not the other way around.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue