mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-03-14 13:28:39 +00:00
Compare commits
103 commits
Author | SHA1 | Date | |
---|---|---|---|
|
24a6d842b5 | ||
|
ee56f73606 | ||
|
210059fff8 | ||
|
4a510637be | ||
|
2fd51cf6b1 | ||
|
7d72b6538a | ||
|
70b4d005e3 | ||
|
2881961421 | ||
|
5f80a142b0 | ||
|
d411337648 | ||
|
2c8bd056fa | ||
|
9c0274850a | ||
|
94660f6333 | ||
|
c3916ef2c3 | ||
|
22a5bbcef3 | ||
|
e63cbe7c82 | ||
|
13b75c9d1a | ||
|
3ec14d2e8f | ||
|
e9f496a19f | ||
|
68d7e8e01c | ||
|
a227572d01 | ||
|
64e3b6aa48 | ||
|
a7c66dcb0b | ||
|
ff8ea5d4e8 | ||
|
0d8c751e50 | ||
|
d0e47c739a | ||
|
3b54213c08 | ||
|
d7232357d4 | ||
|
e05863d13b | ||
|
75d12081bf | ||
|
62972ebc14 | ||
|
406e8cd840 | ||
|
30b3318503 | ||
|
a1db45d668 | ||
|
25e2d80363 | ||
|
93be186685 | ||
|
d1926e4fb0 | ||
|
cb4aba497e | ||
|
bd170fb849 | ||
|
8d728b4ec1 | ||
|
1ad62ef5f5 | ||
|
91b60ea7d3 | ||
|
3fa02d062b | ||
|
de50d0be49 | ||
|
e70b1063a6 | ||
|
72e0cff82b | ||
|
267d7dca78 | ||
|
83a02fc0c0 | ||
|
847479e6a1 | ||
|
d02e2b629d | ||
|
6969982f77 | ||
|
f09a04d705 | ||
|
5d0cd53d67 | ||
|
e704731f2f | ||
|
50cb21333e | ||
|
8ba2bbf87c | ||
|
7ba8048530 | ||
|
22c5cf3537 | ||
|
4b2ee9a424 | ||
|
00e22b9751 | ||
|
4da753f822 | ||
|
673b26fdb1 | ||
|
3b28749fd1 | ||
|
257fa7c6c9 | ||
|
b2322a804a | ||
|
fcd83e9fd7 | ||
|
16a6a59c43 | ||
|
c047bad446 | ||
|
9513780c45 | ||
|
c07c74df41 | ||
|
c14492e8c8 | ||
|
70aaeb06ad | ||
|
ba0ca6a4ab | ||
|
1f83f472c7 | ||
|
4d2b88dd9d | ||
|
82b400700f | ||
|
4720727bf5 | ||
|
47b679341b | ||
|
e0338b7ed0 | ||
|
64c4de4e38 | ||
|
38b9b13098 | ||
|
4d45be8434 | ||
|
ab5128fb48 | ||
|
dc747ce3b7 | ||
|
663146aa1f | ||
|
86b2493edd | ||
|
80e18222bc | ||
|
b096e68428 | ||
|
dc68e39811 | ||
|
992890721a | ||
|
cffafc4e79 | ||
|
0b21d4caf6 | ||
|
6d20772714 | ||
|
b86c6201d3 | ||
|
c669ae343b | ||
|
c27101a97c | ||
|
4b7b2ef701 | ||
|
0bb6c6e6bd | ||
|
6d509896fb | ||
|
24f81a7f3e | ||
|
f5ea79d649 | ||
|
e741053f0c | ||
|
b285cf8c6e |
140 changed files with 6632 additions and 710 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -1,4 +1,4 @@
|
|||
[submodule "pkg/vm/testdata/neo-vm"]
|
||||
path = pkg/vm/testdata/neo-vm
|
||||
url = https://github.com/neo-project/neo-vm.git
|
||||
url = https://github.com/neo-project/neo.git
|
||||
branch = master
|
||||
|
|
60
CHANGELOG.md
60
CHANGELOG.md
|
@ -2,6 +2,66 @@
|
|||
|
||||
This document outlines major changes between releases.
|
||||
|
||||
## 0.108.1 "Revalidation" (13 Feb 2025)
|
||||
|
||||
An urgent fix for a very old behavior difference with C# node in Rules witness
|
||||
condition parsing. It suddenly affected testnet compatibility at block 5450030
|
||||
and made the chain unprocessable by NeoGo. Please upgrade to fix it, DB is
|
||||
compatible, no resynchronization required.
|
||||
|
||||
Bugs fixed:
|
||||
* incorrect rule depth limit for Rules witness conditions (#3810)
|
||||
|
||||
## 0.108.0 "Participation" (11 Feb 2025)
|
||||
|
||||
This version is compatible with the C# node 3.7.6, but also contains some
|
||||
Echidna changes preview. Additional RPC extensions are introduced with this
|
||||
release as well as some important fixes and improvements.
|
||||
|
||||
We recommend to check your configurations wrt NeoFS synchronization options,
|
||||
a new set of containers was introduced recently, old ones will eventually be
|
||||
deleted (which won't break syncrhonization, but can delay it a bit). No DB
|
||||
resync is required unless you want to use the new "SaveInvocations" option.
|
||||
|
||||
New features:
|
||||
* "Designation" event in RoleManagement native contract starting from Echidna
|
||||
HF (#3761)
|
||||
* base64Url encoding and decoding support in StdLib native contract starting
|
||||
from Echidna HF (#3761)
|
||||
* NEO candidate registration via NEP-27 payment starting from Echidna HF (#3700)
|
||||
* ArchivalNode P2P capability (#3778)
|
||||
* NEP-26 and NEP-27 support everywhere (#3792)
|
||||
* "SaveInvocations" node parameter that allows to store more detailed
|
||||
contract invocation data and retrieve it via RPC (#3569)
|
||||
* "getblocknotifications" RPC API allowing to fetch filtered notifications
|
||||
from all block execution contexts (#3805)
|
||||
|
||||
Behavior changes:
|
||||
* updated "upload-bin" command defaults (#3760)
|
||||
* updated NeoFS containers for all networks (#3759)
|
||||
* additional AllowNotify call flag for some NEO methods starting from Echidna
|
||||
HF (#3761)
|
||||
* Dump*Slot methods removed from vm.Context (#3806)
|
||||
|
||||
Improvements:
|
||||
* golang.org/x/crypto update from 0.26.0 to 0.31.0 (#3765)
|
||||
* neotest can load contracts from NEF/manifest files now (#3771)
|
||||
* more accurate memory management in persisting/processing cycles preventing
|
||||
OOM conditions in most cases (#3787)
|
||||
* RPC bindings now have ToStackItem and ToSCParameter methods for structures
|
||||
(#3794, #3796, #3804)
|
||||
* dBFT 0.3.2 with improved timers (#3799)
|
||||
* github.com/consensys/gnark update from 0.11.0 to 0.12.0 (#3800)
|
||||
* ability to fetch headers from NeoFS (#3789)
|
||||
|
||||
Bugs fixed:
|
||||
* potentially incorrect handling of misconfigured NeoFS endpoints (#3758)
|
||||
* duplicate index objects are no longer an error for "upload-bin" (#3763)
|
||||
* old transfer data removal problem in RemoveUntraceableBlocks configuration,
|
||||
0.107.2 regression (#3787)
|
||||
* zkpbinding module producing code that can't be compiled, 0.107.0 regression
|
||||
(#3802)
|
||||
|
||||
## 0.107.2 "Obliteration" (13 Dec 2024)
|
||||
|
||||
One more compatible patch-release that introduces `RemoveUntraceableHeaders`
|
||||
|
|
13
ROADMAP.md
13
ROADMAP.md
|
@ -7,10 +7,10 @@ functionality.
|
|||
## Versions 0.7X.Y (as needed)
|
||||
* Neo 2.0 support (bug fixes, minor functionality additions)
|
||||
|
||||
## Version 0.108.0 (~Jan-Feb 2025)
|
||||
## Version 0.109.0 (~April 2025)
|
||||
* protocol updates
|
||||
* bug fixes
|
||||
* node resynchronisation from local DB
|
||||
* NeoFS-based synchronization
|
||||
|
||||
## Version 1.0 (2024, TBD)
|
||||
* stable version
|
||||
|
@ -24,12 +24,3 @@ APIs/commands/configurations will be removed and here is a list of scheduled
|
|||
breaking changes. Consider changing your code/scripts/configurations if you're
|
||||
using anything mentioned here.
|
||||
|
||||
## Dump*Slot() methods of `vm.Context`
|
||||
|
||||
The following new methods have been exposed to give access to VM context slot contents
|
||||
with greater flexibility:
|
||||
- `ArgumentsSlot`
|
||||
- `LocalsSlot`
|
||||
- `StaticsSlot`.
|
||||
|
||||
Removal of the `Dump*Slot()` methods are scheduled for the 0.108.0 release.
|
||||
|
|
|
@ -25,8 +25,11 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||
"github.com/nspcc-dev/neo-go/pkg/services/helpers/neofs"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
@ -43,9 +46,13 @@ const (
|
|||
DefaultAwaitableTimeout = 3 * 15 * time.Second
|
||||
)
|
||||
|
||||
// RPCEndpointFlag is a long flag name for an RPC endpoint. It can be used to
|
||||
// check for flag presence in the context.
|
||||
const RPCEndpointFlag = "rpc-endpoint"
|
||||
const (
|
||||
// RPCEndpointFlag is a long flag name for an RPC endpoint. It can be used to
|
||||
// check for flag presence in the context.
|
||||
RPCEndpointFlag = "rpc-endpoint"
|
||||
// NeoFSRPCEndpointFlag is a long flag name for a NeoFS RPC endpoint.
|
||||
NeoFSRPCEndpointFlag = "fs-rpc-endpoint"
|
||||
)
|
||||
|
||||
// Wallet is a set of flags used for wallet operations.
|
||||
var Wallet = []cli.Flag{
|
||||
|
@ -101,6 +108,22 @@ var RPC = []cli.Flag{
|
|||
},
|
||||
}
|
||||
|
||||
// NeoFSRPC is a set of flags used for NeoFS RPC connections (endpoint).
|
||||
var NeoFSRPC = []cli.Flag{&cli.StringSliceFlag{
|
||||
Name: NeoFSRPCEndpointFlag,
|
||||
Aliases: []string{"fsr"},
|
||||
Usage: "List of NeoFS storage node RPC addresses (comma-separated or multiple --fs-rpc-endpoint flags)",
|
||||
Required: true,
|
||||
Action: func(ctx *cli.Context, fsRpcEndpoints []string) error {
|
||||
for _, endpoint := range fsRpcEndpoints {
|
||||
if endpoint == "" {
|
||||
return cli.Exit("NeoFS RPC endpoint cannot contain empty values", 1)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}}
|
||||
|
||||
// Historic is a flag for commands that can perform historic invocations.
|
||||
var Historic = &cli.StringFlag{
|
||||
Name: "historic",
|
||||
|
@ -180,6 +203,26 @@ func GetRPCClient(gctx context.Context, ctx *cli.Context) (*rpcclient.Client, cl
|
|||
return c, nil
|
||||
}
|
||||
|
||||
// GetNeoFSClientPool returns a NeoFS pool and a signer for the given Context.
|
||||
func GetNeoFSClientPool(ctx *cli.Context, acc *wallet.Account) (user.Signer, neofs.PoolWrapper, error) {
|
||||
rpcNeoFS := ctx.StringSlice(NeoFSRPCEndpointFlag)
|
||||
signer := user.NewAutoIDSignerRFC6979(acc.PrivateKey().PrivateKey)
|
||||
|
||||
params := pool.DefaultOptions()
|
||||
params.SetHealthcheckTimeout(neofs.DefaultHealthcheckTimeout)
|
||||
params.SetNodeDialTimeout(neofs.DefaultDialTimeout)
|
||||
params.SetNodeStreamTimeout(neofs.DefaultStreamTimeout)
|
||||
p, err := pool.New(pool.NewFlatNodeParams(rpcNeoFS), signer, params)
|
||||
if err != nil {
|
||||
return nil, neofs.PoolWrapper{}, fmt.Errorf("failed to create NeoFS pool: %w", err)
|
||||
}
|
||||
pWrapper := neofs.PoolWrapper{Pool: p}
|
||||
if err = pWrapper.Dial(context.Background()); err != nil {
|
||||
return nil, neofs.PoolWrapper{}, fmt.Errorf("failed to dial NeoFS pool: %w", err)
|
||||
}
|
||||
return signer, pWrapper, nil
|
||||
}
|
||||
|
||||
// GetInvoker returns an invoker using the given RPC client, context and signers.
|
||||
// It parses "--historic" parameter to adjust it.
|
||||
func GetInvoker(c *rpcclient.Client, ctx *cli.Context, signers []transaction.Signer) (*invoker.Invoker, cli.ExitCoder) {
|
||||
|
|
|
@ -30,7 +30,7 @@ func dumpBin(ctx *cli.Context) error {
|
|||
count := uint32(ctx.Uint("count"))
|
||||
start := uint32(ctx.Uint("start"))
|
||||
|
||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
||||
chain, _, prometheus, pprof, err := InitBCWithMetrics(cfg, log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -140,10 +140,11 @@ func newGraceContext() context.Context {
|
|||
return ctx
|
||||
}
|
||||
|
||||
func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *metrics.Service, *metrics.Service, error) {
|
||||
chain, _, err := initBlockChain(cfg, log)
|
||||
// InitBCWithMetrics initializes the blockchain with metrics with the given configuration.
|
||||
func InitBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, *metrics.Service, *metrics.Service, error) {
|
||||
chain, store, err := initBlockChain(cfg, log)
|
||||
if err != nil {
|
||||
return nil, nil, nil, cli.Exit(err, 1)
|
||||
return nil, nil, nil, nil, cli.Exit(err, 1)
|
||||
}
|
||||
prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log)
|
||||
pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log)
|
||||
|
@ -151,14 +152,14 @@ func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *m
|
|||
go chain.Run()
|
||||
err = prometheus.Start()
|
||||
if err != nil {
|
||||
return nil, nil, nil, cli.Exit(fmt.Errorf("failed to start Prometheus service: %w", err), 1)
|
||||
return nil, nil, nil, nil, cli.Exit(fmt.Errorf("failed to start Prometheus service: %w", err), 1)
|
||||
}
|
||||
err = pprof.Start()
|
||||
if err != nil {
|
||||
return nil, nil, nil, cli.Exit(fmt.Errorf("failed to start Pprof service: %w", err), 1)
|
||||
return nil, nil, nil, nil, cli.Exit(fmt.Errorf("failed to start Pprof service: %w", err), 1)
|
||||
}
|
||||
|
||||
return chain, prometheus, pprof, nil
|
||||
return chain, store, prometheus, pprof, nil
|
||||
}
|
||||
|
||||
func dumpDB(ctx *cli.Context) error {
|
||||
|
@ -189,7 +190,7 @@ func dumpDB(ctx *cli.Context) error {
|
|||
defer outStream.Close()
|
||||
writer := io.NewBinWriterFromIO(outStream)
|
||||
|
||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
||||
chain, _, prometheus, pprof, err := InitBCWithMetrics(cfg, log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -249,7 +250,7 @@ func restoreDB(ctx *cli.Context) error {
|
|||
cfg.ApplicationConfiguration.SaveStorageBatch = true
|
||||
}
|
||||
|
||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
||||
chain, _, prometheus, pprof, err := InitBCWithMetrics(cfg, log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -470,7 +471,7 @@ func startServer(ctx *cli.Context) error {
|
|||
return cli.Exit(err, 1)
|
||||
}
|
||||
|
||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
||||
chain, _, prometheus, pprof, err := InitBCWithMetrics(cfg, log)
|
||||
if err != nil {
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
|
|
|
@ -185,11 +185,11 @@ func TestInitBCWithMetrics(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("bad store", func(t *testing.T) {
|
||||
_, _, _, err = initBCWithMetrics(config.Config{}, logger)
|
||||
_, _, _, _, err = InitBCWithMetrics(config.Config{}, logger)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, logger)
|
||||
chain, _, prometheus, pprof, err := InitBCWithMetrics(cfg, logger)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
chain.Close()
|
||||
|
|
|
@ -208,8 +208,15 @@ func itemToNftRoyaltyRecipientShare(item stackitem.Item, err error) (*NftRoyalty
|
|||
return res, err
|
||||
}
|
||||
|
||||
// Ensure *NftRoyaltyRecipientShare is a proper [stackitem.Convertible].
|
||||
var _ = stackitem.Convertible(&NftRoyaltyRecipientShare{})
|
||||
|
||||
// Ensure *NftRoyaltyRecipientShare is a proper [smartcontract.Convertible].
|
||||
var _ = smartcontract.Convertible(&NftRoyaltyRecipientShare{})
|
||||
|
||||
// FromStackItem retrieves fields of NftRoyaltyRecipientShare from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *NftRoyaltyRecipientShare) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
|
@ -247,3 +254,58 @@ func (res *NftRoyaltyRecipientShare) FromStackItem(item stackitem.Item) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToStackItem creates [stackitem.Item] representing NftRoyaltyRecipientShare.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *NftRoyaltyRecipientShare) ToStackItem() (stackitem.Item, error) {
|
||||
if res == nil {
|
||||
return stackitem.Null{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
itm stackitem.Item
|
||||
items = make([]stackitem.Item, 0, 2)
|
||||
)
|
||||
itm, err = stackitem.NewByteArray(res.Address.BytesBE()), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field Address: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
itm, err = (*stackitem.BigInteger)(res.Share), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field Share: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
return stackitem.NewStruct(items), nil
|
||||
}
|
||||
|
||||
// ToSCParameter creates [smartcontract.Parameter] representing NftRoyaltyRecipientShare.
|
||||
// It implements [smartcontract.Convertible] interface so that NftRoyaltyRecipientShare
|
||||
// could be used with invokers.
|
||||
func (res *NftRoyaltyRecipientShare) ToSCParameter() (smartcontract.Parameter, error) {
|
||||
if res == nil {
|
||||
return smartcontract.Parameter{Type: smartcontract.AnyType}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
prm smartcontract.Parameter
|
||||
prms = make([]smartcontract.Parameter, 0, 2)
|
||||
)
|
||||
prm, err = smartcontract.NewParameterFromValue(res.Address)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field Address: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
prm, err = smartcontract.NewParameterFromValue(res.Share)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field Share: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
return smartcontract.Parameter{Type: smartcontract.ArrayType, Value: prms}, nil
|
||||
}
|
||||
|
|
|
@ -203,8 +203,15 @@ func itemToNftRoyaltyRecipientShare(item stackitem.Item, err error) (*NftRoyalty
|
|||
return res, err
|
||||
}
|
||||
|
||||
// Ensure *NftRoyaltyRecipientShare is a proper [stackitem.Convertible].
|
||||
var _ = stackitem.Convertible(&NftRoyaltyRecipientShare{})
|
||||
|
||||
// Ensure *NftRoyaltyRecipientShare is a proper [smartcontract.Convertible].
|
||||
var _ = smartcontract.Convertible(&NftRoyaltyRecipientShare{})
|
||||
|
||||
// FromStackItem retrieves fields of NftRoyaltyRecipientShare from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *NftRoyaltyRecipientShare) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
|
@ -242,3 +249,58 @@ func (res *NftRoyaltyRecipientShare) FromStackItem(item stackitem.Item) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToStackItem creates [stackitem.Item] representing NftRoyaltyRecipientShare.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *NftRoyaltyRecipientShare) ToStackItem() (stackitem.Item, error) {
|
||||
if res == nil {
|
||||
return stackitem.Null{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
itm stackitem.Item
|
||||
items = make([]stackitem.Item, 0, 2)
|
||||
)
|
||||
itm, err = stackitem.NewByteArray(res.Address.BytesBE()), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field Address: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
itm, err = (*stackitem.BigInteger)(res.Share), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field Share: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
return stackitem.NewStruct(items), nil
|
||||
}
|
||||
|
||||
// ToSCParameter creates [smartcontract.Parameter] representing NftRoyaltyRecipientShare.
|
||||
// It implements [smartcontract.Convertible] interface so that NftRoyaltyRecipientShare
|
||||
// could be used with invokers.
|
||||
func (res *NftRoyaltyRecipientShare) ToSCParameter() (smartcontract.Parameter, error) {
|
||||
if res == nil {
|
||||
return smartcontract.Parameter{Type: smartcontract.AnyType}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
prm smartcontract.Parameter
|
||||
prms = make([]smartcontract.Parameter, 0, 2)
|
||||
)
|
||||
prm, err = smartcontract.NewParameterFromValue(res.Address)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field Address: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
prm, err = smartcontract.NewParameterFromValue(res.Share)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field Share: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
return smartcontract.Parameter{Type: smartcontract.ArrayType, Value: prms}, nil
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"math/big"
|
||||
|
@ -200,8 +201,15 @@ func itemToCrazyStruct(item stackitem.Item, err error) (*CrazyStruct, error) {
|
|||
return res, err
|
||||
}
|
||||
|
||||
// Ensure *CrazyStruct is a proper [stackitem.Convertible].
|
||||
var _ = stackitem.Convertible(&CrazyStruct{})
|
||||
|
||||
// Ensure *CrazyStruct is a proper [smartcontract.Convertible].
|
||||
var _ = smartcontract.Convertible(&CrazyStruct{})
|
||||
|
||||
// FromStackItem retrieves fields of CrazyStruct from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *CrazyStruct) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
|
@ -230,6 +238,61 @@ func (res *CrazyStruct) FromStackItem(item stackitem.Item) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ToStackItem creates [stackitem.Item] representing CrazyStruct.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *CrazyStruct) ToStackItem() (stackitem.Item, error) {
|
||||
if res == nil {
|
||||
return stackitem.Null{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
itm stackitem.Item
|
||||
items = make([]stackitem.Item, 0, 2)
|
||||
)
|
||||
itm, err = (*stackitem.BigInteger)(res.I), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
itm, err = stackitem.NewBool(res.B), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field B: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
return stackitem.NewStruct(items), nil
|
||||
}
|
||||
|
||||
// ToSCParameter creates [smartcontract.Parameter] representing CrazyStruct.
|
||||
// It implements [smartcontract.Convertible] interface so that CrazyStruct
|
||||
// could be used with invokers.
|
||||
func (res *CrazyStruct) ToSCParameter() (smartcontract.Parameter, error) {
|
||||
if res == nil {
|
||||
return smartcontract.Parameter{Type: smartcontract.AnyType}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
prm smartcontract.Parameter
|
||||
prms = make([]smartcontract.Parameter, 0, 2)
|
||||
)
|
||||
prm, err = smartcontract.NewParameterFromValue(res.I)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
prm, err = smartcontract.NewParameterFromValue(res.B)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field B: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
return smartcontract.Parameter{Type: smartcontract.ArrayType, Value: prms}, nil
|
||||
}
|
||||
|
||||
// itemToSimpleStruct converts stack item into *SimpleStruct.
|
||||
// NULL item is returned as nil pointer without error.
|
||||
func itemToSimpleStruct(item stackitem.Item, err error) (*SimpleStruct, error) {
|
||||
|
@ -245,8 +308,15 @@ func itemToSimpleStruct(item stackitem.Item, err error) (*SimpleStruct, error) {
|
|||
return res, err
|
||||
}
|
||||
|
||||
// Ensure *SimpleStruct is a proper [stackitem.Convertible].
|
||||
var _ = stackitem.Convertible(&SimpleStruct{})
|
||||
|
||||
// Ensure *SimpleStruct is a proper [smartcontract.Convertible].
|
||||
var _ = smartcontract.Convertible(&SimpleStruct{})
|
||||
|
||||
// FromStackItem retrieves fields of SimpleStruct from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *SimpleStruct) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
|
@ -269,6 +339,49 @@ func (res *SimpleStruct) FromStackItem(item stackitem.Item) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ToStackItem creates [stackitem.Item] representing SimpleStruct.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *SimpleStruct) ToStackItem() (stackitem.Item, error) {
|
||||
if res == nil {
|
||||
return stackitem.Null{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
itm stackitem.Item
|
||||
items = make([]stackitem.Item, 0, 1)
|
||||
)
|
||||
itm, err = (*stackitem.BigInteger)(res.I), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
return stackitem.NewStruct(items), nil
|
||||
}
|
||||
|
||||
// ToSCParameter creates [smartcontract.Parameter] representing SimpleStruct.
|
||||
// It implements [smartcontract.Convertible] interface so that SimpleStruct
|
||||
// could be used with invokers.
|
||||
func (res *SimpleStruct) ToSCParameter() (smartcontract.Parameter, error) {
|
||||
if res == nil {
|
||||
return smartcontract.Parameter{Type: smartcontract.AnyType}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
prm smartcontract.Parameter
|
||||
prms = make([]smartcontract.Parameter, 0, 1)
|
||||
)
|
||||
prm, err = smartcontract.NewParameterFromValue(res.I)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
return smartcontract.Parameter{Type: smartcontract.ArrayType, Value: prms}, nil
|
||||
}
|
||||
|
||||
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
|
||||
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"math/big"
|
||||
|
@ -200,8 +201,15 @@ func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
|
|||
return res, err
|
||||
}
|
||||
|
||||
// Ensure *Unnamed is a proper [stackitem.Convertible].
|
||||
var _ = stackitem.Convertible(&Unnamed{})
|
||||
|
||||
// Ensure *Unnamed is a proper [smartcontract.Convertible].
|
||||
var _ = smartcontract.Convertible(&Unnamed{})
|
||||
|
||||
// FromStackItem retrieves fields of Unnamed from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
|
@ -230,6 +238,61 @@ func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ToStackItem creates [stackitem.Item] representing Unnamed.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *Unnamed) ToStackItem() (stackitem.Item, error) {
|
||||
if res == nil {
|
||||
return stackitem.Null{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
itm stackitem.Item
|
||||
items = make([]stackitem.Item, 0, 2)
|
||||
)
|
||||
itm, err = (*stackitem.BigInteger)(res.I), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
itm, err = stackitem.NewBool(res.B), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field B: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
return stackitem.NewStruct(items), nil
|
||||
}
|
||||
|
||||
// ToSCParameter creates [smartcontract.Parameter] representing Unnamed.
|
||||
// It implements [smartcontract.Convertible] interface so that Unnamed
|
||||
// could be used with invokers.
|
||||
func (res *Unnamed) ToSCParameter() (smartcontract.Parameter, error) {
|
||||
if res == nil {
|
||||
return smartcontract.Parameter{Type: smartcontract.AnyType}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
prm smartcontract.Parameter
|
||||
prms = make([]smartcontract.Parameter, 0, 2)
|
||||
)
|
||||
prm, err = smartcontract.NewParameterFromValue(res.I)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
prm, err = smartcontract.NewParameterFromValue(res.B)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field B: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
return smartcontract.Parameter{Type: smartcontract.ArrayType, Value: prms}, nil
|
||||
}
|
||||
|
||||
// itemToUnnamedX converts stack item into *UnnamedX.
|
||||
// NULL item is returned as nil pointer without error.
|
||||
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
||||
|
@ -245,8 +308,15 @@ func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
|||
return res, err
|
||||
}
|
||||
|
||||
// Ensure *UnnamedX is a proper [stackitem.Convertible].
|
||||
var _ = stackitem.Convertible(&UnnamedX{})
|
||||
|
||||
// Ensure *UnnamedX is a proper [smartcontract.Convertible].
|
||||
var _ = smartcontract.Convertible(&UnnamedX{})
|
||||
|
||||
// FromStackItem retrieves fields of UnnamedX from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
|
@ -269,6 +339,49 @@ func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ToStackItem creates [stackitem.Item] representing UnnamedX.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *UnnamedX) ToStackItem() (stackitem.Item, error) {
|
||||
if res == nil {
|
||||
return stackitem.Null{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
itm stackitem.Item
|
||||
items = make([]stackitem.Item, 0, 1)
|
||||
)
|
||||
itm, err = (*stackitem.BigInteger)(res.I), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
return stackitem.NewStruct(items), nil
|
||||
}
|
||||
|
||||
// ToSCParameter creates [smartcontract.Parameter] representing UnnamedX.
|
||||
// It implements [smartcontract.Convertible] interface so that UnnamedX
|
||||
// could be used with invokers.
|
||||
func (res *UnnamedX) ToSCParameter() (smartcontract.Parameter, error) {
|
||||
if res == nil {
|
||||
return smartcontract.Parameter{Type: smartcontract.AnyType}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
prm smartcontract.Parameter
|
||||
prms = make([]smartcontract.Parameter, 0, 1)
|
||||
)
|
||||
prm, err = smartcontract.NewParameterFromValue(res.I)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
return smartcontract.Parameter{Type: smartcontract.ArrayType, Value: prms}, nil
|
||||
}
|
||||
|
||||
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
|
||||
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
|
||||
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"math/big"
|
||||
|
@ -384,8 +385,15 @@ func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
|
|||
return res, err
|
||||
}
|
||||
|
||||
// Ensure *Unnamed is a proper [stackitem.Convertible].
|
||||
var _ = stackitem.Convertible(&Unnamed{})
|
||||
|
||||
// Ensure *Unnamed is a proper [smartcontract.Convertible].
|
||||
var _ = smartcontract.Convertible(&Unnamed{})
|
||||
|
||||
// FromStackItem retrieves fields of Unnamed from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
|
@ -408,6 +416,49 @@ func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ToStackItem creates [stackitem.Item] representing Unnamed.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *Unnamed) ToStackItem() (stackitem.Item, error) {
|
||||
if res == nil {
|
||||
return stackitem.Null{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
itm stackitem.Item
|
||||
items = make([]stackitem.Item, 0, 1)
|
||||
)
|
||||
itm, err = (*stackitem.BigInteger)(res.I), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
return stackitem.NewStruct(items), nil
|
||||
}
|
||||
|
||||
// ToSCParameter creates [smartcontract.Parameter] representing Unnamed.
|
||||
// It implements [smartcontract.Convertible] interface so that Unnamed
|
||||
// could be used with invokers.
|
||||
func (res *Unnamed) ToSCParameter() (smartcontract.Parameter, error) {
|
||||
if res == nil {
|
||||
return smartcontract.Parameter{Type: smartcontract.AnyType}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
prm smartcontract.Parameter
|
||||
prms = make([]smartcontract.Parameter, 0, 1)
|
||||
)
|
||||
prm, err = smartcontract.NewParameterFromValue(res.I)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
return smartcontract.Parameter{Type: smartcontract.ArrayType, Value: prms}, nil
|
||||
}
|
||||
|
||||
// itemToUnnamedX converts stack item into *UnnamedX.
|
||||
// NULL item is returned as nil pointer without error.
|
||||
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
||||
|
@ -423,8 +474,15 @@ func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
|||
return res, err
|
||||
}
|
||||
|
||||
// Ensure *UnnamedX is a proper [stackitem.Convertible].
|
||||
var _ = stackitem.Convertible(&UnnamedX{})
|
||||
|
||||
// Ensure *UnnamedX is a proper [smartcontract.Convertible].
|
||||
var _ = smartcontract.Convertible(&UnnamedX{})
|
||||
|
||||
// FromStackItem retrieves fields of UnnamedX from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
|
@ -452,3 +510,58 @@ func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToStackItem creates [stackitem.Item] representing UnnamedX.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *UnnamedX) ToStackItem() (stackitem.Item, error) {
|
||||
if res == nil {
|
||||
return stackitem.Null{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
itm stackitem.Item
|
||||
items = make([]stackitem.Item, 0, 2)
|
||||
)
|
||||
itm, err = (*stackitem.BigInteger)(res.I), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
itm, err = stackitem.NewBool(res.B), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field B: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
return stackitem.NewStruct(items), nil
|
||||
}
|
||||
|
||||
// ToSCParameter creates [smartcontract.Parameter] representing UnnamedX.
|
||||
// It implements [smartcontract.Convertible] interface so that UnnamedX
|
||||
// could be used with invokers.
|
||||
func (res *UnnamedX) ToSCParameter() (smartcontract.Parameter, error) {
|
||||
if res == nil {
|
||||
return smartcontract.Parameter{Type: smartcontract.AnyType}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
prm smartcontract.Parameter
|
||||
prms = make([]smartcontract.Parameter, 0, 2)
|
||||
)
|
||||
prm, err = smartcontract.NewParameterFromValue(res.I)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
prm, err = smartcontract.NewParameterFromValue(res.B)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field B: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
return smartcontract.Parameter{Type: smartcontract.ArrayType, Value: prms}, nil
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"math/big"
|
||||
|
@ -380,8 +381,15 @@ func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
|
|||
return res, err
|
||||
}
|
||||
|
||||
// Ensure *Unnamed is a proper [stackitem.Convertible].
|
||||
var _ = stackitem.Convertible(&Unnamed{})
|
||||
|
||||
// Ensure *Unnamed is a proper [smartcontract.Convertible].
|
||||
var _ = smartcontract.Convertible(&Unnamed{})
|
||||
|
||||
// FromStackItem retrieves fields of Unnamed from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
|
@ -404,6 +412,49 @@ func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ToStackItem creates [stackitem.Item] representing Unnamed.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *Unnamed) ToStackItem() (stackitem.Item, error) {
|
||||
if res == nil {
|
||||
return stackitem.Null{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
itm stackitem.Item
|
||||
items = make([]stackitem.Item, 0, 1)
|
||||
)
|
||||
itm, err = (*stackitem.BigInteger)(res.I), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
return stackitem.NewStruct(items), nil
|
||||
}
|
||||
|
||||
// ToSCParameter creates [smartcontract.Parameter] representing Unnamed.
|
||||
// It implements [smartcontract.Convertible] interface so that Unnamed
|
||||
// could be used with invokers.
|
||||
func (res *Unnamed) ToSCParameter() (smartcontract.Parameter, error) {
|
||||
if res == nil {
|
||||
return smartcontract.Parameter{Type: smartcontract.AnyType}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
prm smartcontract.Parameter
|
||||
prms = make([]smartcontract.Parameter, 0, 1)
|
||||
)
|
||||
prm, err = smartcontract.NewParameterFromValue(res.I)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
return smartcontract.Parameter{Type: smartcontract.ArrayType, Value: prms}, nil
|
||||
}
|
||||
|
||||
// itemToUnnamedX converts stack item into *UnnamedX.
|
||||
// NULL item is returned as nil pointer without error.
|
||||
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
||||
|
@ -419,8 +470,15 @@ func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
|||
return res, err
|
||||
}
|
||||
|
||||
// Ensure *UnnamedX is a proper [stackitem.Convertible].
|
||||
var _ = stackitem.Convertible(&UnnamedX{})
|
||||
|
||||
// Ensure *UnnamedX is a proper [smartcontract.Convertible].
|
||||
var _ = smartcontract.Convertible(&UnnamedX{})
|
||||
|
||||
// FromStackItem retrieves fields of UnnamedX from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
|
@ -448,3 +506,58 @@ func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToStackItem creates [stackitem.Item] representing UnnamedX.
|
||||
// It implements [stackitem.Convertible] interface.
|
||||
func (res *UnnamedX) ToStackItem() (stackitem.Item, error) {
|
||||
if res == nil {
|
||||
return stackitem.Null{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
itm stackitem.Item
|
||||
items = make([]stackitem.Item, 0, 2)
|
||||
)
|
||||
itm, err = (*stackitem.BigInteger)(res.I), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
itm, err = stackitem.NewBool(res.B), error(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field B: %w", err)
|
||||
}
|
||||
items = append(items, itm)
|
||||
|
||||
return stackitem.NewStruct(items), nil
|
||||
}
|
||||
|
||||
// ToSCParameter creates [smartcontract.Parameter] representing UnnamedX.
|
||||
// It implements [smartcontract.Convertible] interface so that UnnamedX
|
||||
// could be used with invokers.
|
||||
func (res *UnnamedX) ToSCParameter() (smartcontract.Parameter, error) {
|
||||
if res == nil {
|
||||
return smartcontract.Parameter{Type: smartcontract.AnyType}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
prm smartcontract.Parameter
|
||||
prms = make([]smartcontract.Parameter, 0, 2)
|
||||
)
|
||||
prm, err = smartcontract.NewParameterFromValue(res.I)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field I: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
prm, err = smartcontract.NewParameterFromValue(res.B)
|
||||
if err != nil {
|
||||
return smartcontract.Parameter{}, fmt.Errorf("field B: %w", err)
|
||||
}
|
||||
prms = append(prms, prm)
|
||||
|
||||
return smartcontract.Parameter{Type: smartcontract.ArrayType, Value: prms}, nil
|
||||
}
|
||||
|
|
|
@ -16,6 +16,35 @@ import (
|
|||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var neoFSFlags = append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "container",
|
||||
Aliases: []string{"cid"},
|
||||
Usage: "NeoFS container ID to upload objects to",
|
||||
Required: true,
|
||||
Action: cmdargs.EnsureNotEmpty("container"),
|
||||
},
|
||||
&flags.AddressFlag{
|
||||
Name: "address",
|
||||
Usage: "Address to use for signing the uploading and searching transactions in NeoFS",
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "retries",
|
||||
Usage: "Maximum number of NeoFS node request retries",
|
||||
Value: neofs.MaxRetries,
|
||||
Action: func(context *cli.Context, u uint) error {
|
||||
if u < 1 {
|
||||
return cli.Exit("retries should be greater than 0", 1)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "searchers",
|
||||
Usage: "Number of concurrent searches for objects",
|
||||
Value: 100,
|
||||
}}, options.NeoFSRPC...)
|
||||
|
||||
// NewCommands returns util commands for neo-go CLI.
|
||||
func NewCommands() []*cli.Command {
|
||||
// By default, RPC flag is required. sendtx and txdump may be called without provided rpc-endpoint.
|
||||
|
@ -35,42 +64,17 @@ func NewCommands() []*cli.Command {
|
|||
}, options.RPC...)
|
||||
txCancelFlags = append(txCancelFlags, options.Wallet...)
|
||||
uploadBinFlags := append([]cli.Flag{
|
||||
&cli.StringSliceFlag{
|
||||
Name: "fs-rpc-endpoint",
|
||||
Aliases: []string{"fsr"},
|
||||
Usage: "List of NeoFS storage node RPC addresses (comma-separated or multiple --fs-rpc-endpoint flags)",
|
||||
Required: true,
|
||||
Action: func(ctx *cli.Context, fsRpcEndpoints []string) error {
|
||||
for _, endpoint := range fsRpcEndpoints {
|
||||
if endpoint == "" {
|
||||
return cli.Exit("NeoFS RPC endpoint cannot contain empty values", 1)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "block-attribute",
|
||||
Usage: "Attribute key of the block object",
|
||||
Value: neofs.DefaultBlockAttribute,
|
||||
Action: cmdargs.EnsureNotEmpty("block-attribute"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "container",
|
||||
Aliases: []string{"cid"},
|
||||
Usage: "NeoFS container ID to upload blocks to",
|
||||
Required: true,
|
||||
Action: cmdargs.EnsureNotEmpty("container"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "block-attribute",
|
||||
Usage: "Attribute key of the block object",
|
||||
Required: true,
|
||||
Action: cmdargs.EnsureNotEmpty("block-attribute"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "index-attribute",
|
||||
Usage: "Attribute key of the index file object",
|
||||
Required: true,
|
||||
Action: cmdargs.EnsureNotEmpty("index-attribute"),
|
||||
},
|
||||
&flags.AddressFlag{
|
||||
Name: "address",
|
||||
Usage: "Address to use for signing the uploading and searching transactions in NeoFS",
|
||||
Name: "index-attribute",
|
||||
Usage: "Attribute key of the index file object",
|
||||
Value: neofs.DefaultIndexFileAttribute,
|
||||
Action: cmdargs.EnsureNotEmpty("index-attribute"),
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "index-file-size",
|
||||
|
@ -80,27 +84,24 @@ func NewCommands() []*cli.Command {
|
|||
&cli.UintFlag{
|
||||
Name: "workers",
|
||||
Usage: "Number of workers to fetch and upload blocks concurrently",
|
||||
Value: 50,
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "searchers",
|
||||
Usage: "Number of concurrent searches for blocks",
|
||||
Value: 20,
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "retries",
|
||||
Usage: "Maximum number of Neo/NeoFS node request retries",
|
||||
Value: neofs.MaxRetries,
|
||||
Action: func(context *cli.Context, u uint) error {
|
||||
if u < 1 {
|
||||
return cli.Exit("retries should be greater than 0", 1)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
options.Debug,
|
||||
}, options.RPC...)
|
||||
uploadBinFlags = append(uploadBinFlags, options.Wallet...)
|
||||
uploadBinFlags = append(uploadBinFlags, neoFSFlags...)
|
||||
|
||||
uploadStateFlags := append([]cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "state-attribute",
|
||||
Usage: "Attribute key of the state object",
|
||||
Value: neofs.DefaultStateAttribute,
|
||||
Action: cmdargs.EnsureNotEmpty("state-attribute"),
|
||||
},
|
||||
options.Debug, options.Config, options.ConfigFile, options.RelativePath,
|
||||
}, options.Wallet...)
|
||||
uploadStateFlags = append(uploadStateFlags, options.Network...)
|
||||
uploadStateFlags = append(uploadStateFlags, neoFSFlags...)
|
||||
return []*cli.Command{
|
||||
{
|
||||
Name: "util",
|
||||
|
@ -185,6 +186,13 @@ func NewCommands() []*cli.Command {
|
|||
Action: uploadBin,
|
||||
Flags: uploadBinFlags,
|
||||
},
|
||||
{
|
||||
Name: "upload-state",
|
||||
Usage: "Start the node, traverse MPT and upload MPT nodes to the NeoFS container at every StateSyncInterval number of blocks",
|
||||
UsageText: "neo-go util upload-state --fs-rpc-endpoint <address1>[,<address2>[...]] --container <cid> --state-attribute state --wallet <wallet> [--wallet-config <config>] [--address <address>] [--searchers <num>] [--retries <num>] [--debug] [--config-path path] [-p/-m/-t] [--config-file file]",
|
||||
Action: uploadState,
|
||||
Flags: uploadStateFlags,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -19,28 +19,14 @@ import (
|
|||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/pool"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// poolWrapper wraps a NeoFS pool to adapt its Close method to return an error.
|
||||
type poolWrapper struct {
|
||||
*pool.Pool
|
||||
}
|
||||
|
||||
// Close closes the pool and returns nil.
|
||||
func (p poolWrapper) Close() error {
|
||||
p.Pool.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func uploadBin(ctx *cli.Context) error {
|
||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
rpcNeoFS := ctx.StringSlice("fs-rpc-endpoint")
|
||||
containerIDStr := ctx.String("container")
|
||||
attr := ctx.String("block-attribute")
|
||||
numWorkers := ctx.Uint("workers")
|
||||
maxParallelSearches := ctx.Uint("searchers")
|
||||
|
@ -52,12 +38,6 @@ func uploadBin(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to load account: %v", err), 1)
|
||||
}
|
||||
|
||||
var containerID cid.ID
|
||||
if err = containerID.DecodeString(containerIDStr); err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to decode container ID: %v", err), 1)
|
||||
}
|
||||
|
||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
rpc, err := options.GetRPCClient(gctx, ctx)
|
||||
|
@ -65,39 +45,20 @@ func uploadBin(ctx *cli.Context) error {
|
|||
return cli.Exit(fmt.Sprintf("failed to create RPC client: %v", err), 1)
|
||||
}
|
||||
|
||||
signer := user.NewAutoIDSignerRFC6979(acc.PrivateKey().PrivateKey)
|
||||
|
||||
params := pool.DefaultOptions()
|
||||
params.SetHealthcheckTimeout(neofs.DefaultHealthcheckTimeout)
|
||||
params.SetNodeDialTimeout(neofs.DefaultDialTimeout)
|
||||
params.SetNodeStreamTimeout(neofs.DefaultStreamTimeout)
|
||||
p, err := pool.New(pool.NewFlatNodeParams(rpcNeoFS), signer, params)
|
||||
signer, pWrapper, err := options.GetNeoFSClientPool(ctx, acc)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to create NeoFS pool: %v", err), 1)
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
pWrapper := poolWrapper{p}
|
||||
if err = pWrapper.Dial(context.Background()); err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to dial NeoFS pool: %v", err), 1)
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
var containerObj container.Container
|
||||
err = retry(func() error {
|
||||
containerObj, err = p.ContainerGet(ctx.Context, containerID, client.PrmContainerGet{})
|
||||
return err
|
||||
}, maxRetries, debug)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Errorf("failed to get container with ID %s: %w", containerID, err), 1)
|
||||
}
|
||||
containerMagic := containerObj.Attribute("Magic")
|
||||
defer pWrapper.Close()
|
||||
|
||||
v, err := rpc.GetVersion()
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to get version from RPC: %v", err), 1)
|
||||
}
|
||||
magic := strconv.Itoa(int(v.Protocol.Network))
|
||||
if containerMagic != magic {
|
||||
return cli.Exit(fmt.Sprintf("container magic %s does not match the network magic %s", containerMagic, magic), 1)
|
||||
containerID, err := getContainer(ctx, pWrapper, magic, maxRetries, debug)
|
||||
if err != nil {
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
|
||||
currentBlockHeight, err := rpc.GetBlockCount()
|
||||
|
@ -138,7 +99,7 @@ func retry(action func() error, maxRetries uint, debug bool) error {
|
|||
}
|
||||
|
||||
// uploadBlocksAndIndexFiles uploads the blocks and index files to the container using the pool.
|
||||
func uploadBlocksAndIndexFiles(ctx *cli.Context, p poolWrapper, rpc *rpcclient.Client, signer user.Signer, containerID cid.ID, attr, indexAttributeKey string, buf []byte, currentIndexFileID, indexFileSize, currentBlockHeight uint, numWorkers, maxRetries uint, debug bool) error {
|
||||
func uploadBlocksAndIndexFiles(ctx *cli.Context, p neofs.PoolWrapper, rpc *rpcclient.Client, signer user.Signer, containerID cid.ID, attr, indexAttributeKey string, buf []byte, currentIndexFileID, indexFileSize, currentBlockHeight uint, numWorkers, maxRetries uint, debug bool) error {
|
||||
if currentIndexFileID*indexFileSize >= currentBlockHeight {
|
||||
fmt.Fprintf(ctx.App.Writer, "No new blocks to upload. Need to upload starting from %d, current height %d\n", currentIndexFileID*indexFileSize, currentBlockHeight)
|
||||
return nil
|
||||
|
@ -257,7 +218,7 @@ func uploadBlocksAndIndexFiles(ctx *cli.Context, p poolWrapper, rpc *rpcclient.C
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to upload index file: %w", err)
|
||||
}
|
||||
fmt.Println("Successfully uploaded index file ", indexFileStart/indexFileSize)
|
||||
fmt.Fprintln(ctx.App.Writer, "Successfully uploaded index file ", indexFileStart/indexFileSize)
|
||||
}
|
||||
clear(buf)
|
||||
}
|
||||
|
@ -265,7 +226,7 @@ func uploadBlocksAndIndexFiles(ctx *cli.Context, p poolWrapper, rpc *rpcclient.C
|
|||
}
|
||||
|
||||
// searchIndexFile returns the ID and buffer for the next index file to be uploaded.
|
||||
func searchIndexFile(ctx *cli.Context, p poolWrapper, containerID cid.ID, privKeys *keys.PrivateKey, signer user.Signer, indexFileSize uint, blockAttributeKey, attributeKey string, maxParallelSearches, maxRetries uint, debug bool) (uint, []byte, error) {
|
||||
func searchIndexFile(ctx *cli.Context, p neofs.PoolWrapper, containerID cid.ID, privKeys *keys.PrivateKey, signer user.Signer, indexFileSize uint, blockAttributeKey, attributeKey string, maxParallelSearches, maxRetries uint, debug bool) (uint, []byte, error) {
|
||||
var (
|
||||
// buf is used to store OIDs of the uploaded blocks.
|
||||
buf = make([]byte, indexFileSize*oid.Size)
|
||||
|
@ -281,20 +242,16 @@ func searchIndexFile(ctx *cli.Context, p poolWrapper, containerID cid.ID, privKe
|
|||
filters.AddFilter("IndexSize", fmt.Sprintf("%d", indexFileSize), object.MatchStringEqual)
|
||||
for i := 0; ; i++ {
|
||||
indexIDs := searchObjects(ctx.Context, p, containerID, privKeys, attributeKey, uint(i), uint(i+1), 1, maxRetries, debug, errCh, filters)
|
||||
count := 0
|
||||
for range indexIDs {
|
||||
count++
|
||||
if count > 1 {
|
||||
select {
|
||||
case errCh <- fmt.Errorf("duplicated index file %d found", i):
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
resOIDs := make([]oid.ID, 0, 1)
|
||||
for id := range indexIDs {
|
||||
resOIDs = append(resOIDs, id)
|
||||
}
|
||||
if count == 0 {
|
||||
if len(resOIDs) == 0 {
|
||||
break
|
||||
}
|
||||
if len(resOIDs) > 1 {
|
||||
fmt.Fprintf(ctx.App.Writer, "WARN: %d duplicated index files with index %d found: %s\n", len(resOIDs), i, resOIDs)
|
||||
}
|
||||
existingIndexCount++
|
||||
}
|
||||
fmt.Fprintf(ctx.App.Writer, "Current index files count: %d\n", existingIndexCount)
|
||||
|
@ -361,7 +318,7 @@ func searchIndexFile(ctx *cli.Context, p poolWrapper, containerID cid.ID, privKe
|
|||
// searchObjects searches in parallel for objects with attribute GE startIndex and LT
|
||||
// endIndex. It returns a buffered channel of resulting object IDs and closes it once
|
||||
// OID search is finished. Errors are sent to errCh in a non-blocking way.
|
||||
func searchObjects(ctx context.Context, p poolWrapper, containerID cid.ID, privKeys *keys.PrivateKey, blockAttributeKey string, startIndex, endIndex, maxParallelSearches, maxRetries uint, debug bool, errCh chan error, additionalFilters ...object.SearchFilters) chan oid.ID {
|
||||
func searchObjects(ctx context.Context, p neofs.PoolWrapper, containerID cid.ID, privKeys *keys.PrivateKey, blockAttributeKey string, startIndex, endIndex, maxParallelSearches, maxRetries uint, debug bool, errCh chan error, additionalFilters ...object.SearchFilters) chan oid.ID {
|
||||
var res = make(chan oid.ID, 2*neofs.DefaultSearchBatchSize)
|
||||
go func() {
|
||||
var wg sync.WaitGroup
|
||||
|
@ -423,7 +380,7 @@ func searchObjects(ctx context.Context, p poolWrapper, containerID cid.ID, privK
|
|||
}
|
||||
|
||||
// uploadObj uploads object to the container using provided settings.
|
||||
func uploadObj(ctx context.Context, p poolWrapper, signer user.Signer, containerID cid.ID, objData []byte, attrs []object.Attribute) (oid.ID, error) {
|
||||
func uploadObj(ctx context.Context, p neofs.PoolWrapper, signer user.Signer, containerID cid.ID, objData []byte, attrs []object.Attribute) (oid.ID, error) {
|
||||
var (
|
||||
hdr object.Object
|
||||
prmObjectPutInit client.PrmObjectPutInit
|
||||
|
@ -465,3 +422,28 @@ func getBlockIndex(header object.Object, attribute string) (int, error) {
|
|||
}
|
||||
return -1, fmt.Errorf("attribute %s not found", attribute)
|
||||
}
|
||||
|
||||
// getContainer gets container by ID and checks its magic.
|
||||
func getContainer(ctx *cli.Context, p neofs.PoolWrapper, expectedMagic string, maxRetries uint, debug bool) (cid.ID, error) {
|
||||
var (
|
||||
containerObj container.Container
|
||||
err error
|
||||
containerIDStr = ctx.String("container")
|
||||
)
|
||||
var containerID cid.ID
|
||||
if err = containerID.DecodeString(containerIDStr); err != nil {
|
||||
return containerID, fmt.Errorf("failed to decode container ID: %w", err)
|
||||
}
|
||||
err = retry(func() error {
|
||||
containerObj, err = p.ContainerGet(ctx.Context, containerID, client.PrmContainerGet{})
|
||||
return err
|
||||
}, maxRetries, debug)
|
||||
if err != nil {
|
||||
return containerID, fmt.Errorf("failed to get container: %w", err)
|
||||
}
|
||||
containerMagic := containerObj.Attribute("Magic")
|
||||
if containerMagic != expectedMagic {
|
||||
return containerID, fmt.Errorf("container magic mismatch: expected %s, got %s", expectedMagic, containerMagic)
|
||||
}
|
||||
return containerID, nil
|
||||
}
|
||||
|
|
206
cli/util/upload_state.go
Normal file
206
cli/util/upload_state.go
Normal file
|
@ -0,0 +1,206 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/cli/server"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/mpt"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
gio "github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/services/helpers/neofs"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/client"
|
||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func uploadState(ctx *cli.Context) error {
|
||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
cfg, err := options.GetConfigFromContext(ctx)
|
||||
if err != nil {
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
attr := ctx.String("state-attribute")
|
||||
maxRetries := ctx.Uint("retries")
|
||||
debug := ctx.Bool("debug")
|
||||
|
||||
acc, _, err := options.GetAccFromContext(ctx)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to load account: %v", err), 1)
|
||||
}
|
||||
|
||||
signer, p, err := options.GetNeoFSClientPool(ctx, acc)
|
||||
if err != nil {
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
defer p.Close()
|
||||
log, _, logCloser, err := options.HandleLoggingParams(debug, cfg.ApplicationConfiguration)
|
||||
if err != nil {
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
if logCloser != nil {
|
||||
defer func() { _ = logCloser() }()
|
||||
}
|
||||
|
||||
chain, store, prometheus, pprof, err := server.InitBCWithMetrics(cfg, log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
pprof.ShutDown()
|
||||
prometheus.ShutDown()
|
||||
chain.Close()
|
||||
}()
|
||||
|
||||
if chain.GetConfig().Ledger.KeepOnlyLatestState || chain.GetConfig().Ledger.RemoveUntraceableBlocks {
|
||||
return cli.Exit("only full-state node is supported: disable KeepOnlyLatestState and RemoveUntraceableBlocks", 1)
|
||||
}
|
||||
syncInterval := cfg.ProtocolConfiguration.StateSyncInterval
|
||||
if syncInterval == 0 {
|
||||
syncInterval = core.DefaultStateSyncInterval
|
||||
}
|
||||
|
||||
containerID, err := getContainer(ctx, p, strconv.Itoa(int(chain.GetConfig().Magic)), maxRetries, debug)
|
||||
if err != nil {
|
||||
return cli.Exit(err, 1)
|
||||
}
|
||||
|
||||
stateObjCount, err := searchStateIndex(ctx, p, containerID, acc.PrivateKey(), attr, syncInterval, maxRetries, debug)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed searching existing states: %v", err), 1)
|
||||
}
|
||||
stateModule := chain.GetStateModule()
|
||||
currentHeight := int(stateModule.CurrentLocalHeight())
|
||||
currentStateIndex := currentHeight / syncInterval
|
||||
if currentStateIndex <= stateObjCount {
|
||||
log.Info("no new states to upload",
|
||||
zap.Int("number of uploaded state objects", stateObjCount),
|
||||
zap.Int("latest state is uploaded for block", stateObjCount*syncInterval),
|
||||
zap.Int("current height", currentHeight),
|
||||
zap.Int("StateSyncInterval", syncInterval))
|
||||
return nil
|
||||
}
|
||||
log.Info("starting uploading",
|
||||
zap.Int("number of uploaded state objects", stateObjCount),
|
||||
zap.Int("next state to upload for block", stateObjCount*syncInterval),
|
||||
zap.Int("current height", currentHeight),
|
||||
zap.Int("StateSyncInterval", syncInterval),
|
||||
zap.Int("number of states to upload", currentStateIndex-stateObjCount))
|
||||
for state := stateObjCount; state < currentStateIndex; state++ {
|
||||
height := uint32(state * syncInterval)
|
||||
stateRoot, err := stateModule.GetStateRoot(height)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to get state root for height %d: %v", height, err), 1)
|
||||
}
|
||||
h, err := chain.GetHeader(chain.GetHeaderHash(height))
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to get header %d: %v", height, err), 1)
|
||||
}
|
||||
|
||||
var (
|
||||
hdr object.Object
|
||||
prmObjectPutInit client.PrmObjectPutInit
|
||||
attrs = []object.Attribute{
|
||||
*object.NewAttribute(attr, strconv.Itoa(int(height))),
|
||||
*object.NewAttribute("Timestamp", strconv.FormatInt(time.Now().Unix(), 10)),
|
||||
*object.NewAttribute("StateRoot", stateRoot.Root.StringLE()),
|
||||
*object.NewAttribute("StateSyncInterval", strconv.Itoa(syncInterval)),
|
||||
*object.NewAttribute("BlockTime", strconv.FormatUint(h.Timestamp, 10)),
|
||||
}
|
||||
)
|
||||
hdr.SetContainerID(containerID)
|
||||
hdr.SetOwner(signer.UserID())
|
||||
hdr.SetAttributes(attrs...)
|
||||
err = retry(func() error {
|
||||
writer, err := p.ObjectPutInit(ctx.Context, hdr, signer, prmObjectPutInit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start := time.Now()
|
||||
wrt := gio.NewBinWriterFromIO(writer)
|
||||
wrt.WriteB(byte(0))
|
||||
wrt.WriteU32LE(uint32(chain.GetConfig().Magic))
|
||||
wrt.WriteU32LE(height)
|
||||
wrt.WriteBytes(stateRoot.Root[:])
|
||||
err = traverseMPT(stateRoot.Root, store, wrt)
|
||||
if err != nil {
|
||||
_ = writer.Close()
|
||||
return err
|
||||
}
|
||||
err = writer.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
duration := time.Since(start)
|
||||
res := writer.GetResult()
|
||||
log.Info("uploaded state object",
|
||||
zap.String("object ID", res.StoredObjectID().String()),
|
||||
zap.Uint32("height", height),
|
||||
zap.Duration("time spent", duration))
|
||||
return nil
|
||||
}, maxRetries, debug)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Sprintf("failed to upload object at height %d: %v", height, err), 1)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func searchStateIndex(ctx *cli.Context, p neofs.PoolWrapper, containerID cid.ID, privKeys *keys.PrivateKey,
|
||||
attributeKey string, syncInterval int, maxRetries uint, debug bool,
|
||||
) (int, error) {
|
||||
var (
|
||||
doneCh = make(chan struct{})
|
||||
errCh = make(chan error)
|
||||
objCount = 0
|
||||
)
|
||||
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
for i := 0; ; i++ {
|
||||
indexIDs := searchObjects(ctx.Context, p, containerID, privKeys,
|
||||
attributeKey, uint(i*syncInterval), uint(i*syncInterval)+1, 1, maxRetries, debug, errCh)
|
||||
resOIDs := make([]oid.ID, 0, 1)
|
||||
for id := range indexIDs {
|
||||
resOIDs = append(resOIDs, id)
|
||||
}
|
||||
if len(resOIDs) == 0 {
|
||||
break
|
||||
}
|
||||
if len(resOIDs) > 1 {
|
||||
fmt.Fprintf(ctx.App.Writer, "WARN: %d duplicated state objects with %s: %d found: %s\n", len(resOIDs), attributeKey, i, resOIDs)
|
||||
}
|
||||
objCount++
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return objCount, err
|
||||
case <-doneCh:
|
||||
return objCount, nil
|
||||
}
|
||||
}
|
||||
|
||||
func traverseMPT(root util.Uint256, store storage.Store, writer *gio.BinWriter) error {
|
||||
cache := storage.NewMemCachedStore(store)
|
||||
billet := mpt.NewBillet(root, mpt.ModeAll, mpt.DummySTTempStoragePrefix, cache)
|
||||
err := billet.Traverse(func(pathToNode []byte, node mpt.Node, nodeBytes []byte) bool {
|
||||
writer.WriteVarBytes(nodeBytes)
|
||||
return writer.Err != nil
|
||||
}, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("billet traversal error: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -204,8 +204,6 @@ func TestUploadBin(t *testing.T) {
|
|||
e.In.WriteString("one\r")
|
||||
e.RunWithErrorCheckExit(t, "failed to load account", append(args, "--cid", "test", "--wallet", "./not-exist.json", "--rpc-endpoint", "https://test")...)
|
||||
e.In.WriteString("one\r")
|
||||
e.RunWithErrorCheckExit(t, "failed to decode container ID", append(args, "--cid", "test", "--wallet", testcli.ValidatorWallet, "--rpc-endpoint", "https://test")...)
|
||||
e.In.WriteString("one\r")
|
||||
e.RunWithErrorCheckExit(t, "failed to create RPC client", append(args, "--cid", "9iVfUg8aDHKjPC4LhQXEkVUM4HDkR7UCXYLs8NQwYfSG", "--wallet", testcli.ValidatorWallet, "--rpc-endpoint", "https://test")...)
|
||||
e.In.WriteString("one\r")
|
||||
e.RunWithErrorCheckExit(t, "failed to dial NeoFS pool", append(args, "--cid", "9iVfUg8aDHKjPC4LhQXEkVUM4HDkR7UCXYLs8NQwYfSG", "--wallet", testcli.ValidatorWallet, "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])...)
|
||||
|
|
|
@ -93,6 +93,6 @@ ApplicationConfiguration:
|
|||
BQueueSize: 16000 # must be larger than OIDBatchSize; recommended to be 2*OIDBatchSize or 3*OIDBatchSize
|
||||
SkipIndexFilesSearch: false
|
||||
IndexFileSize: 128000
|
||||
ContainerID: "VCVr6RKg1hfJR7v36xvjbaXTncj1waPi94u9EFyEttW"
|
||||
ContainerID: "BP71MqY7nJhpuHfdQU3infRSjMgVmSFFt9GfG2GGMZJj"
|
||||
BlockAttribute: "Block"
|
||||
IndexFileAttribute: "Index"
|
||||
|
|
|
@ -111,6 +111,6 @@ ApplicationConfiguration:
|
|||
BQueueSize: 16000 # must be larger than OIDBatchSize; recommended to be 2*OIDBatchSize or 3*OIDBatchSize
|
||||
SkipIndexFilesSearch: false
|
||||
IndexFileSize: 128000
|
||||
ContainerID: "7a1cn9LNmAcHjESKWxRGG7RSZ55YHJF6z2xDLTCuTZ6c"
|
||||
ContainerID: "3RCdP3ZubyKyo8qFeo7EJPryidTZaGCMdUjqFJaaEKBV"
|
||||
BlockAttribute: "Block"
|
||||
IndexFileAttribute: "Index"
|
||||
|
|
|
@ -100,6 +100,6 @@ ApplicationConfiguration:
|
|||
BQueueSize: 16000 # must be larger than OIDBatchSize; recommended to be 2*OIDBatchSize or 3*OIDBatchSize
|
||||
SkipIndexFilesSearch: false
|
||||
IndexFileSize: 128000
|
||||
ContainerID: "FidCcVzUxzY3PeUksCnnpUQ8h8PJeYPessX8FRMuveSy"
|
||||
ContainerID: "98xz5YeanzxRCpH6EfUhECVm2MynGYchDN4naJViHT9M"
|
||||
BlockAttribute: "Block"
|
||||
IndexFileAttribute: "Index"
|
||||
|
|
|
@ -113,6 +113,6 @@ ApplicationConfiguration:
|
|||
BQueueSize: 16000 # must be larger than OIDBatchSize; recommended to be 2*OIDBatchSize or 3*OIDBatchSize
|
||||
SkipIndexFilesSearch: false
|
||||
IndexFileSize: 128000
|
||||
ContainerID: "87JRc7vyWcjW8uS32LMoLTAj4ckCzFZWfKbacjU3sAob"
|
||||
ContainerID: "A8nGtDemWrm2SjfcGAG6wvrxmXwqc5fwr8ezNDm6FraT"
|
||||
BlockAttribute: "Block"
|
||||
IndexFileAttribute: "Index"
|
||||
|
|
|
@ -22,6 +22,7 @@ ProtocolConfiguration:
|
|||
Basilisk: 6
|
||||
Cockatrice: 9
|
||||
Domovoi: 12
|
||||
Echidna: 13
|
||||
|
||||
ApplicationConfiguration:
|
||||
SkipBlockVerification: false
|
||||
|
|
|
@ -73,39 +73,16 @@ parameter.
|
|||
Once all blocks available in the NeoFS container are processed, the service
|
||||
shuts down automatically.
|
||||
|
||||
### NeoFS Upload Command
|
||||
The `upload-bin` command is designed to fetch blocks from the RPC node and upload
|
||||
them to the NeoFS container.
|
||||
It also creates and uploads index files. Below is an example usage of the command:
|
||||
### NeoFS block uploading command
|
||||
The `util upload-bin` command is designed to fetch blocks from the RPC node and upload
|
||||
them to the NeoFS container. It also creates and uploads index files. Below is an
|
||||
example usage of the command:
|
||||
|
||||
```shell
|
||||
./bin/neo-go util upload-bin --cid 9iVfUg8aDHKjPC4LhQXEkVUM4HDkR7UCXYLs8NQwYfSG --wallet-config ./wallet-config.yml --block-attribute Block --index-attribute Index --rpc-endpoint https://rpc.t5.n3.nspcc.ru:20331 -fsr st1.t5.fs.neo.org:8080 -fsr st2.t5.fs.neo.org:8080 -fsr st3.t5.fs.neo.org:8080
|
||||
```
|
||||
The command supports the following options:
|
||||
```
|
||||
NAME:
|
||||
neo-go util upload-bin - Fetch blocks from RPC node and upload them to the NeoFS container
|
||||
|
||||
USAGE:
|
||||
neo-go util upload-bin --fs-rpc-endpoint <address1>[,<address2>[...]] --container <cid> --block-attribute block --index-attribute index --rpc-endpoint <node> [--timeout <time>] --wallet <wallet> [--wallet-config <config>] [--address <address>] [--workers <num>] [--searchers <num>] [--index-file-size <size>] [--retries <num>] [--debug]
|
||||
|
||||
OPTIONS:
|
||||
--fs-rpc-endpoint value, --fsr value [ --fs-rpc-endpoint value, --fsr value ] List of NeoFS storage node RPC addresses (comma-separated or multiple --fs-rpc-endpoint flags)
|
||||
--container value, --cid value NeoFS container ID to upload blocks to
|
||||
--block-attribute value Attribute key of the block object
|
||||
--index-attribute value Attribute key of the index file object
|
||||
--address value Address to use for signing the uploading and searching transactions in NeoFS
|
||||
--index-file-size value Size of index file (default: 128000)
|
||||
--workers value Number of workers to fetch, upload and search blocks concurrently (default: 50)
|
||||
--searchers value Number of concurrent searches for blocks (default: 20)
|
||||
--retries value Maximum number of Neo/NeoFS node request retries (default: 5)
|
||||
--debug, -d Enable debug logging (LOTS of output, overrides configuration) (default: false)
|
||||
--rpc-endpoint value, -r value RPC node address
|
||||
--timeout value, -s value Timeout for the operation (default: 10s)
|
||||
--wallet value, -w value Wallet to use to get the key for transaction signing; conflicts with --wallet-config flag
|
||||
--wallet-config value Path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag
|
||||
--help, -h show help
|
||||
```
|
||||
Run `./bin/neo-go util upload-bin --help` to see the full list of supported options.
|
||||
|
||||
This command works as follows:
|
||||
1. Fetches the current block height from the RPC node.
|
||||
|
@ -117,10 +94,33 @@ This command works as follows:
|
|||
7. Repeats steps 4-6 until the current block height is reached.
|
||||
|
||||
If the command is interrupted, it can be resumed. It starts the uploading process
|
||||
from the last uploaded index file.
|
||||
from the last uploaded index file.
|
||||
|
||||
For a given block sequence, only one type of index file is supported. If new index
|
||||
files are needed (different `index-file-size` or `index-attribute`), the entire
|
||||
block sequence must be uploaded from the beginning. Please, add a comment to the
|
||||
files are needed (different `index-file-size` or `index-attribute`), `upload-bin`
|
||||
will upload the entire block sequence starting from genesis since no migration is
|
||||
supported yet by this command. Please, add a comment to the
|
||||
[#3744](https://github.com/nspcc-dev/neo-go/issues/3744) issue if you need this
|
||||
functionality.
|
||||
functionality.
|
||||
|
||||
### NeoFS state uploading command
|
||||
The `util upload-state` command is used to start a node, traverse the MPT over the
|
||||
smart contract storage, and upload MPT nodes to a NeoFS container at every
|
||||
`StateSyncInterval` number of blocks. Below is an example usage of the command:
|
||||
|
||||
```shell
|
||||
./bin/neo-go util upload-state --cid 9iVfUg8aDHKjPC4LhQXEkVUM4HDkR7UCXYLs8NQwYfSG --wallet-config ./wallet-config.yml --state-attribute State -m -fsr st1.t5.fs.neo.org:8080 -fsr st2.t5.fs.neo.org:8080 -fsr st3.t5.fs.neo.org:8080
|
||||
```
|
||||
|
||||
Run `./bin/neo-go util upload-state --help` to see the full list of supported options.
|
||||
|
||||
This command works as follows:
|
||||
1. Searches for the state objects stored in NeoFS to find the latest uploaded object.
|
||||
2. Checks if new state objects could be uploaded given the current local state height.
|
||||
3. Traverses the MPT nodes (pre-order) starting from the stateroot at the height of the
|
||||
latest uploaded state object down to its children.
|
||||
4. Uploads the MPT nodes to the NeoFS container.
|
||||
5. Repeats steps 3-4 with a step equal to the `StateSyncInterval` number of blocks.
|
||||
|
||||
If the command is interrupted, it can be resumed. It starts the uploading process
|
||||
from the last uploaded state object.
|
|
@ -18,7 +18,7 @@ node-related settings described in the table below.
|
|||
| --- | --- | --- | --- |
|
||||
| DBConfiguration | [DB Configuration](#DB-Configuration) | | Describes configuration for database. See the [DB Configuration](#DB-Configuration) section for details. |
|
||||
| LogLevel | `string` | "info" | Minimal logged messages level (can be "debug", "info", "warn", "error", "dpanic", "panic" or "fatal"). |
|
||||
| GarbageCollectionPeriod | `uint32` | 10000 | Controls MPT garbage collection interval (in blocks) for configurations with `RemoveUntraceableBlocks` enabled and `KeepOnlyLatestState` disabled. In this mode the node stores a number of MPT trees (corresponding to `MaxTraceableBlocks` and `StateSyncInterval`), but the DB needs to be clean from old entries from time to time. Doing it too often will cause too much processing overhead, doing it too rarely will leave more useless data in the DB. |
|
||||
| GarbageCollectionPeriod | `uint32` | 10000 | Controls MPT garbage collection interval (in blocks) for configurations with `RemoveUntraceableBlocks` enabled and `KeepOnlyLatestState` disabled. In this mode the node stores a number of MPT trees (corresponding to `MaxTraceableBlocks` and `StateSyncInterval`), but the DB needs to be clean from old entries from time to time. Doing it too often will cause too much processing overhead (it requires going through the whole DB which can take minutes), doing it too rarely will leave more useless data in the DB. Always compare this to `MaxTraceableBlocks`, values lower than 10% of it are likely too low, values higher than 50% are likely to leave more garbage than is possible to collect. The default value is more aligned with NeoFS networks that have low MTB values, but for N3 mainnet it's too low. |
|
||||
| KeepOnlyLatestState | `bool` | `false` | Specifies if MPT should only store the latest state (or a set of latest states, see `P2PStateExchangeExtensions` section in the ProtocolConfiguration for details). If true, DB size will be smaller, but older roots won't be accessible. This value should remain the same for the same database. | |
|
||||
| LogPath | `string` | "", so only console logging | File path where to store node logs. |
|
||||
| NeoFSBlockFetcher | [NeoFS BlockFetcher Configuration](#NeoFS-BlockFetcher-Configuration) | | NeoFS BlockFetcher module configuration. See the [NeoFS BlockFetcher Configuration](#NeoFS-BlockFetcher-Configuration) section for details. |
|
||||
|
@ -35,6 +35,7 @@ node-related settings described in the table below.
|
|||
| SaveStorageBatch | `bool` | `false` | Enables storage batch saving before every persist. It is similar to StorageDump plugin for C# node. |
|
||||
| SkipBlockVerification | `bool` | `false` | Allows to disable verification of received/processed blocks (including cryptographic checks). |
|
||||
| StateRoot | [State Root Configuration](#State-Root-Configuration) | | State root module configuration. See the [State Root Configuration](#State-Root-Configuration) section for details. |
|
||||
| SaveInvocations | `bool` | `false` | Determines if additional smart contract invocation details are stored. If enabled, the `getapplicationlog` RPC method will return a new field with invocation details for the transaction. See the [RPC](rpc.md#applicationlog-invocations) documentation for more information. |
|
||||
|
||||
### P2P Configuration
|
||||
|
||||
|
@ -100,7 +101,12 @@ DBConfiguration:
|
|||
```
|
||||
where:
|
||||
- `Type` is the database type (string value). Supported types: `leveldb`, `boltdb` and
|
||||
`inmemory` (not recommended for production usage).
|
||||
`inmemory` (not recommended for production usage). LevelDB is better for archive nodes
|
||||
that store all data, it better deals with writes in general, but any tail-cutting node
|
||||
options seriously degrade its performance. BoltDB works much better in various
|
||||
performance tests, however it can seriously degrade GC in case the DB size is bigger
|
||||
than the amount of available memory. BoltDB is also more memory-demanding for some
|
||||
operations, so GC can be problematic from that angle as well.
|
||||
- `LevelDBOptions` are settings for LevelDB. Includes the DB files path and ReadOnly mode toggle.
|
||||
If ReadOnly mode is on, then an error will be returned on attempt to connect to unexisting or empty
|
||||
database. Database doesn't allow changes in this mode, a warning will be logged on DB persist attempts.
|
||||
|
@ -245,6 +251,7 @@ RPC:
|
|||
MaxRequestBodyBytes: 5242880
|
||||
MaxRequestHeaderBytes: 1048576
|
||||
MaxWebSocketClients: 64
|
||||
MaxWebSocketFeeds: 16
|
||||
SessionEnabled: false
|
||||
SessionExpirationTime: 15
|
||||
SessionBackedByMPT: false
|
||||
|
@ -290,6 +297,9 @@ where:
|
|||
number (64 by default). Attempts to establish additional connections will
|
||||
lead to websocket handshake failures. Use "-1" to disable websocket
|
||||
connections (0 will lead to using the default value).
|
||||
- `MaxWebSocketFeeds` -- the maximum simultaneous event subscriptions number
|
||||
for a single client (16 by default). Attemps to create additional subscriptions
|
||||
will lead to error.
|
||||
- `SessionEnabled` denotes whether session-based iterator JSON-RPC API is enabled.
|
||||
If true, then all iterators got from `invoke*` calls will be stored as sessions
|
||||
on the server side available for further traverse. `traverseiterator` and
|
||||
|
@ -470,7 +480,7 @@ in development and can change in an incompatible way.
|
|||
| `Basilisk` | Enables strict smart contract script check against a set of JMP instructions and against method boundaries enabled on contract deploy or update. Increases `stackitem.Integer` JSON parsing precision up to the maximum value supported by the NeoVM. Enables strict check for notifications emitted by a contract to precisely match the events specified in the contract manifest. | https://github.com/nspcc-dev/neo-go/pull/3056 <br> https://github.com/neo-project/neo/pull/2881 <br> https://github.com/nspcc-dev/neo-go/pull/3080 <br> https://github.com/neo-project/neo/pull/2883 <br> https://github.com/nspcc-dev/neo-go/pull/3085 <br> https://github.com/neo-project/neo/pull/2810 |
|
||||
| `Cockatrice` | Introduces the ability to update native contracts. Includes a couple of new native smart contract APIs: `keccak256` of native CryptoLib contract and `getCommitteeAddress` of native NeoToken contract. | https://github.com/nspcc-dev/neo-go/pull/3402 <br> https://github.com/neo-project/neo/pull/2942 <br> https://github.com/nspcc-dev/neo-go/pull/3301 <br> https://github.com/neo-project/neo/pull/2925 <br> https://github.com/nspcc-dev/neo-go/pull/3362 <br> https://github.com/neo-project/neo/pull/3154 |
|
||||
| `Domovoi` | Makes node use executing contract state for the contract call permissions check instead of the state stored in the native Management contract. In C# also makes System.Runtime.GetNotifications interop properly count stack references of notification parameters which prevents users from creating objects that exceed MaxStackSize constraint, but NeoGo has never had this bug, thus proper behaviour is preserved even before HFDomovoi. It results in the fact that some T5 testnet transactions have different ApplicationLogs compared to the C# node, but the node states match. | https://github.com/nspcc-dev/neo-go/pull/3476 <br> https://github.com/neo-project/neo/pull/3290 <br> https://github.com/nspcc-dev/neo-go/pull/3473 <br> https://github.com/neo-project/neo/pull/3290 <br> https://github.com/neo-project/neo/pull/3301 <br> https://github.com/nspcc-dev/neo-go/pull/3485 |
|
||||
| `Echidna` | No changes for now | https://github.com/nspcc-dev/neo-go/pull/3554 |
|
||||
| `Echidna` | Introduces `Designation` event extension with `Old` and `New` roles data to native RoleManagement contract. Adds support for `base64UrlEncode` and `base64UrlDecode` methods to native StdLib contract. Extends the list of required call flags for `registerCandidate`, `unregisterCandidate`and `vote` methods of native NeoToken contract with AllowNotify flag. Enables `onNEP17Payment` method of NEO contract for candidate registration. Introduces constraint for maximum number of execution notifications. | https://github.com/nspcc-dev/neo-go/pull/3554 <br> https://github.com/nspcc-dev/neo-go/pull/3761 <br> https://github.com/nspcc-dev/neo-go/pull/3554 <br> https://github.com/neo-project/neo/pull/3597 <br> https://github.com/nspcc-dev/neo-go/pull/3700 <br> https://github.com/nspcc-dev/neo-go/pull/3640 <br> https://github.com/neo-project/neo/pull/3548 |
|
||||
|
||||
|
||||
## DB compatibility
|
||||
|
@ -490,6 +500,7 @@ affect this:
|
|||
- `GarbageCollectionPeriod` must be the same
|
||||
- `KeepOnlyLatestState` must be the same
|
||||
- `RemoveUntraceableBlocks` must be the same
|
||||
- `SaveInvocations` must be the same
|
||||
|
||||
BotlDB is also known to be incompatible between machines with different
|
||||
endianness. Nothing is known for LevelDB wrt this, so it's not recommended
|
||||
|
|
|
@ -58,6 +58,9 @@ method. Upon successful subscription, clients receive subscription ID for
|
|||
subsequent management of this subscription. Subscription is only valid for
|
||||
connection lifetime, no long-term client identification is being made.
|
||||
|
||||
The maximum number of simultaneous subscriptions can be set server-side
|
||||
via `MaxWebSocketFeeds` setting.
|
||||
|
||||
Errors are not described down below, but they can be returned as standard
|
||||
JSON-RPC errors (most often caused by invalid parameters).
|
||||
|
||||
|
|
65
docs/rpc.md
65
docs/rpc.md
|
@ -248,6 +248,15 @@ block. It can be removed in future versions, but at the moment you can use it
|
|||
to see how much GAS is burned with a particular block (because system fees are
|
||||
burned).
|
||||
|
||||
#### `getblocknotifications` call
|
||||
|
||||
This method returns notifications from a block organized by trigger type.
|
||||
Supports filtering by contract and event name (the same filter as provided
|
||||
for subscriptions to execution results, see [notifications specification](notifications.md).
|
||||
The resulting JSON is an object with three (if matched) field: "onpersist",
|
||||
"application" and "postpersist" containing arrays of notifications (same JSON
|
||||
as used in notification service) for the respective triggers.
|
||||
|
||||
#### Historic calls
|
||||
|
||||
A set of `*historic` extension methods provide the ability of interacting with
|
||||
|
@ -356,6 +365,62 @@ to various blockchain events (with simple event filtering) and receive them on
|
|||
the client as JSON-RPC notifications. More details on that are written in the
|
||||
[notifications specification](notifications.md).
|
||||
|
||||
#### `applicationlog` call invocations
|
||||
|
||||
The `SaveInvocations` configuration setting causes the RPC server to store smart contract
|
||||
invocation details as part of the application logs. This feature is specifically useful to
|
||||
capture information in the absence of `System.Runtime.Notify` calls for the given smart
|
||||
contract method. Other use-cases are described in [this issue](https://github.com/neo-project/neo/issues/3386).
|
||||
|
||||
Example transaction on Testnet which interacts with the native PolicyContract:
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"txid": "0xd6fe5f61d9cb34d6324db1be42c056d02ba1f1f6cd0bd3f3c6bb24faaaeef2a9",
|
||||
"executions": [
|
||||
{
|
||||
"trigger": "Application",
|
||||
"vmstate": "HALT",
|
||||
"gasconsumed": "2028120",
|
||||
"stack": [
|
||||
{
|
||||
"type": "Any"
|
||||
}
|
||||
],
|
||||
"notifications": [],
|
||||
"exception": null,
|
||||
"invocations": [
|
||||
{
|
||||
"hash": "0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b",
|
||||
"method": "setFeePerByte",
|
||||
"arguments": {
|
||||
"type": "Array",
|
||||
"value": [
|
||||
{
|
||||
"type": "Integer",
|
||||
"value": "100"
|
||||
}
|
||||
]
|
||||
},
|
||||
"argumentscount": 1,
|
||||
"truncated": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For security reasons the `arguments` field data may result in `null` if the count exceeds 2048.
|
||||
In such case the `Truncated` field will be set to `true`.
|
||||
|
||||
The invocation records are presented in a flat structure in the order as how they were executed.
|
||||
Note that invocation records for faulted transactions are kept and are present in the
|
||||
applicationlog. This behaviour differs from notifications which are omitted for faulted transactions.
|
||||
|
||||
## Reference
|
||||
|
||||
* [JSON-RPC 2.0 Specification](http://www.jsonrpc.org/specification)
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: "NeoFS Object NFT"
|
||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||
supportedstandards: ["NEP-11", "NEP-24"]
|
||||
supportedstandards: ["NEP-11", "NEP-24", "NEP-27"]
|
||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "properties", "tokens", "royaltyInfo"]
|
||||
events:
|
||||
- name: Transfer
|
||||
|
|
|
@ -3,13 +3,13 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd-nns
|
|||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/nspcc-dev/neo-go v0.106.4-0.20241016130346-d8e945978af6
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
github.com/nspcc-dev/neo-go v0.107.3-0.20241223145705-86b2493edd6a
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
github.com/stretchr/testify v1.9.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.14.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
|
@ -18,7 +18,6 @@ require (
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
|
@ -28,11 +27,11 @@ require (
|
|||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b // 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/neofs-sdk-go v1.0.0-rc.12 // indirect
|
||||
github.com/nspcc-dev/hrw/v2 v2.0.2 // indirect
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea // indirect
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20241205083504-335d9fe90f24 // indirect
|
||||
github.com/nspcc-dev/rfc6979 v0.2.3 // indirect
|
||||
github.com/nspcc-dev/tzhash v1.7.2 // indirect
|
||||
github.com/nspcc-dev/tzhash v1.8.2 // indirect
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.20.2 // indirect
|
||||
|
@ -57,8 +56,8 @@ require (
|
|||
golang.org/x/term v0.27.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
|
||||
google.golang.org/grpc v1.65.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
|
||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bits-and-blooms/bitset v1.14.2 h1:YXVoyPndbdvcEVcseEovVfp0qjJp7S+i5+xgp/Nfbdc=
|
||||
github.com/bits-and-blooms/bitset v1.14.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
||||
|
@ -12,17 +20,43 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj
|
|||
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
|
||||
github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E=
|
||||
github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0=
|
||||
github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao=
|
||||
github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
|
||||
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
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.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
|
||||
github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
|
||||
github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
|
@ -30,15 +64,11 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
|
|||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
|
@ -61,31 +91,47 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4=
|
||||
github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
|
||||
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
|
||||
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
|
||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
|
||||
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
|
||||
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nspcc-dev/dbft v0.3.0 h1:P9dFQje43sabA6w89l1OqGe1BvnO7DdHcu27w6mfnOE=
|
||||
github.com/nspcc-dev/dbft v0.3.0/go.mod h1:oFE6paSC/yfFh9mcNU6MheMGOYXK9+sPiRk3YMoz49o=
|
||||
github.com/nspcc-dev/dbft v0.3.1 h1:3qoc65CVJMtdL/627JZH+1Jz839LmdsVN52L4mlP5z8=
|
||||
github.com/nspcc-dev/dbft v0.3.1/go.mod h1:BNvJkPKTE28r+qRaAk2C3VoL2J9qzox3fvEeJbh7EWE=
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b h1:DRG4cRqIOmI/nUPggMgR92Jxt63Lxsuz40m5QpdvYXI=
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b/go.mod h1:d3cUseu4Asxfo9/QA/w4TtGjM0AbC9ynyab+PfH+Bso=
|
||||
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 v0.106.4-0.20241016130346-d8e945978af6 h1:3/V1U2ZgbFZQ5xGjTD9NMsz4NHzPy/nYJzcaHDVDu88=
|
||||
github.com/nspcc-dev/neo-go v0.106.4-0.20241016130346-d8e945978af6/go.mod h1:ds91T4WJwtk7eWUo0fuVC36HpTQKkkdj5AjNxbjXAR0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
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/hrw/v2 v2.0.2 h1:Vuc2Yu96MCv1YDUjErMuCt5tq+g/43/Y89u/XfyLkRI=
|
||||
github.com/nspcc-dev/hrw/v2 v2.0.2/go.mod h1:XRsG20axGJfr0Ytcau/UcZ/9NF54RmUIqmoYKuuliSo=
|
||||
github.com/nspcc-dev/neo-go v0.107.3-0.20241223145705-86b2493edd6a h1:n9jfbHsFb2H4DsZgwsVfQcvFB4+3EROmJruz8GYlIHM=
|
||||
github.com/nspcc-dev/neo-go v0.107.3-0.20241223145705-86b2493edd6a/go.mod h1:hng8Bi42di31z1nXtWOboiJYwuZSgb2Wjd68peBIy8I=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea h1:mK0EMGLvunXcFyq7fBURS/CsN4MH+4nlYiqn6pTwWAU=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea/go.mod h1:YzhD4EZmC9Z/PNyd7ysC7WXgIgURc9uCG1UWDeV027Y=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20241205083504-335d9fe90f24 h1:+6KYoXnhs6LfGnn5f+4puuOj3M3MeofBw9iQn7LFG04=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20241205083504-335d9fe90f24/go.mod h1:INZZXiTr9L7gWFeg3RBuB1laH2h9+vnomvg1XE42zQU=
|
||||
github.com/nspcc-dev/rfc6979 v0.2.3 h1:QNVykGZ3XjFwM/88rGfV3oj4rKNBy+nYI6jM7q19hDI=
|
||||
github.com/nspcc-dev/rfc6979 v0.2.3/go.mod h1:q3sCL1Ed7homjqYK8KmFSzEmm+7Ngyo7PePbZanhaDE=
|
||||
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/nspcc-dev/tzhash v1.8.2 h1:ebRCbPoEuoqrhC6sSZmrT/jI3h1SzCWakxxV6gp5QAg=
|
||||
github.com/nspcc-dev/tzhash v1.8.2/go.mod h1:SFwvvB1KyKm45vdWpcOCFpklkUEsXtddnHsk+zq298g=
|
||||
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=
|
||||
|
@ -95,10 +141,18 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
|
|||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
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/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=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
|
||||
github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
|
@ -111,18 +165,40 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN
|
|||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
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/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
|
||||
github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
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=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
|
||||
github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
|
||||
github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
|
||||
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||
github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8=
|
||||
github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
|
||||
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
||||
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
|
||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
|
@ -170,18 +246,16 @@ golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ
|
|||
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-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/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
||||
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=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: "HASHY NFT"
|
||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||
supportedstandards: ["NEP-11", "NEP-24"]
|
||||
supportedstandards: ["NEP-11", "NEP-24", "NEP-27"]
|
||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "tokens", "properties", "royaltyInfo"]
|
||||
events:
|
||||
- name: Transfer
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -3,18 +3,18 @@ module github.com/nspcc-dev/neo-go/examples/zkp/cubic
|
|||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/consensys/gnark v0.11.0
|
||||
github.com/consensys/gnark-crypto v0.14.0
|
||||
github.com/consensys/gnark v0.12.0
|
||||
github.com/consensys/gnark-crypto v0.15.0
|
||||
github.com/nspcc-dev/neo-go v0.106.3
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.14.2 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.20.0 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/consensys/bavard v0.1.13 // indirect
|
||||
github.com/consensys/bavard v0.1.27 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||
|
@ -25,14 +25,13 @@ require (
|
|||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/holiman/uint256 v1.2.4 // indirect
|
||||
github.com/ingonyama-zk/icicle v1.1.0 // indirect
|
||||
github.com/ingonyama-zk/iciclegnark v0.1.0 // indirect
|
||||
github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
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-20240301084351-0246b013f8b2 // indirect
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 // indirect
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 // indirect
|
||||
github.com/nspcc-dev/rfc6979 v0.2.1 // indirect
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
|
@ -51,13 +50,13 @@ require (
|
|||
go.etcd.io/bbolt v1.3.9 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.26.0 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/term v0.23.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/term v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
|
@ -2,20 +2,20 @@ github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h
|
|||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bits-and-blooms/bitset v1.14.2 h1:YXVoyPndbdvcEVcseEovVfp0qjJp7S+i5+xgp/Nfbdc=
|
||||
github.com/bits-and-blooms/bitset v1.14.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU=
|
||||
github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
|
||||
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
|
||||
github.com/consensys/gnark v0.11.0 h1:YlndnlbRAoIEA+aIIHzNIW4P0dCIOM9/jCVzsXf356c=
|
||||
github.com/consensys/gnark v0.11.0/go.mod h1:2LbheIOxsBI1a9Ck1XxUoy6PRnH28mSI9qrvtN2HwDY=
|
||||
github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E=
|
||||
github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0=
|
||||
github.com/consensys/bavard v0.1.27 h1:j6hKUrGAy/H+gpNrpLU3I26n1yc+VMGmd6ID5+gAhOs=
|
||||
github.com/consensys/bavard v0.1.27/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
|
||||
github.com/consensys/gnark v0.12.0 h1:XgQ1kh2R6fHuf5fBYl+i7TxR+QTbGQuZaaqqkk5nLO0=
|
||||
github.com/consensys/gnark v0.12.0/go.mod h1:WDvuIQ8qrRvWT9NhTrib84WeLVBSGhSTrbQBXs1yR5w=
|
||||
github.com/consensys/gnark-crypto v0.15.0 h1:OXsWnhheHV59eXIzhL5OIexa/vqTK8wtRYQCtwfMDtY=
|
||||
github.com/consensys/gnark-crypto v0.15.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
|
@ -59,10 +59,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyf
|
|||
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
|
||||
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ingonyama-zk/icicle v1.1.0 h1:a2MUIaF+1i4JY2Lnb961ZMvaC8GFs9GqZgSnd9e95C8=
|
||||
github.com/ingonyama-zk/icicle v1.1.0/go.mod h1:kAK8/EoN7fUEmakzgZIYdWy1a2rBnpCaZLqSHwZWxEk=
|
||||
github.com/ingonyama-zk/iciclegnark v0.1.0 h1:88MkEghzjQBMjrYRJFxZ9oR9CTIpB8NG2zLeCJSvXKQ=
|
||||
github.com/ingonyama-zk/iciclegnark v0.1.0/go.mod h1:wz6+IpyHKs6UhMMoQpNqz1VY+ddfKqC/gRwR/64W6WU=
|
||||
github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b h1:AvQTK7l0PTHODD06PVQX1Tn2o29sRIaKIDOvTJmKurY=
|
||||
github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b/go.mod h1:e0JHb27/P6WorCJS3YolbY5XffS4PGBuoW38OthLkDs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
|
@ -90,8 +88,8 @@ github.com/nspcc-dev/hrw/v2 v2.0.1 h1:CxYUkBeJvNfMEn2lHhrV6FjY8pZPceSxXUtMVq0BUO
|
|||
github.com/nspcc-dev/hrw/v2 v2.0.1/go.mod h1:iZAs5hT2q47EGq6AZ0FjaUI6ggntOi7vrY4utfzk5VA=
|
||||
github.com/nspcc-dev/neo-go v0.106.3 h1:HEyhgkjQY+HfBzotMJ12xx2VuOUphkngZ4kEkjvXDtE=
|
||||
github.com/nspcc-dev/neo-go v0.106.3/go.mod h1:3vEwJ2ld12N7HRGCaH/l/7EwopplC/+8XdIdPDNmD/M=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
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=
|
||||
|
@ -131,8 +129,8 @@ github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
|||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
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/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM=
|
||||
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
|
||||
|
@ -153,8 +151,8 @@ 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.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
|
@ -166,8 +164,8 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R
|
|||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -180,15 +178,15 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
|
||||
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/zkp/xor
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
6
go.mod
6
go.mod
|
@ -13,9 +13,9 @@ require (
|
|||
github.com/holiman/uint256 v1.3.1
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/mr-tron/base58 v1.2.0
|
||||
github.com/nspcc-dev/dbft v0.3.1
|
||||
github.com/nspcc-dev/dbft v0.3.2
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20241205083504-335d9fe90f24
|
||||
github.com/nspcc-dev/rfc6979 v0.2.3
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible
|
||||
|
@ -30,7 +30,6 @@ require (
|
|||
golang.org/x/term v0.27.0
|
||||
golang.org/x/text v0.21.0
|
||||
golang.org/x/tools v0.24.0
|
||||
google.golang.org/grpc v1.65.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
|
@ -73,6 +72,7 @@ require (
|
|||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
|
||||
google.golang.org/grpc v1.65.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
)
|
||||
|
|
8
go.sum
8
go.sum
|
@ -142,14 +142,14 @@ 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nspcc-dev/dbft v0.3.1 h1:3qoc65CVJMtdL/627JZH+1Jz839LmdsVN52L4mlP5z8=
|
||||
github.com/nspcc-dev/dbft v0.3.1/go.mod h1:BNvJkPKTE28r+qRaAk2C3VoL2J9qzox3fvEeJbh7EWE=
|
||||
github.com/nspcc-dev/dbft v0.3.2 h1:8AFRpV6JZFn1kEPJB7fVQKUm06PzJ69jFxSdOhTEfJo=
|
||||
github.com/nspcc-dev/dbft v0.3.2/go.mod h1:tpBE0IRebgucPzKGGxv2Iy7s4knpKqODv157Gc/m1RE=
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b h1:DRG4cRqIOmI/nUPggMgR92Jxt63Lxsuz40m5QpdvYXI=
|
||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240830112754-291b000d1f3b/go.mod h1:d3cUseu4Asxfo9/QA/w4TtGjM0AbC9ynyab+PfH+Bso=
|
||||
github.com/nspcc-dev/hrw/v2 v2.0.2 h1:Vuc2Yu96MCv1YDUjErMuCt5tq+g/43/Y89u/XfyLkRI=
|
||||
github.com/nspcc-dev/hrw/v2 v2.0.2/go.mod h1:XRsG20axGJfr0Ytcau/UcZ/9NF54RmUIqmoYKuuliSo=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea h1:mK0EMGLvunXcFyq7fBURS/CsN4MH+4nlYiqn6pTwWAU=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea/go.mod h1:YzhD4EZmC9Z/PNyd7ysC7WXgIgURc9uCG1UWDeV027Y=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20241205083504-335d9fe90f24 h1:+6KYoXnhs6LfGnn5f+4puuOj3M3MeofBw9iQn7LFG04=
|
||||
|
|
|
@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/internal/examples/oracle
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6 h1:rTnsU+Y/bP1bLN/SNWmOKEexmSeniMQe5bOJxXNbXgg=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241212130705-ea0a6114d2d6/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
||||
|
|
|
@ -49,6 +49,11 @@ type FakeStateSync struct {
|
|||
AddMPTNodesFunc func(nodes [][]byte) error
|
||||
}
|
||||
|
||||
// HeaderHeight returns the height of the latest stored header.
|
||||
func (s *FakeStateSync) HeaderHeight() uint32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// NewFakeChain returns a new FakeChain structure.
|
||||
func NewFakeChain() *FakeChain {
|
||||
return NewFakeChainWithCustomCfg(nil)
|
||||
|
@ -447,6 +452,9 @@ func (s *FakeStateSync) Init(currChainHeight uint32) error {
|
|||
// NeedHeaders implements the StateSync interface.
|
||||
func (s *FakeStateSync) NeedHeaders() bool { return s.RequestHeaders.Load() }
|
||||
|
||||
// NeedBlocks implements the StateSync interface.
|
||||
func (s *FakeStateSync) NeedBlocks() bool { return false }
|
||||
|
||||
// NeedMPTNodes implements the StateSync interface.
|
||||
func (s *FakeStateSync) NeedMPTNodes() bool {
|
||||
panic("TODO")
|
||||
|
@ -464,3 +472,13 @@ func (s *FakeStateSync) Traverse(root util.Uint256, process func(node mpt.Node,
|
|||
func (s *FakeStateSync) GetUnknownMPTNodesBatch(limit int) []util.Uint256 {
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
// GetConfig implements the StateSync interface.
|
||||
func (s *FakeStateSync) GetConfig() config.Blockchain {
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
// SetOnStageChanged implements the StateSync interface.
|
||||
func (s *FakeStateSync) SetOnStageChanged(func()) {
|
||||
panic("TODO")
|
||||
}
|
||||
|
|
|
@ -468,12 +468,12 @@ func CreateManifest(di *DebugInfo, o *Options) (*manifest.Manifest, error) {
|
|||
return m, err
|
||||
}
|
||||
if m.ABI.GetMethod(manifest.MethodOnNEP11Payment, -1) != nil {
|
||||
if err := standard.CheckABI(m, manifest.NEP11Payable); err != nil {
|
||||
if err := standard.CheckABI(m, manifest.NEP26StandardName); err != nil {
|
||||
return m, err
|
||||
}
|
||||
}
|
||||
if m.ABI.GetMethod(manifest.MethodOnNEP17Payment, -1) != nil {
|
||||
if err := standard.CheckABI(m, manifest.NEP17Payable); err != nil {
|
||||
if err := standard.CheckABI(m, manifest.NEP27StandardName); err != nil {
|
||||
return m, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ func (c Config) Blockchain() Blockchain {
|
|||
return Blockchain{
|
||||
ProtocolConfiguration: c.ProtocolConfiguration,
|
||||
Ledger: c.ApplicationConfiguration.Ledger,
|
||||
NeoFSBlockFetcher: c.ApplicationConfiguration.NeoFSBlockFetcher,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,8 @@ const (
|
|||
// match. See #3485 for details.
|
||||
HFDomovoi // Domovoi
|
||||
// HFEchidna represents hard-fork introduced in #3554 (ported from
|
||||
// https://github.com/neo-project/neo/pull/3454).
|
||||
// https://github.com/neo-project/neo/pull/3454), #3640 (ported from
|
||||
// https://github.com/neo-project/neo/pull/3548).
|
||||
HFEchidna // Echidna
|
||||
// hfLast denotes the end of hardforks enum. Consider adding new hardforks
|
||||
// before hfLast.
|
||||
|
|
|
@ -22,6 +22,8 @@ type Ledger struct {
|
|||
// SkipBlockVerification allows to disable verification of received
|
||||
// blocks (including cryptographic checks).
|
||||
SkipBlockVerification bool `yaml:"SkipBlockVerification"`
|
||||
// SaveInvocations enables smart contract invocation data saving.
|
||||
SaveInvocations bool `yaml:"SaveInvocations"`
|
||||
}
|
||||
|
||||
// Blockchain is a set of settings for core.Blockchain to use, it includes protocol
|
||||
|
@ -29,4 +31,5 @@ type Ledger struct {
|
|||
type Blockchain struct {
|
||||
ProtocolConfiguration
|
||||
Ledger
|
||||
NeoFSBlockFetcher
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ type (
|
|||
P2PSigExtensions bool `yaml:"P2PSigExtensions"`
|
||||
// P2PStateExchangeExtensions enables additional P2P MPT state data exchange logic.
|
||||
P2PStateExchangeExtensions bool `yaml:"P2PStateExchangeExtensions"`
|
||||
// NeoFSStateSyncExtensions enables state data exchange logic via NeoFS.
|
||||
NeoFSStateSyncExtensions bool `yaml:"NeoFSStateSyncExtensions"`
|
||||
// ReservedAttributes allows to have reserved attributes range for experimental or private purposes.
|
||||
ReservedAttributes bool `yaml:"ReservedAttributes"`
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ type (
|
|||
MaxRequestBodyBytes int `yaml:"MaxRequestBodyBytes"`
|
||||
MaxRequestHeaderBytes int `yaml:"MaxRequestHeaderBytes"`
|
||||
MaxWebSocketClients int `yaml:"MaxWebSocketClients"`
|
||||
MaxWebSocketFeeds int `yaml:"MaxWebSocketFeeds"`
|
||||
SessionEnabled bool `yaml:"SessionEnabled"`
|
||||
SessionExpirationTime int `yaml:"SessionExpirationTime"`
|
||||
SessionBackedByMPT bool `yaml:"SessionBackedByMPT"`
|
||||
|
|
|
@ -58,7 +58,7 @@ type Ledger interface {
|
|||
|
||||
// BlockQueuer is an interface to the block queue manager sufficient for Service.
|
||||
type BlockQueuer interface {
|
||||
PutBlock(block *coreb.Block) error
|
||||
Put(queueable *coreb.Block) error
|
||||
}
|
||||
|
||||
// Service represents a consensus instance.
|
||||
|
@ -623,7 +623,7 @@ func (s *service) processBlock(b dbft.Block[util.Uint256]) error {
|
|||
bb := &b.(*neoBlock).Block
|
||||
bb.Script = *(s.getBlockWitness(bb))
|
||||
|
||||
if err := s.BlockQueue.PutBlock(bb); err != nil {
|
||||
if err := s.BlockQueue.Put(bb); err != nil {
|
||||
// The block might already be added via the regular network
|
||||
// interaction.
|
||||
if _, errget := s.Chain.GetBlock(bb.Hash()); errget != nil {
|
||||
|
|
|
@ -528,7 +528,7 @@ type testBlockQueuer struct {
|
|||
var _ = BlockQueuer(testBlockQueuer{})
|
||||
|
||||
// PutBlock implements BlockQueuer interface.
|
||||
func (bq testBlockQueuer) PutBlock(b *coreb.Block) error {
|
||||
func (bq testBlockQueuer) Put(b *coreb.Block) error {
|
||||
return bq.bc.AddBlock(b)
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,13 @@ type auxBlockIn struct {
|
|||
Transactions []json.RawMessage `json:"tx"`
|
||||
}
|
||||
|
||||
// GetIndex returns the index of the block. This method should be used
|
||||
// for interfaces only. As generics don't support structural types
|
||||
// ref. golang/go#51259.
|
||||
func (b *Block) GetIndex() uint32 {
|
||||
return b.Index
|
||||
}
|
||||
|
||||
// ComputeMerkleRoot computes Merkle tree root hash based on actual block's data.
|
||||
func (b *Block) ComputeMerkleRoot() util.Uint256 {
|
||||
hashes := make([]util.Uint256, len(b.Transactions))
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
|
@ -80,6 +81,13 @@ type baseAux struct {
|
|||
Witnesses []transaction.Witness `json:"witnesses"`
|
||||
}
|
||||
|
||||
// GetIndex returns the index of the block. This method should be used
|
||||
// for interfaces only. As generics don't support structural types
|
||||
// ref. golang/go#51259.
|
||||
func (b *Header) GetIndex() uint32 {
|
||||
return b.Index
|
||||
}
|
||||
|
||||
// Hash returns the hash of the block. Notice that it is cached internally,
|
||||
// so no matter how you change the [Header] after the first invocation of this
|
||||
// method it won't change. To get an updated hash in case you're changing
|
||||
|
@ -228,3 +236,31 @@ func (b *Header) UnmarshalJSON(data []byte) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetExpectedHeaderSize returns the expected Header size with the given number of validators.
|
||||
// To calculate genesis block Header size numOfValidators should be 0.
|
||||
func GetExpectedHeaderSize(stateRootInHeader bool, numOfValidators int) int {
|
||||
var size int
|
||||
// Genesis block case.
|
||||
if numOfValidators == 0 {
|
||||
// 1 byte for the PUSH1 opcode.
|
||||
size = expectedHeaderSizeWithEmptyWitness + 1
|
||||
} else {
|
||||
m := smartcontract.GetDefaultHonestNodeCount(numOfValidators)
|
||||
// expectedHeaderSizeWithEmptyWitness contains 2 bytes for zero-length (new(Header)).Script.Invocation/Verification
|
||||
// InvocationScript:
|
||||
// 64 is the size of the default signature length + 2 bytes length and opcode
|
||||
// 2 = 1 push opcode + 1 length
|
||||
// VerifcationScript:
|
||||
// m = 1 bytes
|
||||
// 33 = 1 push opcode + 1 length + 33 bytes for public key
|
||||
// n = 1 bytes
|
||||
// 5 for SYSCALL
|
||||
size = expectedHeaderSizeWithEmptyWitness + (1+1+64)*m + 2 + numOfValidators*(1+1+33) + 2 + 5
|
||||
}
|
||||
|
||||
if stateRootInHeader {
|
||||
size += util.Uint256Size
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
|
|
@ -61,7 +61,8 @@ const (
|
|||
defaultTimePerBlock = 15 * time.Second
|
||||
// HeaderVerificationGasLimit is the maximum amount of GAS for block header verification.
|
||||
HeaderVerificationGasLimit = 3_00000000 // 3 GAS
|
||||
defaultStateSyncInterval = 40000
|
||||
// DefaultStateSyncInterval is the default interval for state sync.
|
||||
DefaultStateSyncInterval = 40000
|
||||
|
||||
// defaultBlockTimesCache should be sufficient for tryRunGC() to get in
|
||||
// sync with storeBlock(). Most of the time they differ by some thousands of
|
||||
|
@ -70,6 +71,13 @@ const (
|
|||
// either, the next cycle will still do the job (only transfers need this,
|
||||
// MPT won't notice at all).
|
||||
defaultBlockTimesCache = 8
|
||||
|
||||
// persistSamples is the number of persist velocity samples to use for
|
||||
// storeBlock limit.
|
||||
persistSamples = 10
|
||||
// persistMinForSampling is the minimal number of keys to take persist
|
||||
// time into account wrt persist velocity.
|
||||
persistMinForSampling = 100
|
||||
)
|
||||
|
||||
// stateChangeStage denotes the stage of state modification process.
|
||||
|
@ -165,6 +173,14 @@ type Blockchain struct {
|
|||
// Current persisted block count.
|
||||
persistedHeight uint32
|
||||
|
||||
// keysPerPersist is the average number of persisted keys per persist
|
||||
// time limit.
|
||||
keysPerPersist uint32
|
||||
|
||||
// persistCond is signaled each time persist cycle ends, this wakes
|
||||
// storeBlock if needed (when it has too many queued blocks)
|
||||
persistCond *sync.Cond
|
||||
|
||||
// Index->Timestamp cache for garbage collector. Headers can be gone
|
||||
// by the time it runs, so we use a tiny little cache to sync block
|
||||
// removal (performed in storeBlock()) with transfer/MPT GC (tryRunGC())
|
||||
|
@ -284,6 +300,9 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
|
|||
log.Info("MaxValidUntilBlockIncrement is not set or wrong, using default value",
|
||||
zap.Uint32("MaxValidUntilBlockIncrement", cfg.MaxValidUntilBlockIncrement))
|
||||
}
|
||||
if cfg.P2PStateExchangeExtensions && cfg.NeoFSStateSyncExtensions {
|
||||
return nil, errors.New("P2PStateExchangeExtensions and NeoFSStateSyncExtensions cannot be enabled simultaneously")
|
||||
}
|
||||
if cfg.P2PStateExchangeExtensions {
|
||||
if !cfg.StateRootInHeader {
|
||||
return nil, errors.New("P2PStatesExchangeExtensions are enabled, but StateRootInHeader is off")
|
||||
|
@ -292,7 +311,17 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
|
|||
return nil, errors.New("P2PStateExchangeExtensions can be enabled either on MPT-complete node (KeepOnlyLatestState=false) or on light GC-enabled node (RemoveUntraceableBlocks=true)")
|
||||
}
|
||||
if cfg.StateSyncInterval <= 0 {
|
||||
cfg.StateSyncInterval = defaultStateSyncInterval
|
||||
cfg.StateSyncInterval = DefaultStateSyncInterval
|
||||
log.Info("StateSyncInterval is not set or wrong, using default value",
|
||||
zap.Int("StateSyncInterval", cfg.StateSyncInterval))
|
||||
}
|
||||
}
|
||||
if cfg.NeoFSStateSyncExtensions {
|
||||
if !cfg.NeoFSBlockFetcher.Enabled {
|
||||
return nil, errors.New("NeoFSStateSyncExtensions are enabled, but NeoFSBlockFetcher is off")
|
||||
}
|
||||
if cfg.StateSyncInterval <= 0 {
|
||||
cfg.StateSyncInterval = DefaultStateSyncInterval
|
||||
log.Info("StateSyncInterval is not set or wrong, using default value",
|
||||
zap.Int("StateSyncInterval", cfg.StateSyncInterval))
|
||||
}
|
||||
|
@ -338,6 +367,7 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
|
|||
contracts: *native.NewContracts(cfg.ProtocolConfiguration),
|
||||
}
|
||||
|
||||
bc.persistCond = sync.NewCond(&bc.lock)
|
||||
bc.gcBlockTimes, _ = lru.New[uint32, uint64](defaultBlockTimesCache) // Never errors for positive size
|
||||
bc.stateRoot = stateroot.NewModule(cfg, bc.VerifyWitness, bc.log, bc.dao.Store)
|
||||
bc.contracts.Designate.StateRootService = bc.stateRoot
|
||||
|
@ -435,6 +465,7 @@ func (bc *Blockchain) init() error {
|
|||
KeepOnlyLatestState: bc.config.Ledger.KeepOnlyLatestState,
|
||||
Magic: uint32(bc.config.Magic),
|
||||
Value: version,
|
||||
SaveInvocations: bc.config.SaveInvocations,
|
||||
}
|
||||
bc.dao.PutVersion(ver)
|
||||
bc.dao.Version = ver
|
||||
|
@ -472,6 +503,10 @@ func (bc *Blockchain) init() error {
|
|||
return fmt.Errorf("protocol configuration Magic mismatch (old=%v, new=%v)",
|
||||
ver.Magic, bc.config.Magic)
|
||||
}
|
||||
if ver.SaveInvocations != bc.config.SaveInvocations {
|
||||
return fmt.Errorf("SaveInvocations setting mismatch (old=%v, new=%v)",
|
||||
ver.SaveInvocations, bc.config.SaveInvocations)
|
||||
}
|
||||
bc.dao.Version = ver
|
||||
bc.persistent.Version = ver
|
||||
|
||||
|
@ -1088,7 +1123,7 @@ func (bc *Blockchain) isHardforkEnabled(hf *config.Hardfork, blockHeight uint32)
|
|||
hfs := bc.config.Hardforks
|
||||
if hf != nil {
|
||||
start, ok := hfs[hf.String()]
|
||||
if !ok || start < blockHeight {
|
||||
if !ok || start > blockHeight {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -1102,7 +1137,7 @@ func (bc *Blockchain) Run() {
|
|||
persistTimer := time.NewTimer(persistInterval)
|
||||
defer func() {
|
||||
persistTimer.Stop()
|
||||
if _, err := bc.persist(true); err != nil {
|
||||
if _, err := bc.persist(); err != nil {
|
||||
bc.log.Warn("failed to persist", zap.Error(err))
|
||||
}
|
||||
if err := bc.dao.Store.Close(); err != nil {
|
||||
|
@ -1112,27 +1147,24 @@ func (bc *Blockchain) Run() {
|
|||
close(bc.runToExitCh)
|
||||
}()
|
||||
go bc.notificationDispatcher()
|
||||
var nextSync bool
|
||||
for {
|
||||
select {
|
||||
case <-bc.stopCh:
|
||||
return
|
||||
case <-persistTimer.C:
|
||||
var oldPersisted uint32
|
||||
var gcDur time.Duration
|
||||
|
||||
if bc.config.Ledger.RemoveUntraceableBlocks {
|
||||
oldPersisted = atomic.LoadUint32(&bc.persistedHeight)
|
||||
}
|
||||
dur, err := bc.persist(nextSync)
|
||||
dur, err := bc.persist()
|
||||
if err != nil {
|
||||
bc.log.Warn("failed to persist blockchain", zap.Error(err))
|
||||
bc.log.Error("failed to persist blockchain", zap.Error(err))
|
||||
}
|
||||
if bc.config.Ledger.RemoveUntraceableBlocks {
|
||||
gcDur = bc.tryRunGC(oldPersisted)
|
||||
dur += bc.tryRunGC(oldPersisted)
|
||||
}
|
||||
nextSync = dur > persistInterval*2
|
||||
interval := persistInterval - dur - gcDur
|
||||
interval := persistInterval - dur
|
||||
interval = max(interval, time.Microsecond) // Reset doesn't work with zero or negative value.
|
||||
persistTimer.Reset(interval)
|
||||
}
|
||||
|
@ -1159,8 +1191,8 @@ func (bc *Blockchain) tryRunGC(oldHeight uint32) time.Duration {
|
|||
oldHeight /= bc.config.Ledger.GarbageCollectionPeriod
|
||||
newHeight /= bc.config.Ledger.GarbageCollectionPeriod
|
||||
if tgtBlock > int64(bc.config.Ledger.GarbageCollectionPeriod) && newHeight != oldHeight {
|
||||
dur = bc.stateRoot.GC(uint32(tgtBlock), bc.store)
|
||||
dur += bc.removeOldTransfers(uint32(tgtBlock))
|
||||
dur = bc.removeOldTransfers(uint32(tgtBlock))
|
||||
dur += bc.stateRoot.GC(uint32(tgtBlock), bc.store)
|
||||
}
|
||||
return dur
|
||||
}
|
||||
|
@ -1644,7 +1676,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
|||
}
|
||||
for index := start; index < stop; index++ {
|
||||
ts, err := kvcache.DeleteBlock(bc.GetHeaderHash(index), bc.config.Ledger.RemoveUntraceableHeaders)
|
||||
if bc.config.Ledger.RemoveUntraceableHeaders && index%bc.config.Ledger.GarbageCollectionPeriod == 0 {
|
||||
if index%bc.config.Ledger.GarbageCollectionPeriod == 0 {
|
||||
_ = bc.gcBlockTimes.Add(index, ts)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -1741,6 +1773,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
|||
Stack: v.Estack().ToArray(),
|
||||
Events: systemInterop.Notifications,
|
||||
FaultException: faultException,
|
||||
Invocations: systemInterop.InvocationCalls,
|
||||
},
|
||||
}
|
||||
appExecResults = append(appExecResults, aer)
|
||||
|
@ -1798,6 +1831,14 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
|||
}
|
||||
|
||||
bc.lock.Lock()
|
||||
// Wait for a while if we're lagging behind the persistence routine,
|
||||
// it's too easy to OOM otherwise. Keep in mind that this check can't
|
||||
// be perfect, so some tolerance (accepting more) is OK to have.
|
||||
var persistVelocity = atomic.LoadUint32(&bc.keysPerPersist)
|
||||
for persistVelocity != 0 && uint32(bc.dao.Store.Len()) > persistVelocity*4 {
|
||||
bc.persistCond.Wait()
|
||||
}
|
||||
|
||||
_, err = aerCache.Persist()
|
||||
if err != nil {
|
||||
bc.lock.Unlock()
|
||||
|
@ -2149,7 +2190,7 @@ func (bc *Blockchain) LastBatch() *storage.MemBatch {
|
|||
}
|
||||
|
||||
// persist flushes current in-memory Store contents to the persistent storage.
|
||||
func (bc *Blockchain) persist(isSync bool) (time.Duration, error) {
|
||||
func (bc *Blockchain) persist() (time.Duration, error) {
|
||||
var (
|
||||
start = time.Now()
|
||||
duration time.Duration
|
||||
|
@ -2157,11 +2198,7 @@ func (bc *Blockchain) persist(isSync bool) (time.Duration, error) {
|
|||
err error
|
||||
)
|
||||
|
||||
if isSync {
|
||||
persisted, err = bc.dao.PersistSync()
|
||||
} else {
|
||||
persisted, err = bc.dao.Persist()
|
||||
}
|
||||
persisted, err = bc.dao.Persist()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -2178,6 +2215,20 @@ func (bc *Blockchain) persist(isSync bool) (time.Duration, error) {
|
|||
return 0, err
|
||||
}
|
||||
duration = time.Since(start)
|
||||
// Low number of keys is not representative and duration _can_
|
||||
// be zero in tests on strange platforms like Windows.
|
||||
if duration > 0 && persisted > persistMinForSampling {
|
||||
var (
|
||||
currentVelocity = uint32(int64(persisted) * int64(persistInterval) / int64(duration))
|
||||
persistVelocity = atomic.LoadUint32(&bc.keysPerPersist)
|
||||
)
|
||||
if persistVelocity != 0 {
|
||||
currentVelocity = min(currentVelocity, 2*persistVelocity) // Normalize sudden spikes.
|
||||
currentVelocity = (persistVelocity*(persistSamples-1) + currentVelocity) / persistSamples
|
||||
} // Otherwise it's the first sample and we take it as is.
|
||||
atomic.StoreUint32(&bc.keysPerPersist, currentVelocity)
|
||||
updateEstimatedPersistVelocityMetric(currentVelocity)
|
||||
}
|
||||
bc.log.Info("persisted to disk",
|
||||
zap.Uint32("blocks", diff),
|
||||
zap.Int("keys", persisted),
|
||||
|
@ -2188,6 +2239,7 @@ func (bc *Blockchain) persist(isSync bool) (time.Duration, error) {
|
|||
// update monitoring metrics.
|
||||
updatePersistedHeightMetric(bHeight)
|
||||
}
|
||||
bc.persistCond.Signal()
|
||||
|
||||
return duration, nil
|
||||
}
|
||||
|
@ -2798,7 +2850,7 @@ func (bc *Blockchain) PoolTxWithData(t *transaction.Transaction, data any, mp *m
|
|||
if verificationFunction != nil {
|
||||
err := verificationFunction(t, data)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("data verification failed: %w", err)
|
||||
}
|
||||
}
|
||||
return bc.verifyAndPoolTx(t, mp, feer, data)
|
||||
|
@ -3117,3 +3169,8 @@ func (bc *Blockchain) GetStoragePrice() int64 {
|
|||
}
|
||||
return bc.contracts.Policy.GetStoragePriceInternal(bc.dao)
|
||||
}
|
||||
|
||||
// GetTrimmedBlock returns a block with only the header and transaction hashes.
|
||||
func (bc *Blockchain) GetTrimmedBlock(hash util.Uint256) (*block.Block, error) {
|
||||
return bc.dao.GetBlock(hash)
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ func TestAddBlock(t *testing.T) {
|
|||
assert.Equal(t, lastBlock.Hash(), bc.CurrentHeaderHash())
|
||||
|
||||
// This one tests persisting blocks, so it does need to persist()
|
||||
_, err = bc.persist(false)
|
||||
_, err = bc.persist()
|
||||
require.NoError(t, err)
|
||||
|
||||
key := make([]byte, 1+util.Uint256Size)
|
||||
|
|
|
@ -272,7 +272,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 for the latest hardfork Domovoi (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 Echidna (stored contract state differs from autogenerated one)", nativenames.CryptoLib)), err)
|
||||
})
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
|
|
|
@ -448,6 +448,7 @@ type Version struct {
|
|||
KeepOnlyLatestState bool
|
||||
Magic uint32
|
||||
Value string
|
||||
SaveInvocations bool
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -455,6 +456,7 @@ const (
|
|||
p2pSigExtensionsBit
|
||||
p2pStateExchangeExtensionsBit
|
||||
keepOnlyLatestStateBit
|
||||
saveInvocationsBit
|
||||
)
|
||||
|
||||
// FromBytes decodes v from a byte-slice.
|
||||
|
@ -482,6 +484,7 @@ func (v *Version) FromBytes(data []byte) error {
|
|||
v.P2PSigExtensions = data[i+2]&p2pSigExtensionsBit != 0
|
||||
v.P2PStateExchangeExtensions = data[i+2]&p2pStateExchangeExtensionsBit != 0
|
||||
v.KeepOnlyLatestState = data[i+2]&keepOnlyLatestStateBit != 0
|
||||
v.SaveInvocations = data[i+2]&saveInvocationsBit != 0
|
||||
|
||||
m := i + 3
|
||||
if len(data) == m+4 {
|
||||
|
@ -505,6 +508,9 @@ func (v *Version) Bytes() []byte {
|
|||
if v.KeepOnlyLatestState {
|
||||
mask |= keepOnlyLatestStateBit
|
||||
}
|
||||
if v.SaveInvocations {
|
||||
mask |= saveInvocationsBit
|
||||
}
|
||||
res := append([]byte(v.Value), '\x00', byte(v.StoragePrefix), mask)
|
||||
res = binary.LittleEndian.AppendUint32(res, v.Magic)
|
||||
return res
|
||||
|
|
|
@ -35,6 +35,9 @@ const (
|
|||
DefaultBaseExecFee = 30
|
||||
// ContextNonceDataLen is a length of [Context.NonceData] in bytes.
|
||||
ContextNonceDataLen = 16
|
||||
// MaxNotificationCount is the maximum number of notifications per single
|
||||
// application execution.
|
||||
MaxNotificationCount = 512
|
||||
)
|
||||
|
||||
// Ledger is the interface to Blockchain required for Context functionality.
|
||||
|
@ -63,6 +66,7 @@ type Context struct {
|
|||
VM *vm.VM
|
||||
Functions []Function
|
||||
Invocations map[util.Uint160]int
|
||||
InvocationCalls []state.ContractInvocation
|
||||
cancelFuncs []context.CancelFunc
|
||||
getContract func(*dao.Simple, util.Uint160) (*state.Contract, error)
|
||||
baseExecFee int64
|
||||
|
@ -70,6 +74,7 @@ type Context struct {
|
|||
loadToken func(ic *Context, id int32) error
|
||||
GetRandomCounter uint32
|
||||
signers []transaction.Signer
|
||||
SaveInvocations bool
|
||||
}
|
||||
|
||||
// NewContext returns new interop context.
|
||||
|
@ -78,22 +83,23 @@ func NewContext(trigger trigger.Type, bc Ledger, d *dao.Simple, baseExecFee, bas
|
|||
loadTokenFunc func(ic *Context, id int32) error,
|
||||
block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context {
|
||||
dao := d.GetPrivate()
|
||||
cfg := bc.GetConfig().ProtocolConfiguration
|
||||
cfg := bc.GetConfig()
|
||||
return &Context{
|
||||
Chain: bc,
|
||||
Network: uint32(cfg.Magic),
|
||||
Hardforks: cfg.Hardforks,
|
||||
Natives: natives,
|
||||
Trigger: trigger,
|
||||
Block: block,
|
||||
Tx: tx,
|
||||
DAO: dao,
|
||||
Log: log,
|
||||
Invocations: make(map[util.Uint160]int),
|
||||
getContract: getContract,
|
||||
baseExecFee: baseExecFee,
|
||||
baseStorageFee: baseStorageFee,
|
||||
loadToken: loadTokenFunc,
|
||||
Chain: bc,
|
||||
Network: uint32(cfg.Magic),
|
||||
Hardforks: cfg.Hardforks,
|
||||
Natives: natives,
|
||||
Trigger: trigger,
|
||||
Block: block,
|
||||
Tx: tx,
|
||||
DAO: dao,
|
||||
Log: log,
|
||||
Invocations: make(map[util.Uint160]int),
|
||||
getContract: getContract,
|
||||
baseExecFee: baseExecFee,
|
||||
baseStorageFee: baseStorageFee,
|
||||
loadToken: loadTokenFunc,
|
||||
SaveInvocations: cfg.SaveInvocations,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,7 +219,7 @@ type ContractMD struct {
|
|||
mdCache map[config.Hardfork]*HFSpecificContractMD
|
||||
|
||||
// onManifestConstruction is a callback for manifest finalization.
|
||||
onManifestConstruction func(*manifest.Manifest)
|
||||
onManifestConstruction func(*manifest.Manifest, config.Hardfork)
|
||||
}
|
||||
|
||||
// HFSpecificContractMD is a hardfork-specific native contract descriptor.
|
||||
|
@ -225,7 +231,7 @@ type HFSpecificContractMD struct {
|
|||
|
||||
// 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 {
|
||||
func NewContractMD(name string, id int32, onManifestConstruction ...func(*manifest.Manifest, config.Hardfork)) *ContractMD {
|
||||
c := &ContractMD{Name: name}
|
||||
if len(onManifestConstruction) != 0 {
|
||||
c.onManifestConstruction = onManifestConstruction[0]
|
||||
|
@ -250,10 +256,10 @@ func (c *ContractMD) HFSpecificContractMD(hf *config.Hardfork) *HFSpecificContra
|
|||
}
|
||||
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))
|
||||
panic(fmt.Errorf("native contract descriptor cache is not initialized: contract %s, hardfork %s", c.Name, key))
|
||||
}
|
||||
if md == nil {
|
||||
panic(fmt.Errorf("native contract descriptor cache is nil: contract %s, hardfork %s", c.Hash.StringLE(), key))
|
||||
panic(fmt.Errorf("native contract descriptor cache is nil: contract %s, hardfork %s", c.Name, key))
|
||||
}
|
||||
return md
|
||||
}
|
||||
|
@ -339,7 +345,7 @@ func (c *ContractMD) buildHFSpecificMD(hf config.Hardfork) {
|
|||
m.ABI.Methods = abiMethods
|
||||
m.ABI.Events = abiEvents
|
||||
if c.onManifestConstruction != nil {
|
||||
c.onManifestConstruction(m)
|
||||
c.onManifestConstruction(m, hf)
|
||||
}
|
||||
md := &HFSpecificContractMD{
|
||||
ContractBase: state.ContractBase{
|
||||
|
@ -562,10 +568,18 @@ func (ic *Context) IsHardforkActivation(hf config.Hardfork) bool {
|
|||
}
|
||||
|
||||
// AddNotification creates notification event and appends it to the notification list.
|
||||
func (ic *Context) AddNotification(hash util.Uint160, name string, item *stackitem.Array) {
|
||||
func (ic *Context) AddNotification(hash util.Uint160, name string, item *stackitem.Array) error {
|
||||
if ic.IsHardforkEnabled(config.HFEchidna) {
|
||||
// Do not check persisting triggers to avoid native persist failure. Do not check
|
||||
// verification trigger since verification context is loaded with ReadOnly flag.
|
||||
if ic.Trigger == trigger.Application && len(ic.Notifications) == MaxNotificationCount {
|
||||
return fmt.Errorf("notification count shouldn't exceed %d", MaxNotificationCount)
|
||||
}
|
||||
}
|
||||
ic.Notifications = append(ic.Notifications, state.NotificationEvent{
|
||||
ScriptHash: hash,
|
||||
Name: name,
|
||||
Item: item,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package contract
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
@ -69,6 +70,18 @@ func Call(ic *interop.Context) error {
|
|||
return fmt.Errorf("method not found: %s/%d", method, len(args))
|
||||
}
|
||||
hasReturn := md.ReturnType != smartcontract.VoidType
|
||||
|
||||
if ic.SaveInvocations {
|
||||
var (
|
||||
arrCount = len(args)
|
||||
argBytes []byte
|
||||
)
|
||||
if argBytes, err = ic.DAO.GetItemCtx().Serialize(stackitem.NewArray(args), false); err != nil {
|
||||
argBytes = nil
|
||||
}
|
||||
ci := state.NewContractInvocation(u, method, bytes.Clone(argBytes), uint32(arrCount))
|
||||
ic.InvocationCalls = append(ic.InvocationCalls, *ci)
|
||||
}
|
||||
return callInternal(ic, cs, method, fs, hasReturn, args, true)
|
||||
}
|
||||
|
||||
|
|
|
@ -114,8 +114,7 @@ func Notify(ic *interop.Context) error {
|
|||
if len(bytes) > MaxNotificationSize {
|
||||
return fmt.Errorf("notification size shouldn't exceed %d", MaxNotificationSize)
|
||||
}
|
||||
ic.AddNotification(curHash, name, stackitem.DeepCopy(stackitem.NewArray(args), true).(*stackitem.Array))
|
||||
return nil
|
||||
return ic.AddNotification(curHash, name, stackitem.DeepCopy(stackitem.NewArray(args), true).(*stackitem.Array))
|
||||
}
|
||||
|
||||
// LoadScript takes a script and arguments from the stack and loads it into the VM.
|
||||
|
|
|
@ -11,6 +11,14 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// DummySTTempStoragePrefix is a dummy contract storage item prefix that may be
|
||||
// passed to Billet constructor when Billet's restoring functionality is not
|
||||
// used, i.e. for those situations when only traversal functionality is used.
|
||||
// Note that using this prefix for MPT restoring is an error which will lead to
|
||||
// a panic since Billet must have the ability to save contract storage items to
|
||||
// the underlying DB during MPT restore process.
|
||||
const DummySTTempStoragePrefix = 0x00
|
||||
|
||||
var (
|
||||
// ErrRestoreFailed is returned when replacing HashNode by its "unhashed"
|
||||
// candidate fails.
|
||||
|
@ -37,7 +45,10 @@ type Billet struct {
|
|||
// NewBillet returns a new billet for MPT trie restoring. It accepts a MemCachedStore
|
||||
// to decouple storage errors from logic errors so that all storage errors are
|
||||
// processed during `store.Persist()` at the caller. Another benefit is
|
||||
// that every `Put` can be considered an atomic operation.
|
||||
// that every `Put` can be considered an atomic operation. Note that mode
|
||||
// parameter must match precisely the Trie mode that is used in the underlying
|
||||
// DB to store the MPT nodes. Using wrong mode will lead to improper MPT nodes
|
||||
// decoding and even runtime panic.
|
||||
func NewBillet(rootHash util.Uint256, mode TrieMode, prefix storage.KeyPrefix, store *storage.MemCachedStore) *Billet {
|
||||
return &Billet{
|
||||
TempStoragePrefix: prefix,
|
||||
|
@ -65,7 +76,7 @@ func (b *Billet) RestoreHashNode(path []byte, node Node) error {
|
|||
|
||||
// If it's a leaf, then put into temporary contract storage.
|
||||
if leaf, ok := node.(*LeafNode); ok {
|
||||
if b.TempStoragePrefix == 0 {
|
||||
if b.TempStoragePrefix == DummySTTempStoragePrefix {
|
||||
panic("invalid storage prefix")
|
||||
}
|
||||
k := append([]byte{byte(b.TempStoragePrefix)}, fromNibbles(path)...)
|
||||
|
|
|
@ -612,7 +612,7 @@ func (t *Trie) Find(prefix, from []byte, maxNum int) ([]storage.KeyValue, error)
|
|||
res []storage.KeyValue
|
||||
count int
|
||||
)
|
||||
b := NewBillet(t.root.Hash(), t.mode, 0, t.Store)
|
||||
b := NewBillet(t.root.Hash(), t.mode, DummySTTempStoragePrefix, t.Store)
|
||||
process := func(pathToNode []byte, node Node, _ []byte) bool {
|
||||
if leaf, ok := node.(*LeafNode); ok {
|
||||
if from == nil || !bytes.Equal(pathToNode, from) { // (*Billet).traverse includes `from` path into result if so. Need to filter out manually.
|
||||
|
|
|
@ -94,7 +94,7 @@ func (m *TrieStore) Seek(rng storage.SeekRange, f func(k, v []byte) bool) {
|
|||
}
|
||||
}
|
||||
|
||||
b := NewBillet(m.trie.root.Hash(), m.trie.mode, 0, m.trie.Store)
|
||||
b := NewBillet(m.trie.root.Hash(), m.trie.mode, DummySTTempStoragePrefix, m.trie.Store)
|
||||
process := func(pathToNode []byte, node Node, _ []byte) bool {
|
||||
if leaf, ok := node.(*LeafNode); ok {
|
||||
// (*Billet).traverse includes `from` path into the result if so. It's OK for Seek, so shouldn't be filtered out.
|
||||
|
|
|
@ -121,7 +121,15 @@ func newDesignate(initialNodeRoles map[noderoles.Role]keys.PublicKeys) *Designat
|
|||
eDesc := newEventDescriptor(DesignationEventName,
|
||||
manifest.NewParameter("Role", smartcontract.IntegerType),
|
||||
manifest.NewParameter("BlockIndex", smartcontract.IntegerType))
|
||||
eMD := newEvent(eDesc)
|
||||
eMD := newEvent(eDesc, config.HFDefault, config.HFEchidna)
|
||||
s.AddEvent(eMD)
|
||||
|
||||
eDesc = newEventDescriptor(DesignationEventName,
|
||||
manifest.NewParameter("Role", smartcontract.IntegerType),
|
||||
manifest.NewParameter("BlockIndex", smartcontract.IntegerType),
|
||||
manifest.NewParameter("Old", smartcontract.ArrayType),
|
||||
manifest.NewParameter("New", smartcontract.ArrayType))
|
||||
eMD = newEvent(eDesc, config.HFEchidna)
|
||||
s.AddEvent(eMD)
|
||||
|
||||
return s
|
||||
|
@ -412,11 +420,20 @@ func (s *Designate) DesignateAsRole(ic *interop.Context, r noderoles.Role, pubs
|
|||
return fmt.Errorf("failed to update Designation role data cache: %w", err)
|
||||
}
|
||||
|
||||
ic.AddNotification(s.Hash, DesignationEventName, stackitem.NewArray([]stackitem.Item{
|
||||
ntf := stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewBigInteger(big.NewInt(int64(r))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(ic.Block.Index))),
|
||||
}))
|
||||
return nil
|
||||
})
|
||||
if ic.IsHardforkEnabled(config.HFEchidna) {
|
||||
old, _, err := s.GetDesignatedByRole(ic.DAO, r, ic.Block.Index)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get old nodes for role %d: %w", r, err)
|
||||
}
|
||||
ntf.Append(pubsToArray(old))
|
||||
ntf.Append(pubsToArray(pubs))
|
||||
}
|
||||
|
||||
return ic.AddNotification(s.Hash, DesignationEventName, ntf)
|
||||
}
|
||||
|
||||
func (s *Designate) getRole(item stackitem.Item) (noderoles.Role, bool) {
|
||||
|
|
|
@ -372,7 +372,10 @@ func (m *Management) deployWithData(ic *interop.Context, args []stackitem.Item)
|
|||
panic(err)
|
||||
}
|
||||
m.callDeploy(ic, newcontract, args[2], false)
|
||||
m.emitNotification(ic, contractDeployNotificationName, newcontract.Hash)
|
||||
err = m.emitNotification(ic, contractDeployNotificationName, newcontract.Hash)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return contractToStack(newcontract)
|
||||
}
|
||||
|
||||
|
@ -444,7 +447,10 @@ func (m *Management) updateWithData(ic *interop.Context, args []stackitem.Item)
|
|||
panic(err)
|
||||
}
|
||||
m.callDeploy(ic, contract, args[2], true)
|
||||
m.emitNotification(ic, contractUpdateNotificationName, contract.Hash)
|
||||
err = m.emitNotification(ic, contractUpdateNotificationName, contract.Hash)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
||||
|
@ -497,7 +503,10 @@ func (m *Management) destroy(ic *interop.Context, sis []stackitem.Item) stackite
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m.emitNotification(ic, contractDestroyNotificationName, hash)
|
||||
err = m.emitNotification(ic, contractDestroyNotificationName, hash)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
||||
|
@ -610,8 +619,6 @@ func (m *Management) OnPersist(ic *interop.Context) error {
|
|||
for _, hf := range config.Hardforks {
|
||||
if _, ok := activeHFs[hf]; ok && ic.IsHardforkActivation(hf) {
|
||||
isUpdate = true
|
||||
activation := hf // avoid loop variable pointer exporting.
|
||||
activeIn = &activation // reuse ActiveIn variable for the initialization hardfork.
|
||||
// Break immediately since native Initialize should be called starting from the first hardfork in a raw
|
||||
// (if there are multiple hardforks with the same enabling height).
|
||||
break
|
||||
|
@ -626,6 +633,10 @@ func (m *Management) OnPersist(ic *interop.Context) error {
|
|||
currentActiveHFs = append(currentActiveHFs, hf)
|
||||
}
|
||||
}
|
||||
// activeIn is not included into the activeHFs list.
|
||||
if activeIn != nil && activeIn.Cmp(latestHF) > 0 {
|
||||
latestHF = *activeIn
|
||||
}
|
||||
if !(isDeploy || isUpdate) {
|
||||
continue
|
||||
}
|
||||
|
@ -668,7 +679,7 @@ func (m *Management) OnPersist(ic *interop.Context) error {
|
|||
// The rest of activating hardforks also require initialization.
|
||||
for _, hf := range currentActiveHFs {
|
||||
if err := native.Initialize(ic, &hf, hfSpecificMD); err != nil {
|
||||
return fmt.Errorf("initializing %s native contract at HF %d: %w", md.Name, activeIn, err)
|
||||
return fmt.Errorf("initializing %s native contract at HF %s: %w", md.Name, hf, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -681,7 +692,10 @@ func (m *Management) OnPersist(ic *interop.Context) error {
|
|||
if isUpdate {
|
||||
ntfName = contractUpdateNotificationName
|
||||
}
|
||||
m.emitNotification(ic, ntfName, cs.Hash)
|
||||
err = m.emitNotification(ic, ntfName, cs.Hash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -806,8 +820,8 @@ func (m *Management) getNextContractID(d *dao.Simple) (int32, error) {
|
|||
return ret, nil
|
||||
}
|
||||
|
||||
func (m *Management) emitNotification(ic *interop.Context, name string, hash util.Uint160) {
|
||||
ic.AddNotification(m.Hash, name, stackitem.NewArray([]stackitem.Item{addrToStackItem(&hash)}))
|
||||
func (m *Management) emitNotification(ic *interop.Context, name string, hash util.Uint160) error {
|
||||
return ic.AddNotification(m.Hash, name, stackitem.NewArray([]stackitem.Item{addrToStackItem(&hash)}))
|
||||
}
|
||||
|
||||
func checkScriptAndMethods(ic *interop.Context, script []byte, methods []manifest.Method) error {
|
||||
|
|
|
@ -39,7 +39,7 @@ func newGAS(init int64, p2pSigExtensionsEnabled bool) *GAS {
|
|||
}
|
||||
defer g.BuildHFSpecificMD(g.ActiveIn())
|
||||
|
||||
nep17 := newNEP17Native(nativenames.Gas, gasContractID)
|
||||
nep17 := newNEP17Native(nativenames.Gas, gasContractID, nil)
|
||||
nep17.symbol = "GAS"
|
||||
nep17.decimals = 8
|
||||
nep17.factor = GASFactor
|
||||
|
|
|
@ -170,7 +170,11 @@ func newNEO(cfg config.ProtocolConfiguration) *NEO {
|
|||
n := &NEO{}
|
||||
defer n.BuildHFSpecificMD(n.ActiveIn())
|
||||
|
||||
nep17 := newNEP17Native(nativenames.Neo, neoContractID)
|
||||
nep17 := newNEP17Native(nativenames.Neo, neoContractID, func(m *manifest.Manifest, hf config.Hardfork) {
|
||||
if hf.Cmp(config.HFEchidna) >= 0 {
|
||||
m.SupportedStandards = append(m.SupportedStandards, manifest.NEP27StandardName)
|
||||
}
|
||||
})
|
||||
nep17.symbol = "NEO"
|
||||
nep17.decimals = 0
|
||||
nep17.factor = 1
|
||||
|
@ -192,18 +196,34 @@ func newNEO(cfg config.ProtocolConfiguration) *NEO {
|
|||
|
||||
desc = newDescriptor("registerCandidate", smartcontract.BoolType,
|
||||
manifest.NewParameter("pubkey", smartcontract.PublicKeyType))
|
||||
md = newMethodAndPrice(n.registerCandidate, 0, callflag.States)
|
||||
md = newMethodAndPrice(n.registerCandidate, 0, callflag.States, config.HFDefault, config.HFEchidna)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
md = newMethodAndPrice(n.registerCandidate, 0, callflag.States|callflag.AllowNotify, config.HFEchidna)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("unregisterCandidate", smartcontract.BoolType,
|
||||
manifest.NewParameter("pubkey", smartcontract.PublicKeyType))
|
||||
md = newMethodAndPrice(n.unregisterCandidate, 1<<16, callflag.States)
|
||||
md = newMethodAndPrice(n.unregisterCandidate, 1<<16, callflag.States, config.HFDefault, config.HFEchidna)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
md = newMethodAndPrice(n.unregisterCandidate, 1<<16, callflag.States|callflag.AllowNotify, config.HFEchidna)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("onNEP17Payment", smartcontract.VoidType,
|
||||
manifest.NewParameter("from", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("amount", smartcontract.IntegerType),
|
||||
manifest.NewParameter("data", smartcontract.AnyType))
|
||||
md = newMethodAndPrice(n.onNEP17Payment, 1<<15, callflag.States|callflag.AllowNotify, config.HFEchidna)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("vote", smartcontract.BoolType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("voteTo", smartcontract.PublicKeyType))
|
||||
md = newMethodAndPrice(n.vote, 1<<16, callflag.States)
|
||||
md = newMethodAndPrice(n.vote, 1<<16, callflag.States, config.HFDefault, config.HFEchidna)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
md = newMethodAndPrice(n.vote, 1<<16, callflag.States|callflag.AllowNotify, config.HFEchidna)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getCandidates", smartcontract.ArrayType)
|
||||
|
@ -459,9 +479,12 @@ func (n *NEO) OnPersist(ic *interop.Context) error {
|
|||
ic.DAO.PutStorageItem(n.ID, prefixCommittee, cache.committee.Bytes(ic.DAO.GetItemCtx()))
|
||||
|
||||
if oldCommittee != nil {
|
||||
ic.AddNotification(n.Hash, "CommitteeChanged", stackitem.NewArray([]stackitem.Item{
|
||||
err := ic.AddNotification(n.Hash, "CommitteeChanged", stackitem.NewArray([]stackitem.Item{
|
||||
oldCommittee, newCommittee,
|
||||
}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -815,20 +838,56 @@ func (n *NEO) CalculateNEOHolderReward(d *dao.Simple, value *big.Int, start, end
|
|||
|
||||
func (n *NEO) registerCandidate(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
pub := toPublicKey(args[0])
|
||||
ok, err := runtime.CheckKeyedWitness(ic, pub)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
} else if !ok {
|
||||
return stackitem.NewBool(false)
|
||||
if !ic.IsHardforkEnabled(config.HFEchidna) {
|
||||
ok, err := runtime.CheckKeyedWitness(ic, pub)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
} else if !ok {
|
||||
return stackitem.NewBool(false)
|
||||
}
|
||||
}
|
||||
if !ic.VM.AddGas(n.getRegisterPriceInternal(ic.DAO)) {
|
||||
panic("insufficient gas")
|
||||
}
|
||||
err = n.RegisterCandidateInternal(ic, pub)
|
||||
var err = n.RegisterCandidateInternal(ic, pub)
|
||||
return stackitem.NewBool(err == nil)
|
||||
}
|
||||
|
||||
// RegisterCandidateInternal registers pub as a new candidate.
|
||||
func (n *NEO) checkRegisterCandidate(ic *interop.Context, pub *keys.PublicKey) error {
|
||||
ok, err := runtime.CheckKeyedWitness(ic, pub)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
} else if !ok {
|
||||
return errors.New("not witnessed by the key owner")
|
||||
}
|
||||
return n.RegisterCandidateInternal(ic, pub)
|
||||
}
|
||||
|
||||
func (n *NEO) onNEP17Payment(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
var (
|
||||
caller = ic.VM.GetCallingScriptHash()
|
||||
_ = toUint160(args[0])
|
||||
amount = toBigInt(args[1])
|
||||
pub = toPublicKey(args[2])
|
||||
regPrice = n.getRegisterPriceInternal(ic.DAO)
|
||||
)
|
||||
|
||||
if caller != n.GAS.Hash {
|
||||
panic("only GAS is accepted")
|
||||
}
|
||||
if !amount.IsInt64() || amount.Int64() != regPrice {
|
||||
panic(fmt.Errorf("incorrect GAS amount for registration (expected %d)", regPrice))
|
||||
}
|
||||
var err = n.checkRegisterCandidate(ic, pub)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
n.GAS.burn(ic, n.Hash, amount)
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
||||
// RegisterCandidateInternal registers pub as a new candidate. This method must not be
|
||||
// called outside of VM since it panics on critical errors.
|
||||
func (n *NEO) RegisterCandidateInternal(ic *interop.Context, pub *keys.PublicKey) error {
|
||||
var emitEvent = true
|
||||
|
||||
|
@ -843,16 +902,23 @@ func (n *NEO) RegisterCandidateInternal(ic *interop.Context, pub *keys.PublicKey
|
|||
c.Registered = true
|
||||
}
|
||||
err := putConvertibleToDAO(n.ID, ic.DAO, key, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if emitEvent {
|
||||
cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
|
||||
cache.votesChanged = true
|
||||
ic.AddNotification(n.Hash, "CandidateStateChanged", stackitem.NewArray([]stackitem.Item{
|
||||
err = ic.AddNotification(n.Hash, "CandidateStateChanged", stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(pub.Bytes()),
|
||||
stackitem.NewBool(c.Registered),
|
||||
stackitem.NewBigInteger(&c.Votes),
|
||||
}))
|
||||
if err != nil {
|
||||
// Panic since it's a critical error that must abort execution.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *NEO) unregisterCandidate(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
|
@ -867,7 +933,8 @@ func (n *NEO) unregisterCandidate(ic *interop.Context, args []stackitem.Item) st
|
|||
return stackitem.NewBool(err == nil)
|
||||
}
|
||||
|
||||
// UnregisterCandidateInternal unregisters pub as a candidate.
|
||||
// UnregisterCandidateInternal unregisters pub as a candidate. This method must not be
|
||||
// called outside of VM since it panics on critical errors.
|
||||
func (n *NEO) UnregisterCandidateInternal(ic *interop.Context, pub *keys.PublicKey) error {
|
||||
var err error
|
||||
|
||||
|
@ -887,14 +954,21 @@ func (n *NEO) UnregisterCandidateInternal(ic *interop.Context, pub *keys.PublicK
|
|||
if !ok {
|
||||
err = putConvertibleToDAO(n.ID, ic.DAO, key, c)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if emitEvent {
|
||||
ic.AddNotification(n.Hash, "CandidateStateChanged", stackitem.NewArray([]stackitem.Item{
|
||||
err := ic.AddNotification(n.Hash, "CandidateStateChanged", stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(pub.Bytes()),
|
||||
stackitem.NewBool(c.Registered),
|
||||
stackitem.NewBigInteger(&c.Votes),
|
||||
}))
|
||||
if err != nil {
|
||||
// Panic since it's a critical error that must abort execution.
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *NEO) vote(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
|
@ -907,7 +981,8 @@ func (n *NEO) vote(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
|||
return stackitem.NewBool(err == nil)
|
||||
}
|
||||
|
||||
// VoteInternal votes from account h for validarors specified in pubs.
|
||||
// VoteInternal votes from account h for validarors specified in pubs. This method
|
||||
// must not be called outside of VM since it panics on critical errors.
|
||||
func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pub *keys.PublicKey) error {
|
||||
ok, err := runtime.CheckHashedWitness(ic, h)
|
||||
if err != nil {
|
||||
|
@ -969,12 +1044,16 @@ func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pub *keys.Public
|
|||
}
|
||||
ic.DAO.PutStorageItem(n.ID, key, acc.Bytes(ic.DAO.GetItemCtx()))
|
||||
|
||||
ic.AddNotification(n.Hash, "Vote", stackitem.NewArray([]stackitem.Item{
|
||||
err = ic.AddNotification(n.Hash, "Vote", stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(h.BytesBE()),
|
||||
keyToStackItem(oldVote),
|
||||
keyToStackItem(pub),
|
||||
stackitem.NewBigInteger(&acc.Balance),
|
||||
}))
|
||||
if err != nil {
|
||||
// Panic since it's a critical error that must abort execution.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if newGas != nil { // Can be if it was already distributed in the same block.
|
||||
n.GAS.mint(ic, h, newGas, true)
|
||||
|
|
|
@ -45,9 +45,12 @@ func (c *nep17TokenNative) Metadata() *interop.ContractMD {
|
|||
return &c.ContractMD
|
||||
}
|
||||
|
||||
func newNEP17Native(name string, id int32) *nep17TokenNative {
|
||||
n := &nep17TokenNative{ContractMD: *interop.NewContractMD(name, id, func(m *manifest.Manifest) {
|
||||
func newNEP17Native(name string, id int32, onManifestConstruction func(m *manifest.Manifest, hf config.Hardfork)) *nep17TokenNative {
|
||||
n := &nep17TokenNative{ContractMD: *interop.NewContractMD(name, id, func(m *manifest.Manifest, hf config.Hardfork) {
|
||||
m.SupportedStandards = []string{manifest.NEP17StandardName}
|
||||
if onManifestConstruction != nil {
|
||||
onManifestConstruction(m, hf)
|
||||
}
|
||||
})}
|
||||
|
||||
desc := newDescriptor("symbol", smartcontract.StringType)
|
||||
|
@ -143,7 +146,11 @@ func (c *nep17TokenNative) postTransfer(ic *interop.Context, from, to *util.Uint
|
|||
}
|
||||
}
|
||||
}()
|
||||
c.emitTransfer(ic, from, to, amount)
|
||||
err := c.emitTransfer(ic, from, to, amount)
|
||||
if err != nil {
|
||||
skipPostCalls = true
|
||||
panic(err)
|
||||
}
|
||||
if to == nil || !callOnPayment {
|
||||
return
|
||||
}
|
||||
|
@ -167,8 +174,8 @@ func (c *nep17TokenNative) postTransfer(ic *interop.Context, from, to *util.Uint
|
|||
}
|
||||
}
|
||||
|
||||
func (c *nep17TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int) {
|
||||
ic.AddNotification(c.Hash, "Transfer", stackitem.NewArray([]stackitem.Item{
|
||||
func (c *nep17TokenNative) emitTransfer(ic *interop.Context, from, to *util.Uint160, amount *big.Int) error {
|
||||
return ic.AddNotification(c.Hash, "Transfer", stackitem.NewArray([]stackitem.Item{
|
||||
addrToStackItem(from),
|
||||
addrToStackItem(to),
|
||||
stackitem.NewBigInteger(amount),
|
||||
|
|
|
@ -117,20 +117,33 @@ func testGetSetCache(t *testing.T, c *neotest.ContractInvoker, name string, defa
|
|||
}
|
||||
}
|
||||
|
||||
func setNodesByRole(t *testing.T, designateInvoker *neotest.ContractInvoker, ok bool, r noderoles.Role, nodes keys.PublicKeys) {
|
||||
func setNodesByRole(t *testing.T, designateInvoker *neotest.ContractInvoker, ok bool, r noderoles.Role, nodes keys.PublicKeys, oldKeys ...keys.PublicKeys) {
|
||||
pubs := make([]any, len(nodes))
|
||||
for i := range nodes {
|
||||
pubs[i] = nodes[i].Bytes()
|
||||
}
|
||||
if ok {
|
||||
h := designateInvoker.Invoke(t, stackitem.Null{}, "designateAsRole", int64(r), pubs)
|
||||
ntf := stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(int64(r)),
|
||||
stackitem.Make(designateInvoker.Chain.BlockHeight()),
|
||||
})
|
||||
if len(oldKeys) > 0 {
|
||||
old := stackitem.NewArray([]stackitem.Item{})
|
||||
for _, key := range oldKeys[0] {
|
||||
old.Append(stackitem.NewByteArray(key.Bytes()))
|
||||
}
|
||||
newKeys := stackitem.NewArray([]stackitem.Item{})
|
||||
for _, key := range nodes {
|
||||
newKeys.Append(stackitem.NewByteArray(key.Bytes()))
|
||||
}
|
||||
ntf.Append(old)
|
||||
ntf.Append(newKeys)
|
||||
}
|
||||
designateInvoker.CheckTxNotificationEvent(t, h, 0, state.NotificationEvent{
|
||||
ScriptHash: designateInvoker.Hash,
|
||||
Name: native.DesignationEventName,
|
||||
Item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(int64(r)),
|
||||
stackitem.Make(designateInvoker.Chain.BlockHeight()),
|
||||
}),
|
||||
Item: ntf,
|
||||
})
|
||||
} else {
|
||||
designateInvoker.InvokeFail(t, "", "designateAsRole", int64(r), pubs)
|
||||
|
|
|
@ -56,6 +56,29 @@ func TestDesignate_DesignateAsRole(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestDesignate_DesignateAsRole_Echidna(t *testing.T) {
|
||||
c := newCustomNativeClient(t, nativenames.Designation, func(cfg *config.Blockchain) {
|
||||
cfg.Hardforks = map[string]uint32{
|
||||
config.HFEchidna.String(): 3,
|
||||
}
|
||||
})
|
||||
designateInvoker := c.WithSigners(c.Committee)
|
||||
|
||||
priv, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
oldPubs := keys.PublicKeys{priv.PublicKey()}
|
||||
|
||||
checkNodeRoles(t, designateInvoker, true, noderoles.Oracle, 0, keys.PublicKeys{}) // BlockHeight is 1.
|
||||
setNodesByRole(t, designateInvoker, true, noderoles.Oracle, oldPubs) // BlockHeight is 2.
|
||||
checkNodeRoles(t, designateInvoker, true, noderoles.Oracle, designateInvoker.Chain.BlockHeight()+1, oldPubs) // BlockHeight is 3.
|
||||
|
||||
priv, err = keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
pubs := keys.PublicKeys{priv.PublicKey()}
|
||||
setNodesByRole(t, designateInvoker, true, noderoles.Oracle, pubs, oldPubs) // BlockHeight is 4.
|
||||
checkNodeRoles(t, designateInvoker, true, noderoles.Oracle, designateInvoker.Chain.BlockHeight()+1, pubs) // BlockHeight is 5.
|
||||
}
|
||||
|
||||
type dummyOracle struct {
|
||||
updateNodes func(k keys.PublicKeys)
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ var (
|
|||
nativenames.Policy: `{"id":-7,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"PolicyContract","abi":{"methods":[{"name":"blockAccount","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false},{"name":"getAttributeFee","offset":7,"parameters":[{"name":"attributeType","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"getExecFeeFactor","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"getFeePerByte","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"getStoragePrice","offset":28,"parameters":[],"returntype":"Integer","safe":true},{"name":"isBlocked","offset":35,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":true},{"name":"setAttributeFee","offset":42,"parameters":[{"name":"attributeType","type":"Integer"},{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setExecFeeFactor","offset":49,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setFeePerByte","offset":56,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setStoragePrice","offset":63,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"unblockAccount","offset":70,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
nativenames.Designation: `{"id":-8,"hash":"0x49cf4e5378ffcd4dec034fd98a174c5491e395e2","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0A=","checksum":983638438},"manifest":{"name":"RoleManagement","abi":{"methods":[{"name":"designateAsRole","offset":0,"parameters":[{"name":"role","type":"Integer"},{"name":"nodes","type":"Array"}],"returntype":"Void","safe":false},{"name":"getDesignatedByRole","offset":7,"parameters":[{"name":"role","type":"Integer"},{"name":"index","type":"Integer"}],"returntype":"Array","safe":true}],"events":[{"name":"Designation","parameters":[{"name":"Role","type":"Integer"},{"name":"BlockIndex","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
nativenames.Oracle: `{"id":-9,"hash":"0xfe924b7cfe89ddd271abaf7210a80a7e11178758","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"OracleContract","abi":{"methods":[{"name":"finish","offset":0,"parameters":[],"returntype":"Void","safe":false},{"name":"getPrice","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"request","offset":14,"parameters":[{"name":"url","type":"String"},{"name":"filter","type":"String"},{"name":"callback","type":"String"},{"name":"userData","type":"Any"},{"name":"gasForResponse","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setPrice","offset":21,"parameters":[{"name":"price","type":"Integer"}],"returntype":"Void","safe":false},{"name":"verify","offset":28,"parameters":[],"returntype":"Boolean","safe":true}],"events":[{"name":"OracleRequest","parameters":[{"name":"Id","type":"Integer"},{"name":"RequestContract","type":"Hash160"},{"name":"Url","type":"String"},{"name":"Filter","type":"String"}]},{"name":"OracleResponse","parameters":[{"name":"Id","type":"Integer"},{"name":"OriginalTx","type":"Hash256"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
nativenames.Notary: `{"id":-10,"hash":"0xc1e14f19c3e60d0b9244d06dd7ba9b113135ec3b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"Notary","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"addr","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"expirationOf","offset":7,"parameters":[{"name":"addr","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"getMaxNotValidBeforeDelta","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"lockDepositUntil","offset":21,"parameters":[{"name":"address","type":"Hash160"},{"name":"till","type":"Integer"}],"returntype":"Boolean","safe":false},{"name":"onNEP17Payment","offset":28,"parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"setMaxNotValidBeforeDelta","offset":35,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"verify","offset":42,"parameters":[{"name":"signature","type":"Signature"}],"returntype":"Boolean","safe":true},{"name":"withdraw","offset":49,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
nativenames.Notary: `{"id":-10,"hash":"0xc1e14f19c3e60d0b9244d06dd7ba9b113135ec3b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"Notary","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"addr","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"expirationOf","offset":7,"parameters":[{"name":"addr","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"getMaxNotValidBeforeDelta","offset":14,"parameters":[],"returntype":"Integer","safe":true},{"name":"lockDepositUntil","offset":21,"parameters":[{"name":"address","type":"Hash160"},{"name":"till","type":"Integer"}],"returntype":"Boolean","safe":false},{"name":"onNEP17Payment","offset":28,"parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"setMaxNotValidBeforeDelta","offset":35,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"verify","offset":42,"parameters":[{"name":"signature","type":"Signature"}],"returntype":"Boolean","safe":true},{"name":"withdraw","offset":49,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-27"],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
}
|
||||
// cockatriceCSS holds serialized native contract states built for genesis block (with UpdateCounter 0)
|
||||
// under assumption that hardforks from Aspidochelone to Cockatrice (included) are enabled.
|
||||
|
@ -56,6 +56,11 @@ var (
|
|||
nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"keccak256","offset":42,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":49,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":63,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":70,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
nativenames.Neo: `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1325686241},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommitteeAddress","offset":49,"parameters":[],"returntype":"Hash160","safe":true},{"name":"getGasPerBlock","offset":56,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":63,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":70,"parameters":[],"returntype":"Integer","safe":true},{"name":"registerCandidate","offset":77,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":84,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":91,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":98,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":105,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":112,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":119,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":126,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":133,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
}
|
||||
echidnaCSS = map[string]string{
|
||||
nativenames.Neo: `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1991619121},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommitteeAddress","offset":49,"parameters":[],"returntype":"Hash160","safe":true},{"name":"getGasPerBlock","offset":56,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":63,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":70,"parameters":[],"returntype":"Integer","safe":true},{"name":"onNEP17Payment","offset":77,"parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"registerCandidate","offset":84,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":91,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":98,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":105,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":112,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":119,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":126,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":133,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":140,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17","NEP-27"],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
nativenames.StdLib: `{"id":-2,"hash":"0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2681632925},"manifest":{"name":"StdLib","abi":{"methods":[{"name":"atoi","offset":0,"parameters":[{"name":"value","type":"String"}],"returntype":"Integer","safe":true},{"name":"atoi","offset":7,"parameters":[{"name":"value","type":"String"},{"name":"base","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"base58CheckDecode","offset":14,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base58CheckEncode","offset":21,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base58Decode","offset":28,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base58Encode","offset":35,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base64Decode","offset":42,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base64Encode","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base64UrlDecode","offset":56,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base64UrlEncode","offset":63,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"deserialize","offset":70,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"itoa","offset":77,"parameters":[{"name":"value","type":"Integer"}],"returntype":"String","safe":true},{"name":"itoa","offset":84,"parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","safe":true},{"name":"jsonDeserialize","offset":91,"parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"jsonSerialize","offset":98,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"memoryCompare","offset":105,"parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":112,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":119,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":126,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","safe":true},{"name":"serialize","offset":133,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"strLen","offset":140,"parameters":[{"name":"str","type":"String"}],"returntype":"Integer","safe":true},{"name":"stringSplit","offset":147,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","safe":true},{"name":"stringSplit","offset":154,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"},{"name":"removeEmptyEntries","type":"Boolean"}],"returntype":"Array","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
nativenames.Designation: `{"id":-8,"hash":"0x49cf4e5378ffcd4dec034fd98a174c5491e395e2","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0A=","checksum":983638438},"manifest":{"name":"RoleManagement","abi":{"methods":[{"name":"designateAsRole","offset":0,"parameters":[{"name":"role","type":"Integer"},{"name":"nodes","type":"Array"}],"returntype":"Void","safe":false},{"name":"getDesignatedByRole","offset":7,"parameters":[{"name":"role","type":"Integer"},{"name":"index","type":"Integer"}],"returntype":"Array","safe":true}],"events":[{"name":"Designation","parameters":[{"name":"Role","type":"Integer"},{"name":"BlockIndex","type":"Integer"},{"name":"Old","type":"Array"},{"name":"New","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -63,6 +68,9 @@ func init() {
|
|||
if _, ok := cockatriceCSS[k]; !ok {
|
||||
cockatriceCSS[k] = v
|
||||
}
|
||||
if _, ok := echidnaCSS[k]; !ok {
|
||||
echidnaCSS[k] = cockatriceCSS[k]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,6 +122,7 @@ func TestManagement_GenesisNativeState(t *testing.T) {
|
|||
config.HFAspidochelone.String(): 100500,
|
||||
config.HFBasilisk.String(): 100500,
|
||||
config.HFCockatrice.String(): 100500,
|
||||
config.HFEchidna.String(): 100500,
|
||||
}
|
||||
cfg.P2PSigExtensions = true
|
||||
})
|
||||
|
@ -149,6 +158,19 @@ func TestManagement_GenesisNativeState(t *testing.T) {
|
|||
})
|
||||
check(t, mgmt, cockatriceCSS)
|
||||
})
|
||||
t.Run("Echidna enabled", func(t *testing.T) {
|
||||
mgmt := newCustomManagementClient(t, func(cfg *config.Blockchain) {
|
||||
cfg.Hardforks = map[string]uint32{
|
||||
config.HFAspidochelone.String(): 0,
|
||||
config.HFBasilisk.String(): 0,
|
||||
config.HFCockatrice.String(): 0,
|
||||
config.HFEchidna.String(): 0,
|
||||
}
|
||||
cfg.P2PSigExtensions = true
|
||||
})
|
||||
|
||||
check(t, mgmt, echidnaCSS)
|
||||
})
|
||||
}
|
||||
|
||||
func TestManagement_NativeDeployUpdateNotifications(t *testing.T) {
|
||||
|
|
|
@ -740,6 +740,13 @@ func TestNEO_CalculateBonus(t *testing.T) {
|
|||
accH := acc.Signers[0].ScriptHash()
|
||||
rewardDistance := 10
|
||||
|
||||
// We have 11 blocks made by transactions above and we need block 13 to get Echidna.
|
||||
// Otherwise this happens:
|
||||
// logger.go:146: 2024-12-24T17:52:18.160+0300 WARN contract invocation failed {"tx": "603d1b0e29e7aaf50513689be9d5bb946c7f7fec8836f0e90897c825fb762c13", "block": 13, "error": "at instruction 120 (SYSCALL): System.Contract.CallNative failed: gas limit exceeded"}
|
||||
for range 3 {
|
||||
e.AddNewBlock(t)
|
||||
}
|
||||
|
||||
t.Run("Zero", func(t *testing.T) {
|
||||
initialGASBalance := e.Chain.GetUtilityTokenBalance(accH)
|
||||
for range rewardDistance {
|
||||
|
@ -900,3 +907,86 @@ func TestNEO_GetCandidates(t *testing.T) {
|
|||
neoCommitteeInvoker.Invoke(t, expected, "getCandidates")
|
||||
checkGetAllCandidates(t, expected)
|
||||
}
|
||||
|
||||
func TestNEO_RegisterViaNEP27(t *testing.T) {
|
||||
neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
|
||||
neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
|
||||
e := neoCommitteeInvoker.Executor
|
||||
neoHash := e.NativeHash(t, nativenames.Neo)
|
||||
|
||||
cfg := e.Chain.GetConfig()
|
||||
candidatesCount := cfg.GetCommitteeSize(0) - 1
|
||||
|
||||
// Register a set of candidates and vote for them.
|
||||
voters := make([]neotest.Signer, candidatesCount)
|
||||
candidates := make([]neotest.Signer, candidatesCount)
|
||||
for i := range candidatesCount {
|
||||
voters[i] = e.NewAccount(t, 2000_0000_0000) // enough for one registration
|
||||
candidates[i] = e.NewAccount(t, 2000_0000_0000)
|
||||
}
|
||||
|
||||
stack, err := neoCommitteeInvoker.TestInvoke(t, "getRegisterPrice")
|
||||
require.NoError(t, err)
|
||||
registrationPrice, err := stack.Pop().Item().TryInteger()
|
||||
require.NoError(t, err)
|
||||
|
||||
// We have 11 blocks made by transactions above and we need block 13 to get Echidna.
|
||||
for range 3 {
|
||||
e.AddNewBlock(t)
|
||||
}
|
||||
|
||||
gasValidatorsInvoker := e.CommitteeInvoker(e.NativeHash(t, nativenames.Gas))
|
||||
txes := make([]*transaction.Transaction, 0, candidatesCount*3)
|
||||
for i := range candidatesCount {
|
||||
transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(candidatesCount+1-i)*1000000, nil)
|
||||
txes = append(txes, transferTx)
|
||||
registerTx := gasValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "transfer", candidates[i].(neotest.SingleSigner).Account().ScriptHash(), neoHash, registrationPrice, 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)
|
||||
}
|
||||
|
||||
neoValidatorsInvoker.AddNewBlock(t, txes...)
|
||||
for _, tx := range txes {
|
||||
e.CheckHalt(t, tx.Hash(), stackitem.Make(true)) // luckily, both `transfer` and `vote` return boolean values
|
||||
}
|
||||
|
||||
// Ensure NEO holds no GAS.
|
||||
stack, err = gasValidatorsInvoker.TestInvoke(t, "balanceOf", neoHash)
|
||||
require.NoError(t, err)
|
||||
balance, err := stack.Pop().Item().TryInteger()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, balance.Sign())
|
||||
|
||||
var expected = make([]stackitem.Item, candidatesCount)
|
||||
for i := range expected {
|
||||
pub := candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes()
|
||||
v := stackitem.NewBigInteger(big.NewInt(int64(candidatesCount-i+1) * 1000000))
|
||||
expected[i] = stackitem.NewStruct([]stackitem.Item{
|
||||
stackitem.NewByteArray(pub),
|
||||
v,
|
||||
})
|
||||
neoCommitteeInvoker.Invoke(t, v, "getCandidateVote", pub)
|
||||
}
|
||||
|
||||
slices.SortFunc(expected, func(a, b stackitem.Item) int {
|
||||
return bytes.Compare(a.Value().([]stackitem.Item)[0].Value().([]byte), b.Value().([]stackitem.Item)[0].Value().([]byte))
|
||||
})
|
||||
|
||||
neoCommitteeInvoker.Invoke(t, stackitem.NewArray(expected), "getCandidates")
|
||||
|
||||
// Invalid cases.
|
||||
var newCand = voters[0]
|
||||
|
||||
// Missing data.
|
||||
gasValidatorsInvoker.WithSigners(newCand).InvokeFail(t, "invalid conversion", "transfer", newCand.(neotest.SingleSigner).Account().ScriptHash(), neoHash, registrationPrice, nil)
|
||||
// Invalid data.
|
||||
gasValidatorsInvoker.WithSigners(newCand).InvokeFail(t, "unexpected EOF", "transfer", newCand.(neotest.SingleSigner).Account().ScriptHash(), neoHash, registrationPrice, []byte{2, 2, 2})
|
||||
// NEO transfer.
|
||||
neoValidatorsInvoker.WithSigners(newCand).InvokeFail(t, "only GAS is accepted", "transfer", newCand.(neotest.SingleSigner).Account().ScriptHash(), neoHash, 1, newCand.(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||
// Incorrect amount.
|
||||
gasValidatorsInvoker.WithSigners(newCand).InvokeFail(t, "incorrect GAS amount", "transfer", newCand.(neotest.SingleSigner).Account().ScriptHash(), neoHash, 1, newCand.(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||
// Incorrect witness.
|
||||
var anotherAcc = e.NewAccount(t, 2000_0000_0000)
|
||||
gasValidatorsInvoker.WithSigners(newCand).InvokeFail(t, "not witnessed by the key owner", "transfer", newCand.(neotest.SingleSigner).Account().ScriptHash(), neoHash, registrationPrice, anotherAcc.(neotest.SingleSigner).Account().PublicKey().Bytes())
|
||||
}
|
||||
|
|
|
@ -72,7 +72,9 @@ func copyNotaryCache(src, dst *NotaryCache) {
|
|||
|
||||
// newNotary returns Notary native contract.
|
||||
func newNotary() *Notary {
|
||||
n := &Notary{ContractMD: *interop.NewContractMD(nativenames.Notary, notaryContractID)}
|
||||
n := &Notary{ContractMD: *interop.NewContractMD(nativenames.Notary, notaryContractID, func(m *manifest.Manifest, hf config.Hardfork) {
|
||||
m.SupportedStandards = []string{manifest.NEP17Payable}
|
||||
})}
|
||||
defer n.BuildHFSpecificMD(n.ActiveIn())
|
||||
|
||||
desc := newDescriptor("onNEP17Payment", smartcontract.VoidType,
|
||||
|
|
|
@ -316,10 +316,13 @@ func (o *Oracle) FinishInternal(ic *interop.Context) error {
|
|||
if err != nil {
|
||||
return ErrRequestNotFound
|
||||
}
|
||||
ic.AddNotification(o.Hash, "OracleResponse", stackitem.NewArray([]stackitem.Item{
|
||||
err = ic.AddNotification(o.Hash, "OracleResponse", stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(resp.ID),
|
||||
stackitem.Make(req.OriginalTxID.BytesBE()),
|
||||
}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
origTx, _, err := ic.DAO.GetTransaction(req.OriginalTxID)
|
||||
if err != nil {
|
||||
|
@ -422,12 +425,15 @@ func (o *Oracle) RequestInternal(ic *interop.Context, url string, filter *string
|
|||
} else {
|
||||
filterNotif = stackitem.Null{}
|
||||
}
|
||||
ic.AddNotification(o.Hash, "OracleRequest", stackitem.NewArray([]stackitem.Item{
|
||||
err = ic.AddNotification(o.Hash, "OracleRequest", stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(id),
|
||||
stackitem.Make(ic.VM.GetCallingScriptHash().BytesBE()),
|
||||
stackitem.Make(url),
|
||||
filterNotif,
|
||||
}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req := &state.OracleRequest{
|
||||
OriginalTxID: o.getOriginalTxID(ic.DAO, ic.Tx),
|
||||
GasForResponse: gas.Uint64(),
|
||||
|
|
|
@ -100,6 +100,16 @@ func newStd() *Std {
|
|||
md = newMethodAndPrice(s.base64Decode, 1<<5, callflag.NoneFlag)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("base64UrlEncode", smartcontract.StringType,
|
||||
manifest.NewParameter("data", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(s.base64UrlEncode, 1<<5, callflag.NoneFlag, config.HFEchidna)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("base64UrlDecode", smartcontract.ByteArrayType,
|
||||
manifest.NewParameter("s", smartcontract.StringType))
|
||||
md = newMethodAndPrice(s.base64UrlDecode, 1<<5, callflag.NoneFlag, config.HFEchidna)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("base58Encode", smartcontract.StringType,
|
||||
manifest.NewParameter("data", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(s.base58Encode, 1<<13, callflag.NoneFlag)
|
||||
|
@ -314,6 +324,23 @@ func (s *Std) base64Decode(_ *interop.Context, args []stackitem.Item) stackitem.
|
|||
return stackitem.NewByteArray(result)
|
||||
}
|
||||
|
||||
func (s *Std) base64UrlEncode(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
src := s.toLimitedBytes(args[0])
|
||||
result := base64.URLEncoding.EncodeToString(src)
|
||||
|
||||
return stackitem.NewByteArray([]byte(result))
|
||||
}
|
||||
|
||||
func (s *Std) base64UrlDecode(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
src := s.toLimitedString(args[0])
|
||||
result, err := base64.URLEncoding.DecodeString(src)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return stackitem.NewByteArray(result)
|
||||
}
|
||||
|
||||
func (s *Std) base58Encode(_ *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
src := s.toLimitedBytes(args[0])
|
||||
result := base58.Encode(src)
|
||||
|
|
|
@ -170,7 +170,10 @@ func TestStdLibJSON(t *testing.T) {
|
|||
func TestStdLibEncodeDecode(t *testing.T) {
|
||||
s := newStd()
|
||||
original := []byte("my pretty string")
|
||||
// Source C# implementation: https://github.com/neo-project/neo/blob/216c39eddd03de2cb1f6f8aa5b3c19be60606f27/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs#s#L417-L418
|
||||
originalUrl := []byte("Subject=test@example.com&Issuer=https://example.com")
|
||||
encoded64 := base64.StdEncoding.EncodeToString(original)
|
||||
encoded64Url := "U3ViamVjdD10ZXN0QGV4YW1wbGUuY29tJklzc3Vlcj1odHRwczovL2V4YW1wbGUuY29t"
|
||||
encoded58 := base58.Encode(original)
|
||||
encoded58Check := base58neogo.CheckEncode(original)
|
||||
ic := &interop.Context{VM: vm.New()}
|
||||
|
@ -188,6 +191,16 @@ func TestStdLibEncodeDecode(t *testing.T) {
|
|||
require.PanicsWithError(t, ErrTooBigInput.Error(),
|
||||
func() { s.base64Encode(ic, bigInputArgs) })
|
||||
})
|
||||
t.Run("Encode64Url", func(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.base64UrlEncode(ic, []stackitem.Item{stackitem.Make(originalUrl)})
|
||||
})
|
||||
require.Equal(t, stackitem.Make(encoded64Url), actual)
|
||||
})
|
||||
t.Run("Encode64Url/error", func(t *testing.T) {
|
||||
require.PanicsWithError(t, ErrTooBigInput.Error(),
|
||||
func() { s.base64UrlEncode(ic, bigInputArgs) })
|
||||
})
|
||||
t.Run("Encode58", func(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.base58Encode(ic, []stackitem.Item{stackitem.Make(original)})
|
||||
|
@ -224,6 +237,22 @@ func TestStdLibEncodeDecode(t *testing.T) {
|
|||
require.PanicsWithError(t, ErrTooBigInput.Error(),
|
||||
func() { s.base64Decode(ic, bigInputArgs) })
|
||||
})
|
||||
t.Run("Decode64Url/positive", func(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.base64UrlDecode(ic, []stackitem.Item{stackitem.Make(encoded64Url)})
|
||||
})
|
||||
require.Equal(t, stackitem.Make(originalUrl), actual)
|
||||
})
|
||||
t.Run("Decode64Url/error", func(t *testing.T) {
|
||||
require.Panics(t, func() {
|
||||
_ = s.base64UrlDecode(ic, []stackitem.Item{stackitem.Make(encoded64Url + "%")})
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
_ = s.base64UrlDecode(ic, []stackitem.Item{stackitem.NewInterop(nil)})
|
||||
})
|
||||
require.PanicsWithError(t, ErrTooBigInput.Error(),
|
||||
func() { s.base64UrlDecode(ic, bigInputArgs) })
|
||||
})
|
||||
t.Run("Decode58/positive", func(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
actual = s.base58Decode(ic, []stackitem.Item{stackitem.Make(encoded58)})
|
||||
|
|
|
@ -22,6 +22,14 @@ var (
|
|||
Namespace: "neogo",
|
||||
},
|
||||
)
|
||||
// estimatedPersistVelocity prometheus metric.
|
||||
estimatedPersistVelocity = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Help: "Estimation of persist velocity per cycle (1s by default)",
|
||||
Name: "estimated_persist_velocity",
|
||||
Namespace: "neogo",
|
||||
},
|
||||
)
|
||||
// headerHeight prometheus metric.
|
||||
headerHeight = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
|
@ -44,6 +52,7 @@ func init() {
|
|||
prometheus.MustRegister(
|
||||
blockHeight,
|
||||
persistedHeight,
|
||||
estimatedPersistVelocity,
|
||||
headerHeight,
|
||||
mempoolUnsortedTx,
|
||||
)
|
||||
|
@ -53,6 +62,10 @@ func updatePersistedHeightMetric(pHeight uint32) {
|
|||
persistedHeight.Set(float64(pHeight))
|
||||
}
|
||||
|
||||
func updateEstimatedPersistVelocityMetric(v uint32) {
|
||||
estimatedPersistVelocity.Set(float64(v))
|
||||
}
|
||||
|
||||
func updateHeaderHeightMetric(hHeight uint32) {
|
||||
headerHeight.Set(float64(hHeight))
|
||||
}
|
||||
|
|
120
pkg/core/state/contract_invocation.go
Normal file
120
pkg/core/state/contract_invocation.go
Normal file
|
@ -0,0 +1,120 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// ContractInvocation contains method call information.
|
||||
// The Arguments field will be nil if serialization of the arguments exceeds the predefined limit
|
||||
// of [stackitem.MaxSerialized] (for security reasons). In that case Truncated will be set to true.
|
||||
type ContractInvocation struct {
|
||||
Hash util.Uint160 `json:"contract"`
|
||||
Method string `json:"method"`
|
||||
// Arguments are the arguments as passed to the `args` parameter of System.Contract.Call
|
||||
// for use in the RPC Server and RPC Client.
|
||||
Arguments *stackitem.Array `json:"arguments"`
|
||||
// argumentsBytes is the serialized arguments used at the interop level.
|
||||
argumentsBytes []byte
|
||||
ArgumentsCount uint32 `json:"argumentscount"`
|
||||
Truncated bool `json:"truncated"`
|
||||
}
|
||||
|
||||
// contractInvocationAux is an auxiliary struct for ContractInvocation JSON marshalling.
|
||||
type contractInvocationAux struct {
|
||||
Hash util.Uint160 `json:"hash"`
|
||||
Method string `json:"method"`
|
||||
Arguments json.RawMessage `json:"arguments,omitempty"`
|
||||
ArgumentsCount uint32 `json:"argumentscount"`
|
||||
Truncated bool `json:"truncated"`
|
||||
}
|
||||
|
||||
// NewContractInvocation returns a new ContractInvocation.
|
||||
func NewContractInvocation(hash util.Uint160, method string, argBytes []byte, argCnt uint32) *ContractInvocation {
|
||||
return &ContractInvocation{
|
||||
Hash: hash,
|
||||
Method: method,
|
||||
argumentsBytes: argBytes,
|
||||
ArgumentsCount: argCnt,
|
||||
Truncated: argBytes == nil,
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeBinary implements the Serializable interface.
|
||||
func (ci *ContractInvocation) DecodeBinary(r *io.BinReader) {
|
||||
ci.Hash.DecodeBinary(r)
|
||||
ci.Method = r.ReadString()
|
||||
ci.ArgumentsCount = r.ReadU32LE()
|
||||
ci.Truncated = r.ReadBool()
|
||||
if !ci.Truncated {
|
||||
ci.argumentsBytes = r.ReadVarBytes()
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeBinary implements the Serializable interface.
|
||||
func (ci *ContractInvocation) EncodeBinary(w *io.BinWriter) {
|
||||
ci.EncodeBinaryWithContext(w, stackitem.NewSerializationContext())
|
||||
}
|
||||
|
||||
// EncodeBinaryWithContext is the same as EncodeBinary, but allows to efficiently reuse
|
||||
// stack item serialization context.
|
||||
func (ci *ContractInvocation) EncodeBinaryWithContext(w *io.BinWriter, sc *stackitem.SerializationContext) {
|
||||
ci.Hash.EncodeBinary(w)
|
||||
w.WriteString(ci.Method)
|
||||
w.WriteU32LE(ci.ArgumentsCount)
|
||||
w.WriteBool(ci.Truncated)
|
||||
if !ci.Truncated {
|
||||
w.WriteVarBytes(ci.argumentsBytes)
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (ci ContractInvocation) MarshalJSON() ([]byte, error) {
|
||||
var item []byte
|
||||
if ci.Arguments == nil && ci.argumentsBytes != nil {
|
||||
si, err := stackitem.Deserialize(ci.argumentsBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
item, err = stackitem.ToJSONWithTypes(si.(*stackitem.Array))
|
||||
if err != nil {
|
||||
item = nil
|
||||
}
|
||||
}
|
||||
return json.Marshal(contractInvocationAux{
|
||||
Hash: ci.Hash,
|
||||
Method: ci.Method,
|
||||
Arguments: item,
|
||||
ArgumentsCount: ci.ArgumentsCount,
|
||||
Truncated: ci.Truncated,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (ci *ContractInvocation) UnmarshalJSON(data []byte) error {
|
||||
aux := new(contractInvocationAux)
|
||||
if err := json.Unmarshal(data, aux); err != nil {
|
||||
return err
|
||||
}
|
||||
var args *stackitem.Array
|
||||
if aux.Arguments != nil {
|
||||
arguments, err := stackitem.FromJSONWithTypes(aux.Arguments)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t := arguments.Type(); t != stackitem.ArrayT {
|
||||
return fmt.Errorf("failed to convert invocation state of type %s to array", t.String())
|
||||
}
|
||||
args = arguments.(*stackitem.Array)
|
||||
}
|
||||
ci.Method = aux.Method
|
||||
ci.Hash = aux.Hash
|
||||
ci.ArgumentsCount = aux.ArgumentsCount
|
||||
ci.Truncated = aux.Truncated
|
||||
ci.Arguments = args
|
||||
return nil
|
||||
}
|
51
pkg/core/state/contract_invocation_test.go
Normal file
51
pkg/core/state/contract_invocation_test.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
json "github.com/nspcc-dev/go-ordered-json"
|
||||
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestContractInvocation_MarshalUnmarshalJSON(t *testing.T) {
|
||||
t.Run("truncated", func(t *testing.T) {
|
||||
ci := NewContractInvocation(util.Uint160{}, "fakeMethodCall", nil, 1)
|
||||
testserdes.MarshalUnmarshalJSON(t, ci, new(ContractInvocation))
|
||||
})
|
||||
t.Run("not truncated", func(t *testing.T) {
|
||||
si := stackitem.NewArray([]stackitem.Item{stackitem.NewBool(false)})
|
||||
argBytes, err := stackitem.NewSerializationContext().Serialize(si, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
ci := NewContractInvocation(util.Uint160{}, "fakeMethodCall", argBytes, 1)
|
||||
// Marshal and Unmarshal are asymmetric, test manually
|
||||
out, err := json.Marshal(&ci)
|
||||
require.NoError(t, err)
|
||||
var ci2 ContractInvocation
|
||||
err = json.Unmarshal(out, &ci2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ci.Hash, ci2.Hash)
|
||||
require.Equal(t, ci.Method, ci2.Method)
|
||||
require.Equal(t, ci.Truncated, ci2.Truncated)
|
||||
require.Equal(t, ci.ArgumentsCount, ci2.ArgumentsCount)
|
||||
require.Equal(t, si, ci2.Arguments)
|
||||
})
|
||||
}
|
||||
|
||||
func TestContractInvocation_EncodeDecodeBinary(t *testing.T) {
|
||||
t.Run("truncated", func(t *testing.T) {
|
||||
ci := NewContractInvocation(util.Uint160{}, "fakeMethodCall", nil, 1)
|
||||
testserdes.EncodeDecodeBinary(t, ci, new(ContractInvocation))
|
||||
})
|
||||
t.Run("not truncated", func(t *testing.T) {
|
||||
si := stackitem.NewArray([]stackitem.Item{stackitem.NewBool(false)})
|
||||
argBytes, err := stackitem.NewSerializationContext().Serialize(si, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
ci := NewContractInvocation(util.Uint160{}, "fakeMethodCall", argBytes, 1)
|
||||
testserdes.EncodeDecodeBinary(t, ci, new(ContractInvocation))
|
||||
})
|
||||
}
|
|
@ -12,6 +12,18 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
)
|
||||
|
||||
const (
|
||||
// saveInvocationsBit acts as a marker using the VMState to indicate whether contract
|
||||
// invocations (tracked by the VM) have been stored into the DB and thus whether they
|
||||
// should be deserialized upon retrieval. This approach saves 1 byte for all
|
||||
// applicationlogs over using WriteVarBytes. The original discussion can be found here
|
||||
// https://github.com/nspcc-dev/neo-go/pull/3569#discussion_r1909357541
|
||||
saveInvocationsBit = 0x80
|
||||
// cleanSaveInvocationsBitMask is used to remove the save invocations marker bit from
|
||||
// the VMState.
|
||||
cleanSaveInvocationsBitMask = saveInvocationsBit ^ 0xFF
|
||||
)
|
||||
|
||||
// NotificationEvent is a tuple of the scripthash that has emitted the Item as a
|
||||
// notification and the item itself.
|
||||
type NotificationEvent struct {
|
||||
|
@ -78,6 +90,10 @@ func (aer *AppExecResult) EncodeBinary(w *io.BinWriter) {
|
|||
func (aer *AppExecResult) EncodeBinaryWithContext(w *io.BinWriter, sc *stackitem.SerializationContext) {
|
||||
w.WriteBytes(aer.Container[:])
|
||||
w.WriteB(byte(aer.Trigger))
|
||||
invocLen := len(aer.Invocations)
|
||||
if invocLen > 0 {
|
||||
aer.VMState |= saveInvocationsBit
|
||||
}
|
||||
w.WriteB(byte(aer.VMState))
|
||||
w.WriteU64LE(uint64(aer.GasConsumed))
|
||||
// Stack items are expected to be marshaled one by one.
|
||||
|
@ -95,6 +111,12 @@ func (aer *AppExecResult) EncodeBinaryWithContext(w *io.BinWriter, sc *stackitem
|
|||
aer.Events[i].EncodeBinaryWithContext(w, sc)
|
||||
}
|
||||
w.WriteVarBytes([]byte(aer.FaultException))
|
||||
if invocLen > 0 {
|
||||
w.WriteVarUint(uint64(invocLen))
|
||||
for i := range aer.Invocations {
|
||||
aer.Invocations[i].EncodeBinaryWithContext(w, sc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeBinary implements the Serializable interface.
|
||||
|
@ -120,6 +142,10 @@ func (aer *AppExecResult) DecodeBinary(r *io.BinReader) {
|
|||
aer.Stack = arr
|
||||
r.ReadArray(&aer.Events)
|
||||
aer.FaultException = r.ReadString()
|
||||
if aer.VMState&saveInvocationsBit != 0 {
|
||||
r.ReadArray(&aer.Invocations)
|
||||
aer.VMState &= cleanSaveInvocationsBitMask
|
||||
}
|
||||
}
|
||||
|
||||
// notificationEventAux is an auxiliary struct for NotificationEvent JSON marshalling.
|
||||
|
@ -209,16 +235,18 @@ type Execution struct {
|
|||
Stack []stackitem.Item
|
||||
Events []NotificationEvent
|
||||
FaultException string
|
||||
Invocations []ContractInvocation
|
||||
}
|
||||
|
||||
// executionAux represents an auxiliary struct for Execution JSON marshalling.
|
||||
type executionAux struct {
|
||||
Trigger string `json:"trigger"`
|
||||
VMState string `json:"vmstate"`
|
||||
GasConsumed int64 `json:"gasconsumed,string"`
|
||||
Stack json.RawMessage `json:"stack"`
|
||||
Events []NotificationEvent `json:"notifications"`
|
||||
FaultException *string `json:"exception"`
|
||||
Trigger string `json:"trigger"`
|
||||
VMState string `json:"vmstate"`
|
||||
GasConsumed int64 `json:"gasconsumed,string"`
|
||||
Stack json.RawMessage `json:"stack"`
|
||||
Events []NotificationEvent `json:"notifications"`
|
||||
FaultException *string `json:"exception"`
|
||||
Invocations []ContractInvocation `json:"invocations"`
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
|
@ -246,6 +274,7 @@ func (e Execution) MarshalJSON() ([]byte, error) {
|
|||
Stack: st,
|
||||
Events: e.Events,
|
||||
FaultException: exception,
|
||||
Invocations: e.Invocations,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -287,6 +316,7 @@ func (e *Execution) UnmarshalJSON(data []byte) error {
|
|||
if aux.FaultException != nil {
|
||||
e.FaultException = *aux.FaultException
|
||||
}
|
||||
e.Invocations = aux.Invocations
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -93,11 +93,15 @@ type Module struct {
|
|||
billet *mpt.Billet
|
||||
|
||||
jumpCallback func(p uint32) error
|
||||
|
||||
// stageChangedCallback is an optional callback that is triggered whenever
|
||||
// the sync stage changes.
|
||||
stageChangedCallback func()
|
||||
}
|
||||
|
||||
// NewModule returns new instance of statesync module.
|
||||
func NewModule(bc Ledger, stateMod *stateroot.Module, log *zap.Logger, s *dao.Simple, jumpCallback func(p uint32) error) *Module {
|
||||
if !(bc.GetConfig().P2PStateExchangeExtensions && bc.GetConfig().Ledger.RemoveUntraceableBlocks) {
|
||||
if !(bc.GetConfig().P2PStateExchangeExtensions && bc.GetConfig().Ledger.RemoveUntraceableBlocks) && !bc.GetConfig().NeoFSStateSyncExtensions {
|
||||
return &Module{
|
||||
dao: s,
|
||||
bc: bc,
|
||||
|
@ -120,7 +124,13 @@ func NewModule(bc Ledger, stateMod *stateroot.Module, log *zap.Logger, s *dao.Si
|
|||
// Init initializes state sync module for the current chain's height with given
|
||||
// callback for MPT nodes requests.
|
||||
func (s *Module) Init(currChainHeight uint32) error {
|
||||
oldStage := s.syncStage
|
||||
s.lock.Lock()
|
||||
defer func() {
|
||||
if s.syncStage != oldStage {
|
||||
s.notifyStageChanged()
|
||||
}
|
||||
}()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
if s.syncStage != none {
|
||||
|
@ -176,6 +186,20 @@ func (s *Module) Init(currChainHeight uint32) error {
|
|||
return s.defineSyncStage()
|
||||
}
|
||||
|
||||
// SetOnStageChanged sets callback that is triggered whenever the sync stage changes.
|
||||
func (s *Module) SetOnStageChanged(cb func()) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
s.stageChangedCallback = cb
|
||||
}
|
||||
|
||||
// notifyStageChanged triggers stage change callback if it's set.
|
||||
func (s *Module) notifyStageChanged() {
|
||||
if s.stageChangedCallback != nil {
|
||||
s.stageChangedCallback()
|
||||
}
|
||||
}
|
||||
|
||||
// TemporaryPrefix accepts current storage prefix and returns prefix
|
||||
// to use for storing intermediate items during synchronization.
|
||||
func TemporaryPrefix(currPrefix storage.KeyPrefix) storage.KeyPrefix {
|
||||
|
@ -287,7 +311,13 @@ func (s *Module) getLatestSavedBlock(p uint32) uint32 {
|
|||
|
||||
// AddHeaders validates and adds specified headers to the chain.
|
||||
func (s *Module) AddHeaders(hdrs ...*block.Header) error {
|
||||
oldStage := s.syncStage
|
||||
s.lock.Lock()
|
||||
defer func() {
|
||||
if s.syncStage != oldStage {
|
||||
s.notifyStageChanged()
|
||||
}
|
||||
}()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
if s.syncStage != initialized {
|
||||
|
@ -306,7 +336,13 @@ func (s *Module) AddHeaders(hdrs ...*block.Header) error {
|
|||
|
||||
// AddBlock verifies and saves block skipping executable scripts.
|
||||
func (s *Module) AddBlock(block *block.Block) error {
|
||||
oldStage := s.syncStage
|
||||
s.lock.Lock()
|
||||
defer func() {
|
||||
if s.syncStage != oldStage {
|
||||
s.notifyStageChanged()
|
||||
}
|
||||
}()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
if s.syncStage&headersSynced == 0 || s.syncStage&blocksSynced != 0 {
|
||||
|
@ -359,7 +395,13 @@ func (s *Module) AddBlock(block *block.Block) error {
|
|||
// AddMPTNodes tries to add provided set of MPT nodes to the MPT billet if they are
|
||||
// not yet collected.
|
||||
func (s *Module) AddMPTNodes(nodes [][]byte) error {
|
||||
oldStage := s.syncStage
|
||||
s.lock.Lock()
|
||||
defer func() {
|
||||
if s.syncStage != oldStage {
|
||||
s.notifyStageChanged()
|
||||
}
|
||||
}()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
if s.syncStage&headersSynced == 0 || s.syncStage&mptSynced != 0 {
|
||||
|
@ -425,6 +467,12 @@ func (s *Module) restoreNode(n mpt.Node) error {
|
|||
// If so, then jumping to P state sync point occurs. It is not protected by lock, thus caller
|
||||
// should take care of it.
|
||||
func (s *Module) checkSyncIsCompleted() {
|
||||
oldStage := s.syncStage
|
||||
defer func() {
|
||||
if s.syncStage != oldStage {
|
||||
s.notifyStageChanged()
|
||||
}
|
||||
}()
|
||||
if s.syncStage != headersSynced|mptSynced|blocksSynced {
|
||||
return
|
||||
}
|
||||
|
@ -484,6 +532,14 @@ func (s *Module) NeedMPTNodes() bool {
|
|||
return s.syncStage&headersSynced != 0 && s.syncStage&mptSynced == 0
|
||||
}
|
||||
|
||||
// NeedBlocks returns whether the module hasn't completed blocks synchronisation.
|
||||
func (s *Module) NeedBlocks() bool {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
return s.syncStage&headersSynced != 0 && s.syncStage&blocksSynced == 0
|
||||
}
|
||||
|
||||
// Traverse traverses local MPT nodes starting from the specified root down to its
|
||||
// children calling `process` for each serialised node until stop condition is satisfied.
|
||||
func (s *Module) Traverse(root util.Uint256, process func(node mpt.Node, nodeBytes []byte) bool) error {
|
||||
|
@ -495,7 +551,7 @@ func (s *Module) Traverse(root util.Uint256, process func(node mpt.Node, nodeByt
|
|||
if s.bc.GetConfig().Ledger.KeepOnlyLatestState || s.bc.GetConfig().Ledger.RemoveUntraceableBlocks {
|
||||
mode |= mpt.ModeLatest
|
||||
}
|
||||
b := mpt.NewBillet(root, mode, 0, storage.NewMemCachedStore(s.dao.Store))
|
||||
b := mpt.NewBillet(root, mode, mpt.DummySTTempStoragePrefix, storage.NewMemCachedStore(s.dao.Store))
|
||||
return b.Traverse(func(pathToNode []byte, node mpt.Node, nodeBytes []byte) bool {
|
||||
return process(node, nodeBytes)
|
||||
}, false)
|
||||
|
@ -508,3 +564,13 @@ func (s *Module) GetUnknownMPTNodesBatch(limit int) []util.Uint256 {
|
|||
|
||||
return s.mptpool.GetBatch(limit)
|
||||
}
|
||||
|
||||
// HeaderHeight returns the height of the latest stored header.
|
||||
func (s *Module) HeaderHeight() uint32 {
|
||||
return s.bc.HeaderHeight()
|
||||
}
|
||||
|
||||
// GetConfig returns current blockchain configuration.
|
||||
func (s *Module) GetConfig() config.Blockchain {
|
||||
return s.bc.GetConfig()
|
||||
}
|
||||
|
|
|
@ -19,12 +19,14 @@ func TestMemCachedPutGetDelete(t *testing.T) {
|
|||
|
||||
s.Put(key, value)
|
||||
|
||||
require.Equal(t, 1, s.Len())
|
||||
result, err := s.Get(key)
|
||||
assert.Nil(t, err)
|
||||
require.Equal(t, value, result)
|
||||
|
||||
s.Delete(key)
|
||||
|
||||
require.Equal(t, 1, s.Len()) // deletion marker
|
||||
_, err = s.Get(key)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, err, ErrKeyNotFound)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue