mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-03-14 13:28:39 +00:00
Compare commits
162 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 | ||
|
9189b3eb7d | ||
|
b285cf8c6e | ||
|
fec1ac8aee | ||
|
53ab704971 | ||
|
3f651cde27 | ||
|
39cec7d0d6 | ||
|
388ee25cd6 | ||
|
9e3f75e977 | ||
|
f82088b851 | ||
|
be4fc98041 | ||
|
247ee831e5 | ||
|
e0c8bebd05 | ||
|
9834b83cf0 | ||
|
90b6a42331 | ||
|
9599fba24f | ||
|
7d89a53043 | ||
|
c53b0645bb | ||
|
c7f5f173ae | ||
|
46cbfab264 | ||
|
38f635bce0 | ||
|
65bdc82da8 | ||
|
c79ffa967f | ||
|
283ca5cb6c | ||
|
3c372de570 | ||
|
cb4b21fcf4 | ||
|
ea0a6114d2 | ||
|
15cc559c73 | ||
|
1447158f2b | ||
|
62615f8c7e | ||
|
e530ba0791 | ||
|
b058b6cf21 | ||
|
6d1eea307b | ||
|
e993c1bdac | ||
|
4fa5fdc39c | ||
|
0bd378770d | ||
|
727262a95a | ||
|
827acfca23 | ||
|
35c2c5cc0e | ||
|
3010324c4f | ||
|
5f92da21fa | ||
|
703e066acc | ||
|
c84dac501d | ||
|
703bf6c458 | ||
|
2bc41dbe30 | ||
|
a68856c27c | ||
|
5f09e00e44 | ||
|
fc705433a3 | ||
|
a164db92cc | ||
|
981ae10091 | ||
|
109319d220 | ||
|
c812150d83 | ||
|
49267f3412 | ||
|
1aed0faeec | ||
|
d69f8ebbab | ||
|
121307d349 | ||
|
8952922c4d | ||
|
2244d2ad75 | ||
|
0879018e03 | ||
|
f7ee66ff8b | ||
|
8fe2ae8437 |
153 changed files with 7401 additions and 1340 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
|
||||
|
|
122
CHANGELOG.md
122
CHANGELOG.md
|
@ -2,6 +2,128 @@
|
|||
|
||||
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`
|
||||
application-level extension allowing to remove untraceable block headers from the DB.
|
||||
This feature significantly reduces the database size, but for now it is supported in
|
||||
an experimental mode, use it with care. Other than that, this release includes a fix
|
||||
of BlockFetcher service that may hang on retry of NeoFS requests preventing the node
|
||||
from syncing. Also, an improved algorithm of blocks uploading and extended list of
|
||||
block and index file attributes are supported for `upload-bin` CLI command.
|
||||
|
||||
No configuration update or DB resync is required. However, starting from this release
|
||||
`NeoFSBlockFetcher` application configuration section is backed by default values for
|
||||
every parameter except `Addresses` and `ContainerID`, hence if you don't like too
|
||||
chatty configuration files, feel free to remove all optional parameters.
|
||||
|
||||
New features:
|
||||
* untraceable headers removal (#3750)
|
||||
|
||||
Behavior changes:
|
||||
* add `BlockTime` attribute to block objects stored in NeoFS block storage (#3749)
|
||||
* use `Timestamp` attribute to hold object creation time for block and index objects
|
||||
stored in NeoFS block storage (#3749)
|
||||
* extended debug logs for `upload-bin` CLI command (#3751)
|
||||
|
||||
Improvements:
|
||||
* embed default UnitTestNet node configuration (#3696)
|
||||
* NeoFS SDK dependency upgrade (#3725, #3756)
|
||||
* dependent packages updates (#3746, #3747, #3748)
|
||||
* refactor and speed up `upload-bin` CLI command (#3735)
|
||||
* backup NeoFS BlockFetcher configuration with default values (#3742)
|
||||
* reuse more of built-in NeoFS SDK functionality in `upload-bin` CLI handler (#3749)
|
||||
|
||||
Bugs fixed:
|
||||
* NeoFS BlockFetcher sometimes is hanging during the node startup (#3736)
|
||||
* RPC server timers are improperly drained (#3737)
|
||||
* basic unit test chain restore configuration (#3696)
|
||||
|
||||
## 0.107.1 "Narrativization" (06 Dec 2024)
|
||||
|
||||
An urgent version that fixes the problem of intensive CPU usage caused by improper
|
||||
NeoFS BlockFetcher shutdown on the node's sync process completion and magnified by
|
||||
additional bug at the peer discovery level.
|
||||
|
||||
No configuration changes or DB resync is required. It is highly recommended to update
|
||||
from 0.107.0 as soon as possible since described problems affect the speed of blocks
|
||||
processing and the overall node functionality.
|
||||
|
||||
Behavior changes:
|
||||
* explicitly enable the list of stable hardforks in default NeoFS testnet
|
||||
configuration (#3722)
|
||||
|
||||
Improvements:
|
||||
* decrease NeoFS storage nodes deal timeout for NeoFS BlockFetcher (#3723)
|
||||
* adjust optimal number of peers for networks with small peer count (#3727)
|
||||
* don't enable unstable hardforks by default (#3724)
|
||||
|
||||
Bugs fixed:
|
||||
* "unexpected empty payload: CMDVersion" error on peer disconnection (#3726)
|
||||
* NeoFS BlockFetcher shutdown (#3728)
|
||||
* connected peers count is not respected on attempt to gather more node addresses
|
||||
(#3730)
|
||||
|
||||
## 0.107.0 "Mongrelization" (03 Dec 2024)
|
||||
|
||||
A large update that introduces a major node extension: NeoFS BlockFetcher service and
|
||||
|
|
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
|
||||
}
|
||||
|
|
|
@ -11,10 +11,40 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||
vmcli "github.com/nspcc-dev/neo-go/cli/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/services/helpers/neofs"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"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.
|
||||
|
@ -34,76 +64,44 @@ 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",
|
||||
Usage: "Size of index file",
|
||||
Value: 128000,
|
||||
Value: neofs.DefaultIndexFileSize,
|
||||
},
|
||||
&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.BoolFlag{
|
||||
Name: "skip-blocks-uploading",
|
||||
Usage: "Skip blocks uploading and upload only index files",
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "retries",
|
||||
Usage: "Maximum number of Neo/NeoFS node request retries",
|
||||
Value: 5,
|
||||
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",
|
||||
|
@ -184,10 +182,17 @@ func NewCommands() []*cli.Command {
|
|||
{
|
||||
Name: "upload-bin",
|
||||
Usage: "Fetch blocks from RPC node and upload them to the NeoFS container",
|
||||
UsageText: "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>] [--skip-blocks-uploading] [--retries <num>] [--debug]",
|
||||
UsageText: "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]",
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -2,9 +2,7 @@ package util
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -15,84 +13,31 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||
"github.com/nspcc-dev/neo-go/pkg/services/oracle/neofs"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/checksum"
|
||||
"github.com/nspcc-dev/neo-go/pkg/services/helpers/neofs"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/client"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||
"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/nspcc-dev/neofs-sdk-go/version"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
// Number of objects to upload in a batch. All batches of uploadBatchSize size
|
||||
// except the most recent one are guaranteed to be completed and don't contain gaps.
|
||||
uploadBatchSize = 10000
|
||||
// Number of objects to search in a batch. If it is larger than uploadBatchSize,
|
||||
// it may lead to many duplicate uploads. We need to search with EQ filter to
|
||||
// avoid partially-completed SEARCH responses.
|
||||
searchBatchSize = 1
|
||||
// Size of object ID.
|
||||
oidSize = sha256.Size
|
||||
)
|
||||
|
||||
// Constants related to retry mechanism.
|
||||
const (
|
||||
// Initial backoff duration.
|
||||
initialBackoff = 500 * time.Millisecond
|
||||
// Backoff multiplier.
|
||||
backoffFactor = 2
|
||||
// Maximum backoff duration.
|
||||
maxBackoff = 20 * time.Second
|
||||
)
|
||||
|
||||
// Constants related to NeoFS pool request timeouts.
|
||||
// Such big values are used to avoid NeoFS pool timeouts during block search and upload.
|
||||
const (
|
||||
defaultDialTimeout = 10 * time.Minute
|
||||
defaultStreamTimeout = 10 * time.Minute
|
||||
defaultHealthcheckTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
// 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.Int("workers")
|
||||
maxParallelSearches := ctx.Int("searchers")
|
||||
maxRetries := int(ctx.Uint("retries"))
|
||||
numWorkers := ctx.Uint("workers")
|
||||
maxParallelSearches := ctx.Uint("searchers")
|
||||
maxRetries := ctx.Uint("retries")
|
||||
debug := ctx.Bool("debug")
|
||||
indexFileSize := ctx.Uint("index-file-size")
|
||||
indexAttrKey := ctx.String("index-attribute")
|
||||
acc, _, err := options.GetAccFromContext(ctx)
|
||||
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)
|
||||
|
@ -100,50 +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(defaultHealthcheckTimeout)
|
||||
params.SetNodeDialTimeout(defaultDialTimeout)
|
||||
params.SetNodeStreamTimeout(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 net netmap.NetworkInfo
|
||||
err = retry(func() error {
|
||||
var errNet error
|
||||
net, errNet = p.NetworkInfo(ctx.Context, client.PrmNetworkInfo{})
|
||||
return errNet
|
||||
}, maxRetries)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Errorf("failed to get network info: %w", err), 1)
|
||||
}
|
||||
homomorphicHashingDisabled := net.HomomorphicHashingDisabled()
|
||||
|
||||
var containerObj container.Container
|
||||
err = retry(func() error {
|
||||
containerObj, err = p.ContainerGet(ctx.Context, containerID, client.PrmContainerGet{})
|
||||
return err
|
||||
}, maxRetries)
|
||||
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()
|
||||
|
@ -151,137 +66,64 @@ func uploadBin(ctx *cli.Context) error {
|
|||
return cli.Exit(fmt.Sprintf("failed to get current block height from RPC: %v", err), 1)
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, "Chain block height:", currentBlockHeight)
|
||||
|
||||
oldestMissingBlockIndex, errBlock := fetchLatestMissingBlockIndex(ctx.Context, p, containerID, acc.PrivateKey(), attr, int(currentBlockHeight), maxParallelSearches, maxRetries)
|
||||
if errBlock != nil {
|
||||
return cli.Exit(fmt.Errorf("failed to fetch the oldest missing block index from container: %w", errBlock), 1)
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, "First block of latest incomplete batch uploaded to NeoFS container:", oldestMissingBlockIndex)
|
||||
|
||||
if !ctx.Bool("skip-blocks-uploading") {
|
||||
err = uploadBlocks(ctx, pWrapper, rpc, signer, containerID, acc, attr, oldestMissingBlockIndex, uint(currentBlockHeight), homomorphicHashingDisabled, numWorkers, maxRetries, debug)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Errorf("failed to upload blocks: %w", err), 1)
|
||||
}
|
||||
oldestMissingBlockIndex = int(currentBlockHeight) + 1
|
||||
}
|
||||
|
||||
err = uploadIndexFiles(ctx, pWrapper, containerID, acc, signer, uint(oldestMissingBlockIndex), attr, homomorphicHashingDisabled, maxParallelSearches, maxRetries, debug)
|
||||
i, buf, err := searchIndexFile(ctx, pWrapper, containerID, acc.PrivateKey(), signer, indexFileSize, attr, indexAttrKey, maxParallelSearches, maxRetries, debug)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Errorf("failed to upload index files: %w", err), 1)
|
||||
return cli.Exit(fmt.Errorf("failed to find objects: %w", err), 1)
|
||||
}
|
||||
|
||||
err = uploadBlocksAndIndexFiles(ctx, pWrapper, rpc, signer, containerID, attr, indexAttrKey, buf, i, indexFileSize, uint(currentBlockHeight), numWorkers, maxRetries, debug)
|
||||
if err != nil {
|
||||
return cli.Exit(fmt.Errorf("failed to upload objects: %w", err), 1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// retry function with exponential backoff.
|
||||
func retry(action func() error, maxRetries int) error {
|
||||
func retry(action func() error, maxRetries uint, debug bool) error {
|
||||
var err error
|
||||
backoff := initialBackoff
|
||||
for range maxRetries {
|
||||
backoff := neofs.InitialBackoff
|
||||
for i := range maxRetries {
|
||||
if err = action(); err == nil {
|
||||
return nil // Success, no retry needed.
|
||||
}
|
||||
if debug {
|
||||
fmt.Printf("Retry %d: %v\n", i, err)
|
||||
}
|
||||
time.Sleep(backoff) // Backoff before retrying.
|
||||
backoff *= time.Duration(backoffFactor)
|
||||
if backoff > maxBackoff {
|
||||
backoff = maxBackoff
|
||||
backoff *= time.Duration(neofs.BackoffFactor)
|
||||
if backoff > neofs.MaxBackoff {
|
||||
backoff = neofs.MaxBackoff
|
||||
}
|
||||
}
|
||||
return err // Return the last error after exhausting retries.
|
||||
}
|
||||
|
||||
type searchResult struct {
|
||||
startIndex int
|
||||
endIndex int
|
||||
numOIDs int
|
||||
err error
|
||||
}
|
||||
|
||||
// fetchLatestMissingBlockIndex searches the container for the latest full batch of blocks
|
||||
// starting from the currentHeight and going backwards. It returns the index of first block
|
||||
// in the next batch.
|
||||
func fetchLatestMissingBlockIndex(ctx context.Context, p *pool.Pool, containerID cid.ID, priv *keys.PrivateKey, attributeKey string, currentHeight int, maxParallelSearches, maxRetries int) (int, error) {
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
numBatches = currentHeight / searchBatchSize
|
||||
emptyBatchFound bool
|
||||
pWrapper = poolWrapper{p}
|
||||
)
|
||||
|
||||
for batch := numBatches; batch > -maxParallelSearches; batch -= maxParallelSearches {
|
||||
results := make([]searchResult, maxParallelSearches)
|
||||
|
||||
for i := range maxParallelSearches {
|
||||
startIndex := (batch + i) * searchBatchSize
|
||||
endIndex := startIndex + searchBatchSize
|
||||
if endIndex <= 0 {
|
||||
continue
|
||||
}
|
||||
if startIndex < 0 {
|
||||
startIndex = 0
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(i, startIndex, endIndex int) {
|
||||
defer wg.Done()
|
||||
|
||||
prm := client.PrmObjectSearch{}
|
||||
filters := object.NewSearchFilters()
|
||||
if endIndex == startIndex+1 {
|
||||
filters.AddFilter(attributeKey, fmt.Sprintf("%d", startIndex), object.MatchStringEqual)
|
||||
} else {
|
||||
filters.AddFilter(attributeKey, fmt.Sprintf("%d", startIndex), object.MatchNumGE)
|
||||
filters.AddFilter(attributeKey, fmt.Sprintf("%d", endIndex), object.MatchNumLT)
|
||||
}
|
||||
prm.SetFilters(filters)
|
||||
var (
|
||||
objectIDs []oid.ID
|
||||
err error
|
||||
)
|
||||
err = retry(func() error {
|
||||
objectIDs, err = neofs.ObjectSearch(ctx, pWrapper, priv, containerID.String(), prm)
|
||||
return err
|
||||
}, maxRetries)
|
||||
results[i] = searchResult{startIndex: startIndex, endIndex: endIndex, numOIDs: len(objectIDs), err: err}
|
||||
}(i, startIndex, endIndex)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
for i := len(results) - 1; i >= 0; i-- {
|
||||
if results[i].err != nil {
|
||||
return 0, fmt.Errorf("blocks search failed for batch with indexes from %d to %d: %w", results[i].startIndex, results[i].endIndex-1, results[i].err)
|
||||
}
|
||||
if results[i].numOIDs == 0 {
|
||||
emptyBatchFound = true
|
||||
continue
|
||||
}
|
||||
if emptyBatchFound || (batch == numBatches && i == len(results)-1) {
|
||||
return results[i].startIndex / uploadBatchSize * uploadBatchSize, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// uploadBlocks uploads the blocks to the container using the pool.
|
||||
func uploadBlocks(ctx *cli.Context, p poolWrapper, rpc *rpcclient.Client, signer user.Signer, containerID cid.ID, acc *wallet.Account, attr string, oldestMissingBlockIndex int, currentBlockHeight uint, homomorphicHashingDisabled bool, numWorkers, maxRetries int, debug bool) error {
|
||||
if oldestMissingBlockIndex > int(currentBlockHeight) {
|
||||
fmt.Fprintf(ctx.App.Writer, "No new blocks to upload. Need to upload starting from %d, current height %d\n", oldestMissingBlockIndex, currentBlockHeight)
|
||||
// uploadBlocksAndIndexFiles uploads the blocks and index files to the container using the pool.
|
||||
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
|
||||
}
|
||||
for batchStart := oldestMissingBlockIndex; batchStart <= int(currentBlockHeight); batchStart += uploadBatchSize {
|
||||
fmt.Fprintln(ctx.App.Writer, "Uploading blocks and index files...")
|
||||
for indexFileStart := currentIndexFileID * indexFileSize; indexFileStart < currentBlockHeight; indexFileStart += indexFileSize {
|
||||
var (
|
||||
batchEnd = min(batchStart+uploadBatchSize, int(currentBlockHeight)+1)
|
||||
errCh = make(chan error)
|
||||
doneCh = make(chan struct{})
|
||||
wg sync.WaitGroup
|
||||
indexFileEnd = min(indexFileStart+indexFileSize, currentBlockHeight)
|
||||
errCh = make(chan error)
|
||||
doneCh = make(chan struct{})
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
fmt.Fprintf(ctx.App.Writer, "Processing batch from %d to %d\n", batchStart, batchEnd-1)
|
||||
wg.Add(numWorkers)
|
||||
fmt.Fprintf(ctx.App.Writer, "Processing batch from %d to %d\n", indexFileStart, indexFileEnd-1)
|
||||
wg.Add(int(numWorkers))
|
||||
for i := range numWorkers {
|
||||
go func(i int) {
|
||||
go func(i uint) {
|
||||
defer wg.Done()
|
||||
for blockIndex := batchStart + i; blockIndex < batchEnd; blockIndex += numWorkers {
|
||||
for blockIndex := indexFileStart + i; blockIndex < indexFileEnd; blockIndex += numWorkers {
|
||||
if !oid.ID(buf[blockIndex%indexFileSize*oid.Size : blockIndex%indexFileSize*oid.Size+oid.Size]).IsZero() {
|
||||
if debug {
|
||||
fmt.Fprintf(ctx.App.Writer, "Block %d is already uploaded\n", blockIndex)
|
||||
}
|
||||
continue
|
||||
}
|
||||
var blk *block.Block
|
||||
errGet := retry(func() error {
|
||||
var errGetBlock error
|
||||
|
@ -290,7 +132,7 @@ func uploadBlocks(ctx *cli.Context, p poolWrapper, rpc *rpcclient.Client, signer
|
|||
return fmt.Errorf("failed to fetch block %d: %w", blockIndex, errGetBlock)
|
||||
}
|
||||
return nil
|
||||
}, maxRetries)
|
||||
}, maxRetries, debug)
|
||||
if errGet != nil {
|
||||
select {
|
||||
case errCh <- errGet:
|
||||
|
@ -313,12 +155,17 @@ func uploadBlocks(ctx *cli.Context, p poolWrapper, rpc *rpcclient.Client, signer
|
|||
*object.NewAttribute("Primary", strconv.Itoa(int(blk.PrimaryIndex))),
|
||||
*object.NewAttribute("Hash", blk.Hash().StringLE()),
|
||||
*object.NewAttribute("PrevHash", blk.PrevHash.StringLE()),
|
||||
*object.NewAttribute("Timestamp", strconv.FormatUint(blk.Timestamp, 10)),
|
||||
*object.NewAttribute("BlockTime", strconv.FormatUint(blk.Timestamp, 10)),
|
||||
*object.NewAttribute("Timestamp", strconv.FormatInt(time.Now().Unix(), 10)),
|
||||
}
|
||||
|
||||
objBytes := bw.Bytes()
|
||||
var (
|
||||
objBytes = bw.Bytes()
|
||||
resOid oid.ID
|
||||
)
|
||||
errRetr := retry(func() error {
|
||||
resOid, errUpload := uploadObj(ctx.Context, p, signer, acc.PrivateKey().GetScriptHash(), containerID, objBytes, attrs, homomorphicHashingDisabled)
|
||||
var errUpload error
|
||||
resOid, errUpload = uploadObj(ctx.Context, p, signer, containerID, objBytes, attrs)
|
||||
if errUpload != nil {
|
||||
return errUpload
|
||||
}
|
||||
|
@ -326,7 +173,7 @@ func uploadBlocks(ctx *cli.Context, p poolWrapper, rpc *rpcclient.Client, signer
|
|||
fmt.Fprintf(ctx.App.Writer, "Uploaded block %d with object ID: %s\n", blockIndex, resOid.String())
|
||||
}
|
||||
return errUpload
|
||||
}, maxRetries)
|
||||
}, maxRetries, debug)
|
||||
if errRetr != nil {
|
||||
select {
|
||||
case errCh <- errRetr:
|
||||
|
@ -334,6 +181,7 @@ func uploadBlocks(ctx *cli.Context, p poolWrapper, rpc *rpcclient.Client, signer
|
|||
}
|
||||
return
|
||||
}
|
||||
copy(buf[blockIndex%indexFileSize*oid.Size:], resOid[:])
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
@ -348,195 +196,148 @@ func uploadBlocks(ctx *cli.Context, p poolWrapper, rpc *rpcclient.Client, signer
|
|||
return fmt.Errorf("upload error: %w", err)
|
||||
case <-doneCh:
|
||||
}
|
||||
fmt.Fprintf(ctx.App.Writer, "Successfully processed batch of blocks: from %d to %d\n", indexFileStart, indexFileEnd-1)
|
||||
|
||||
fmt.Fprintf(ctx.App.Writer, "Successfully uploaded batch of blocks: from %d to %d\n", batchStart, batchEnd-1)
|
||||
// Additional check for empty OIDs in the buffer.
|
||||
for k := uint(0); k < (indexFileEnd-indexFileStart)*oid.Size; k += oid.Size {
|
||||
if oid.ID(buf[k : k+oid.Size]).IsZero() {
|
||||
return fmt.Errorf("empty OID found in index file %d at position %d (block index %d)", indexFileStart/indexFileSize, k/oid.Size, indexFileStart/indexFileSize*indexFileSize+k/oid.Size)
|
||||
}
|
||||
}
|
||||
if indexFileEnd-indexFileStart == indexFileSize {
|
||||
attrs := []object.Attribute{
|
||||
*object.NewAttribute(indexAttributeKey, strconv.Itoa(int(indexFileStart/indexFileSize))),
|
||||
*object.NewAttribute("IndexSize", strconv.Itoa(int(indexFileSize))),
|
||||
*object.NewAttribute("Timestamp", strconv.FormatInt(time.Now().Unix(), 10)),
|
||||
}
|
||||
err := retry(func() error {
|
||||
var errUpload error
|
||||
_, errUpload = uploadObj(ctx.Context, p, signer, containerID, buf, attrs)
|
||||
return errUpload
|
||||
}, maxRetries, debug)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upload index file: %w", err)
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, "Successfully uploaded index file ", indexFileStart/indexFileSize)
|
||||
}
|
||||
clear(buf)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// uploadIndexFiles uploads missing index files to the container.
|
||||
func uploadIndexFiles(ctx *cli.Context, p poolWrapper, containerID cid.ID, account *wallet.Account, signer user.Signer, oldestMissingBlockIndex uint, blockAttributeKey string, homomorphicHashingDisabled bool, maxParallelSearches, maxRetries int, debug bool) error {
|
||||
// searchIndexFile returns the ID and buffer for the next index file to be uploaded.
|
||||
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 (
|
||||
attributeKey = ctx.String("index-attribute")
|
||||
indexFileSize = ctx.Uint("index-file-size")
|
||||
// buf is used to store OIDs of the uploaded blocks.
|
||||
buf = make([]byte, indexFileSize*oid.Size)
|
||||
doneCh = make(chan struct{})
|
||||
errCh = make(chan error)
|
||||
|
||||
buffer = make([]byte, indexFileSize*oidSize)
|
||||
doneCh = make(chan struct{})
|
||||
errCh = make(chan error)
|
||||
emptyOid = make([]byte, oidSize)
|
||||
|
||||
expectedIndexCount = (oldestMissingBlockIndex - 1) / indexFileSize
|
||||
existingIndexCount = uint(0)
|
||||
filters = object.NewSearchFilters()
|
||||
)
|
||||
fmt.Fprintln(ctx.App.Writer, "Uploading index files...")
|
||||
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
// Search for existing index files.
|
||||
filters.AddFilter("IndexSize", fmt.Sprintf("%d", indexFileSize), object.MatchStringEqual)
|
||||
indexIDs := searchObjects(ctx.Context, p, containerID, account, attributeKey, 0, expectedIndexCount, maxParallelSearches, maxRetries, errCh, filters)
|
||||
for range indexIDs {
|
||||
for i := 0; ; i++ {
|
||||
indexIDs := searchObjects(ctx.Context, p, containerID, privKeys, attributeKey, uint(i), uint(i+1), 1, maxRetries, debug, errCh, filters)
|
||||
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 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)
|
||||
|
||||
if existingIndexCount >= expectedIndexCount {
|
||||
fmt.Fprintf(ctx.App.Writer, "Index files are up to date. Existing: %d, expected: %d\n", existingIndexCount, expectedIndexCount)
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(ctx.App.Writer, "Current index files count: %d, expected: %d\n", existingIndexCount, expectedIndexCount)
|
||||
|
||||
// Main processing loop for each index file.
|
||||
for i := existingIndexCount; i < expectedIndexCount; i++ {
|
||||
// Start block parsing goroutines.
|
||||
var (
|
||||
// processedIndices is a mapping from position in buffer to the block index.
|
||||
processedIndices sync.Map
|
||||
wg sync.WaitGroup
|
||||
oidCh = make(chan oid.ID, 2*maxParallelSearches)
|
||||
)
|
||||
wg.Add(maxParallelSearches)
|
||||
for range maxParallelSearches {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for id := range oidCh {
|
||||
var obj object.Object
|
||||
errRetr := retry(func() error {
|
||||
var errGet error
|
||||
obj, _, errGet = p.ObjectGetInit(ctx.Context, containerID, id, signer, client.PrmObjectGet{})
|
||||
return errGet
|
||||
}, maxRetries)
|
||||
if errRetr != nil {
|
||||
select {
|
||||
case errCh <- fmt.Errorf("failed to fetch object %s: %w", id.String(), errRetr):
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
blockIndex, err := getBlockIndex(obj, blockAttributeKey)
|
||||
if err != nil {
|
||||
select {
|
||||
case errCh <- fmt.Errorf("failed to get block index from object %s: %w", id.String(), err):
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
pos := uint(blockIndex) % indexFileSize
|
||||
if _, ok := processedIndices.LoadOrStore(pos, blockIndex); !ok {
|
||||
id.Encode(buffer[pos*oidSize:])
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Search for blocks within the index file range.
|
||||
startIndex := i * indexFileSize
|
||||
endIndex := startIndex + indexFileSize
|
||||
objIDs := searchObjects(ctx.Context, p, containerID, account, blockAttributeKey, startIndex, endIndex, maxParallelSearches, maxRetries, errCh)
|
||||
for id := range objIDs {
|
||||
oidCh <- id
|
||||
}
|
||||
close(oidCh)
|
||||
wg.Wait()
|
||||
fmt.Fprintf(ctx.App.Writer, "Index file %d generated, checking for the missing blocks...\n", i)
|
||||
|
||||
// Check if there are empty OIDs in the generated index file. This may happen
|
||||
// if searchObjects has returned not all blocks within the requested range, ref.
|
||||
// #3645. In this case, retry the search for every missing object.
|
||||
var count int
|
||||
for idx := range indexFileSize {
|
||||
if _, ok := processedIndices.Load(idx); !ok {
|
||||
count++
|
||||
fmt.Fprintf(ctx.App.Writer, "Index file %d: fetching missing block %d\n", i, i*indexFileSize+idx)
|
||||
objIDs = searchObjects(ctx.Context, p, containerID, account, blockAttributeKey, i*indexFileSize+idx, i*indexFileSize+idx+1, 1, maxRetries, errCh)
|
||||
// Block object duplicates are allowed, we're OK with the first found result.
|
||||
id, ok := <-objIDs
|
||||
for range objIDs {
|
||||
}
|
||||
if !ok {
|
||||
// Start block parsing goroutines.
|
||||
var (
|
||||
// processedIndices is a mapping from position in buffer to the block index.
|
||||
// It prevents duplicates.
|
||||
processedIndices sync.Map
|
||||
wg sync.WaitGroup
|
||||
oidCh = make(chan oid.ID, 2*maxParallelSearches)
|
||||
)
|
||||
wg.Add(int(maxParallelSearches))
|
||||
for range maxParallelSearches {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for id := range oidCh {
|
||||
var obj object.Object
|
||||
errRetr := retry(func() error {
|
||||
var errGet error
|
||||
obj, _, errGet = p.ObjectGetInit(ctx.Context, containerID, id, signer, client.PrmObjectGet{})
|
||||
return errGet
|
||||
}, maxRetries, debug)
|
||||
if errRetr != nil {
|
||||
select {
|
||||
case errCh <- fmt.Errorf("index file %d: block %d is missing from the storage", i, i*indexFileSize+idx):
|
||||
case errCh <- fmt.Errorf("failed to fetch object %s: %w", id.String(), errRetr):
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
processedIndices.Store(idx, id)
|
||||
id.Encode(buffer[idx*oidSize:])
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(ctx.App.Writer, "%d missing block(s) processed for index file %d, uploading index file...\n", count, i)
|
||||
|
||||
// Check if there are empty OIDs in the generated index file. If it happens at
|
||||
// this stage, then there's a bug in the code.
|
||||
for k := 0; k < len(buffer); k += oidSize {
|
||||
if slices.Compare(buffer[k:k+oidSize], emptyOid) == 0 {
|
||||
select {
|
||||
case errCh <- fmt.Errorf("empty OID found in index file %d at position %d (block index %d)", i, k/oidSize, i*indexFileSize+uint(k/oidSize)):
|
||||
default:
|
||||
blockIndex, err := getBlockIndex(obj, blockAttributeKey)
|
||||
if err != nil {
|
||||
select {
|
||||
case errCh <- fmt.Errorf("failed to get block index from object %s: %w", id.String(), err):
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
pos := uint(blockIndex) % indexFileSize
|
||||
if _, ok := processedIndices.LoadOrStore(pos, blockIndex); !ok {
|
||||
copy(buf[pos*oid.Size:], id[:])
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Upload index file.
|
||||
attrs := []object.Attribute{
|
||||
*object.NewAttribute(attributeKey, strconv.Itoa(int(i))),
|
||||
*object.NewAttribute("IndexSize", strconv.Itoa(int(indexFileSize))),
|
||||
}
|
||||
err := retry(func() error {
|
||||
resOid, errUpload := uploadObj(ctx.Context, p, signer, account.PrivateKey().GetScriptHash(), containerID, buffer, attrs, homomorphicHashingDisabled)
|
||||
if errUpload != nil {
|
||||
return errUpload
|
||||
}
|
||||
if debug {
|
||||
fmt.Fprintf(ctx.App.Writer, "Uploaded idex file %d with object ID: %s\n", i, resOid.String())
|
||||
}
|
||||
return errUpload
|
||||
}, maxRetries)
|
||||
if err != nil {
|
||||
select {
|
||||
case errCh <- fmt.Errorf("failed to upload index file %d: %w", i, err):
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(ctx.App.Writer, "Uploaded index file %d\n", i)
|
||||
clear(buffer)
|
||||
}()
|
||||
}
|
||||
|
||||
// Search for blocks within the index file range.
|
||||
objIDs := searchObjects(ctx.Context, p, containerID, privKeys, blockAttributeKey, existingIndexCount*indexFileSize, (existingIndexCount+1)*indexFileSize, maxParallelSearches, maxRetries, debug, errCh)
|
||||
for id := range objIDs {
|
||||
oidCh <- id
|
||||
}
|
||||
close(oidCh)
|
||||
wg.Wait()
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return err
|
||||
return existingIndexCount, nil, err
|
||||
case <-doneCh:
|
||||
return existingIndexCount, buf, nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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, account *wallet.Account, blockAttributeKey string, startIndex, endIndex uint, maxParallelSearches, maxRetries int, errCh chan error, additionalFilters ...object.SearchFilters) chan oid.ID {
|
||||
var res = make(chan oid.ID, 2*searchBatchSize)
|
||||
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
|
||||
defer close(res)
|
||||
|
||||
for i := int(startIndex); i < int(endIndex); i += searchBatchSize * maxParallelSearches {
|
||||
for i := startIndex; i < endIndex; i += neofs.DefaultSearchBatchSize * maxParallelSearches {
|
||||
for j := range maxParallelSearches {
|
||||
start := i + j*searchBatchSize
|
||||
end := start + searchBatchSize
|
||||
start := i + j*neofs.DefaultSearchBatchSize
|
||||
end := start + neofs.DefaultSearchBatchSize
|
||||
|
||||
if start >= int(endIndex) {
|
||||
if start >= endIndex {
|
||||
break
|
||||
}
|
||||
if end > int(endIndex) {
|
||||
end = int(endIndex)
|
||||
if end > endIndex {
|
||||
end = endIndex
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(start, end int) {
|
||||
go func(start, end uint) {
|
||||
defer wg.Done()
|
||||
|
||||
prm := client.PrmObjectSearch{}
|
||||
|
@ -555,9 +356,9 @@ func searchObjects(ctx context.Context, p poolWrapper, containerID cid.ID, accou
|
|||
var objIDs []oid.ID
|
||||
err := retry(func() error {
|
||||
var errBlockSearch error
|
||||
objIDs, errBlockSearch = neofs.ObjectSearch(ctx, p, account.PrivateKey(), containerID.String(), prm)
|
||||
objIDs, errBlockSearch = neofs.ObjectSearch(ctx, p, privKeys, containerID.String(), prm)
|
||||
return errBlockSearch
|
||||
}, maxRetries)
|
||||
}, maxRetries, debug)
|
||||
if err != nil {
|
||||
select {
|
||||
case errCh <- fmt.Errorf("failed to search for block(s) from %d to %d: %w", start, end, err):
|
||||
|
@ -579,41 +380,16 @@ func searchObjects(ctx context.Context, p poolWrapper, containerID cid.ID, accou
|
|||
}
|
||||
|
||||
// uploadObj uploads object to the container using provided settings.
|
||||
func uploadObj(ctx context.Context, p poolWrapper, signer user.Signer, owner util.Uint160, containerID cid.ID, objData []byte, attrs []object.Attribute, homomorphicHashingDisabled bool) (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 (
|
||||
ownerID user.ID
|
||||
hdr object.Object
|
||||
chSHA256 checksum.Checksum
|
||||
chHomomorphic checksum.Checksum
|
||||
v = new(version.Version)
|
||||
prmObjectPutInit client.PrmObjectPutInit
|
||||
resOID = oid.ID{}
|
||||
)
|
||||
|
||||
ownerID.SetScriptHash(owner)
|
||||
hdr.SetPayload(objData)
|
||||
hdr.SetPayloadSize(uint64(len(objData)))
|
||||
hdr.SetContainerID(containerID)
|
||||
hdr.SetOwnerID(&ownerID)
|
||||
hdr.SetOwner(signer.UserID())
|
||||
hdr.SetAttributes(attrs...)
|
||||
hdr.SetCreationEpoch(1)
|
||||
v.SetMajor(1)
|
||||
hdr.SetVersion(v)
|
||||
if !homomorphicHashingDisabled {
|
||||
checksum.Calculate(&chHomomorphic, checksum.TZ, objData)
|
||||
hdr.SetPayloadHomomorphicHash(chHomomorphic)
|
||||
}
|
||||
checksum.Calculate(&chSHA256, checksum.SHA256, objData)
|
||||
hdr.SetPayloadChecksum(chSHA256)
|
||||
|
||||
err := hdr.SetIDWithSignature(signer)
|
||||
if err != nil {
|
||||
return resOID, err
|
||||
}
|
||||
err = hdr.CheckHeaderVerificationFields()
|
||||
if err != nil {
|
||||
return resOID, err
|
||||
}
|
||||
|
||||
writer, err := p.ObjectPutInit(ctx, hdr, signer, prmObjectPutInit)
|
||||
if err != nil {
|
||||
|
@ -630,9 +406,6 @@ func uploadObj(ctx context.Context, p poolWrapper, signer user.Signer, owner uti
|
|||
}
|
||||
res := writer.GetResult()
|
||||
resOID = res.StoredObjectID()
|
||||
if resOID.Equals(oid.ID{}) {
|
||||
return resOID, fmt.Errorf("object ID is empty")
|
||||
}
|
||||
return resOID, nil
|
||||
}
|
||||
|
||||
|
@ -649,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])...)
|
||||
|
|
|
@ -30,3 +30,8 @@ var MainNetNeoFS []byte
|
|||
//
|
||||
//go:embed protocol.testnet.neofs.yml
|
||||
var TestNetNeoFS []byte
|
||||
|
||||
// UnitTestNet is the unit test network configuration.
|
||||
//
|
||||
//go:embed protocol.unit_testnet.yml
|
||||
var UnitTestNet []byte
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -24,6 +24,11 @@ ProtocolConfiguration:
|
|||
- morph7.t5.fs.neo.org:50333
|
||||
VerifyTransactions: true
|
||||
P2PSigExtensions: true
|
||||
Hardforks:
|
||||
Aspidochelone: 0
|
||||
Basilisk: 0
|
||||
Cockatrice: 0
|
||||
Domovoi: 0
|
||||
|
||||
ApplicationConfiguration:
|
||||
SkipBlockVerification: false
|
||||
|
@ -95,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"
|
||||
|
|
|
@ -18,7 +18,11 @@ ProtocolConfiguration:
|
|||
VerifyTransactions: true
|
||||
P2PSigExtensions: true
|
||||
Hardforks:
|
||||
Aspidochelone: 25
|
||||
Aspidochelone: 3
|
||||
Basilisk: 6
|
||||
Cockatrice: 9
|
||||
Domovoi: 12
|
||||
Echidna: 13
|
||||
|
||||
ApplicationConfiguration:
|
||||
SkipBlockVerification: false
|
||||
|
|
|
@ -16,13 +16,15 @@ form as a separate object with a unique OID and a set of attributes:
|
|||
- primary node index (`Primary:0`)
|
||||
- block hash in the LE form (`Hash:5412a781caf278c0736556c0e544c7cfdbb6e3c62ae221ef53646be89364566b`)
|
||||
- previous block hash in the LE form (`PrevHash:3654a054d82a8178c7dfacecc2c57282e23468a42ee407f14506368afe22d929`)
|
||||
- millisecond-precision block timestamp (`Timestamp:1627894840919`)
|
||||
- millisecond-precision block creation timestamp (`BlockTime:1627894840919`)
|
||||
- second-precision block uploading timestamp (`Timestamp:1627894840`)
|
||||
|
||||
Each index file is an object containing a constant-sized batch of raw block object
|
||||
IDs in binary form ordered by block index. Each index file is marked with the
|
||||
following attributes:
|
||||
- index file identifier with consecutive file index value (`Index:0`)
|
||||
- the number of OIDs included into index file (`IndexSize:128000`)
|
||||
- second-precision index file uploading timestamp (`Timestamp:1627894840`)
|
||||
|
||||
### NeoFS BlockFetcher
|
||||
|
||||
|
@ -71,48 +73,54 @@ 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>] [--skip-blocks-uploading] [--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)
|
||||
--skip-blocks-uploading Skip blocks uploading and upload only index files (default: false)
|
||||
--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.
|
||||
2. Searches for the oldest half-filled batch of block objects stored in NeoFS.
|
||||
3. Fetches missing blocks from the RPC node and uploads them to the NeoFS container
|
||||
starting from the oldest half-filled batch.
|
||||
4. After uploading the blocks, it creates index files for the newly uploaded blocks.
|
||||
5. Uploads the created index files to the NeoFS container.
|
||||
2. Searches for the index files stored in NeoFS.
|
||||
3. Searches for the stored blocks from the latest incomplete index file.
|
||||
4. Fetches missing blocks from the RPC node and uploads them to the NeoFS container.
|
||||
5. After uploading the blocks, it creates index file based on the uploaded block OIDs.
|
||||
6. Uploads the created index file to the NeoFS container.
|
||||
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 oldest half-filled batch of blocks.
|
||||
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`), `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.
|
||||
|
||||
### 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. |
|
||||
|
@ -30,10 +30,12 @@ node-related settings described in the table below.
|
|||
| Relay | `bool` | `true` | Determines whether the server is forwarding its inventory. |
|
||||
| Consensus | [Consensus Configuration](#Consensus-Configuration) | | Describes consensus (dBFT) configuration. See the [Consensus Configuration](#Consensus-Configuration) for details. |
|
||||
| RemoveUntraceableBlocks | `bool`| `false` | Denotes whether old blocks should be removed from cache and database. If enabled, then only the last `MaxTraceableBlocks` are stored and accessible to smart contracts. Old MPT data is also deleted in accordance with `GarbageCollectionPeriod` setting. If enabled along with `P2PStateExchangeExtensions` protocol extension, then old blocks and MPT states will be removed up to the second latest state synchronisation point (see `StateSyncInterval`). |
|
||||
| RemoveUntraceableHeaders | `bool`| `false` | Used only with RemoveUntraceableBlocks and makes node delete untraceable block headers as well. Notice that this is an experimental option, not recommended for production use. |
|
||||
| RPC | [RPC Configuration](#RPC-Configuration) | | Describes [RPC subsystem](rpc.md) configuration. See the [RPC Configuration](#RPC-Configuration) for details. |
|
||||
| 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
|
||||
|
||||
|
@ -99,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.
|
||||
|
@ -184,27 +191,28 @@ where:
|
|||
- `UnlockWallet` contains wallet settings to retrieve account to sign requests to
|
||||
NeoFS. Without this setting, the module will use randomly generated private key.
|
||||
For configuration details see [Unlock Wallet Configuration](#Unlock-Wallet-Configuration)
|
||||
- `Addresses` is a list of NeoFS storage nodes addresses.
|
||||
- `Timeout` is a timeout for a single request to NeoFS storage node.
|
||||
- `ContainerID` is a container ID to fetch blocks from.
|
||||
- `Addresses` is a list of NeoFS storage nodes addresses. This parameter is required.
|
||||
- `Timeout` is a timeout for a single request to NeoFS storage node (10 minutes by
|
||||
default).
|
||||
- `ContainerID` is a container ID to fetch blocks from. This parameter is required.
|
||||
- `BlockAttribute` is an attribute name of NeoFS object that contains block
|
||||
data.
|
||||
data. It's set to `Block` by default.
|
||||
- `IndexFileAttribute` is an attribute name of NeoFS index object that contains block
|
||||
object IDs.
|
||||
object IDs. It's set to `Index` by default.
|
||||
- `DownloaderWorkersCount` is a number of workers that download blocks from
|
||||
NeoFS in parallel.
|
||||
NeoFS in parallel (500 by default).
|
||||
- `OIDBatchSize` is the number of blocks to search per a single request to NeoFS
|
||||
in case of disabled index files search. Also, for both modes of BlockFetcher
|
||||
operation this setting manages the buffer size of OIDs and blocks transferring
|
||||
channels.
|
||||
channels. By default, it's set to a half of `BQueueSize` parameter.
|
||||
- `BQueueSize` is a size of the block queue used to manage consecutive blocks
|
||||
addition to the chain. It must be larger than `OIDBatchSize` and highly recommended
|
||||
to be `2*OIDBatchSize` or `3*OIDBatchSize`.
|
||||
to be `2*OIDBatchSize` or `3*OIDBatchSize`. By default, it's set to 16000.
|
||||
- `SkipIndexFilesSearch` is a flag that allows to skip index files search and search
|
||||
for blocks directly. It is set to `false` by default.
|
||||
- `IndexFileSize` is the number of OID objects stored in the index files. This
|
||||
setting depends on the NeoFS block storage configuration and is applicable only if
|
||||
`SkipIndexFilesSearch` is set to `false`.
|
||||
`SkipIndexFilesSearch` is set to `false`. It's set to 128000 by default.
|
||||
|
||||
### Metrics Services Configuration
|
||||
|
||||
|
@ -243,6 +251,7 @@ RPC:
|
|||
MaxRequestBodyBytes: 5242880
|
||||
MaxRequestHeaderBytes: 1048576
|
||||
MaxWebSocketClients: 64
|
||||
MaxWebSocketFeeds: 16
|
||||
SessionEnabled: false
|
||||
SessionExpirationTime: 15
|
||||
SessionBackedByMPT: false
|
||||
|
@ -288,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
|
||||
|
@ -385,7 +397,7 @@ protocol-related settings described in the table below.
|
|||
| --- | --- | --- | --- | --- |
|
||||
| CommitteeHistory | map[uint32]uint32 | none | Number of committee members after the given height, for example `{0: 1, 20: 4}` sets up a chain with one committee member since the genesis and then changes the setting to 4 committee members at the height of 20. `StandbyCommittee` committee setting must have the number of keys equal or exceeding the highest value in this option. Blocks numbers where the change happens must be divisible by the old and by the new values simultaneously. If not set, committee size is derived from the `StandbyCommittee` setting and never changes. |
|
||||
| Genesis | [Genesis](#Genesis-Configuration) | none | The set of genesis block settings including NeoGo-specific protocol extensions that should be enabled at the genesis block or during native contracts initialisation. |
|
||||
| Hardforks | `map[string]uint32` | [] | The set of incompatible changes that affect node behaviour starting from the specified height. The default value is an empty set which should be interpreted as "each known hard-fork is applied from the zero blockchain height". The list of valid hard-fork names:<br>• `Aspidochelone` represents hard-fork introduced in [#2469](https://github.com/nspcc-dev/neo-go/pull/2469) (ported from the [reference](https://github.com/neo-project/neo/pull/2712)). It adjusts the prices of `System.Contract.CreateStandardAccount` and `System.Contract.CreateMultisigAccount` interops so that the resulting prices are in accordance with `sha256` method of native `CryptoLib` contract. It also includes [#2519](https://github.com/nspcc-dev/neo-go/pull/2519) (ported from the [reference](https://github.com/neo-project/neo/pull/2749)) that adjusts the price of `System.Runtime.GetRandom` interop and fixes its vulnerability. A special NeoGo-specific change is included as well for ContractManagement's update/deploy call flags behaviour to be compatible with pre-0.99.0 behaviour that was changed because of the [3.2.0 protocol change](https://github.com/neo-project/neo/pull/2653).<br>• `Basilisk` represents hard-fork introduced in [#3056](https://github.com/nspcc-dev/neo-go/pull/3056) (ported from the [reference](https://github.com/neo-project/neo/pull/2881)). It enables strict smart contract script check against a set of JMP instructions and against method boundaries enabled on contract deploy or update. It also includes [#3080](https://github.com/nspcc-dev/neo-go/pull/3080) (ported from the [reference](https://github.com/neo-project/neo/pull/2883)) that increases `stackitem.Integer` JSON parsing precision up to the maximum value supported by the NeoVM. It also includes [#3085](https://github.com/nspcc-dev/neo-go/pull/3085) (ported from the [reference](https://github.com/neo-project/neo/pull/2810)) that enables strict check for notifications emitted by a contract to precisely match the events specified in the contract manifest. <br>• `Cockatrice` represents hard-fork introduced in [#3402](https://github.com/nspcc-dev/neo-go/pull/3402) (ported from the [reference](https://github.com/neo-project/neo/pull/2942)). Initially it is introduced along with the ability to update native contracts. This hard-fork also includes a couple of new native smart contract APIs: `keccak256` of native CryptoLib contract introduced in [#3301](https://github.com/nspcc-dev/neo-go/pull/3301) (ported from the [reference](https://github.com/neo-project/neo/pull/2925)) and `getCommitteeAddress` of native NeoToken contract inctroduced in [#3362](https://github.com/nspcc-dev/neo-go/pull/3362) (ported from the [reference](https://github.com/neo-project/neo/pull/3154)).<br>• `Domovoi` represents hard-fork introduced in [#3476](https://github.com/nspcc-dev/neo-go/pull/3476) (ported from the [reference](https://github.com/neo-project/neo/pull/3290)). This hard-fork makes the node use executing contract state for the contract call permissions check instead of the state stored in the native Management. This change was introduced in [#3473](https://github.com/nspcc-dev/neo-go/pull/3473) and ported to the [reference](https://github.com/neo-project/neo/pull/3290). Also, this hard-fork makes the System.Runtime.GetNotifications interop properly count stack references of notification parameters which prevents users from creating objects that exceed [vm.MaxStackSize] constraint. This change is implemented in the [reference](https://github.com/neo-project/neo/pull/3301), but NeoGo has never had this bug, thus proper behaviour is preserved even before HFDomovoi. It results in the fact that some T5 transactions have different ApplicationLogs comparing to the C# node, but the node states match. See [#3485](https://github.com/nspcc-dev/neo-go/pull/3485) for details on NeoGo behaviour. |
|
||||
| Hardforks | `map[string]uint32` | [] | The set of incompatible changes that affect node behaviour starting from the specified height. The default value is an empty set which should be interpreted as "each known stable hard-fork is applied from the zero blockchain height". See [Hardforks](#Hardforks) section for a list of supported keys. |
|
||||
| Magic | `uint32` | `0` | Magic number which uniquely identifies Neo network. |
|
||||
| MaxBlockSize | `uint32` | `262144` | Maximum block size in bytes. |
|
||||
| MaxBlockSystemFee | `int64` | `900000000000` | Maximum overall transactions system fee per block. |
|
||||
|
@ -457,6 +469,20 @@ where:
|
|||
Note that `Transaction` is a NeoGo extension that isn't supported by the NeoC#
|
||||
node and must be disabled on the public Neo N3 networks.
|
||||
|
||||
### Hardforks
|
||||
|
||||
The latest stable hardfork as per 0.107.1 release is Domovoi. Echidna is still
|
||||
in development and can change in an incompatible way.
|
||||
|
||||
| Name | Changes | References |
|
||||
| --- | --- | --- |
|
||||
| `Aspidochelone` | Adjusts the price of `System.Contract.CreateStandardAccount` and `System.Contract.CreateMultisigAccount` interops so that the resulting prices are in accordance with `sha256` method of native `CryptoLib` contract. Also adjusts the price of `System.Runtime.GetRandom` interop and fixes its vulnerability. A special NeoGo-specific change is included as well for ContractManagement's update/deploy call flags behaviour to be compatible with pre-0.99.0 behaviour that was changed because of the 3.2.0 protocol change | https://github.com/nspcc-dev/neo-go/pull/2469 <br> https://github.com/neo-project/neo/pull/2712 <br> https://github.com/nspcc-dev/neo-go/pull/2519 <br> https://github.com/neo-project/neo/pull/2749 <br> https://github.com/neo-project/neo/pull/2653 |
|
||||
| `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` | 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
|
||||
|
||||
Real networks with large number of blocks require a substantial amount of time
|
||||
|
@ -474,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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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
|
||||
|
@ -48,17 +47,17 @@ require (
|
|||
go.etcd.io/bbolt v1.3.11 // 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.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
|
||||
golang.org/x/mod v0.20.0 // indirect
|
||||
golang.org/x/net v0.28.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.28.0 // indirect
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 h1:arN0Ypn+jawZpu1BND7TGRn44InAVIqKygndsx0y2no=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12 h1:mdxtlSU2I4oVZ/7AXTLKyz8uUPbDWikZw4DM8gvrddA=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12/go.mod h1:JdsEM1qgNukrWqgOBDChcYp8oY4XUzidcKaxY4hNJvQ=
|
||||
github.com/nspcc-dev/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=
|
||||
|
@ -131,8 +207,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.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
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.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||
|
@ -144,8 +220,8 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R
|
|||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
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=
|
||||
|
@ -155,33 +231,31 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
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.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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,13 +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-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
|
||||
|
@ -50,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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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=
|
||||
|
|
29
go.mod
29
go.mod
|
@ -13,10 +13,10 @@ 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-20240727093519-1a48f1ce43ec
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12
|
||||
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
|
||||
github.com/prometheus/client_golang v1.20.2
|
||||
|
@ -26,16 +26,15 @@ require (
|
|||
github.com/urfave/cli/v2 v2.27.4
|
||||
go.etcd.io/bbolt v1.3.11
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.26.0
|
||||
golang.org/x/term v0.23.0
|
||||
golang.org/x/text v0.17.0
|
||||
golang.org/x/crypto v0.31.0
|
||||
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.62.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
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/blang/semver/v4 v4.0.0 // indirect
|
||||
|
@ -45,7 +44,6 @@ require (
|
|||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/frankban/quicktest v1.14.5 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
|
||||
github.com/ingonyama-zk/icicle v1.1.0 // indirect
|
||||
|
@ -55,9 +53,9 @@ require (
|
|||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nspcc-dev/hrw/v2 v2.0.1 // indirect
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 // indirect
|
||||
github.com/nspcc-dev/tzhash v1.7.2 // indirect
|
||||
github.com/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/tzhash v1.8.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
|
@ -71,9 +69,10 @@ require (
|
|||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
|
||||
golang.org/x/mod v0.20.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect
|
||||
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
|
||||
)
|
||||
|
|
130
go.sum
130
go.sum
|
@ -2,12 +2,10 @@ 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.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
|
||||
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
|
||||
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=
|
||||
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=
|
||||
|
@ -30,10 +28,12 @@ github.com/consensys/gnark v0.11.0 h1:YlndnlbRAoIEA+aIIHzNIW4P0dCIOM9/jCVzsXf356
|
|||
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/containerd/containerd v1.7.13 h1:wPYKIeGMN8vaggSKuV1X0wZulpMz4CrgEsZdaCyB6Is=
|
||||
github.com/containerd/containerd v1.7.13/go.mod h1:zT3up6yTRfEUa6+GsITYIJNgSVL9NQ4x4h1RPzk0Wu4=
|
||||
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/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
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=
|
||||
|
@ -44,14 +44,16 @@ 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/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0=
|
||||
github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
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=
|
||||
|
@ -59,6 +61,10 @@ github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWo
|
|||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
|
@ -71,15 +77,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.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
|
@ -124,10 +126,14 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||
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/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
|
||||
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
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=
|
||||
|
@ -136,22 +142,22 @@ 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.1 h1:CxYUkBeJvNfMEn2lHhrV6FjY8pZPceSxXUtMVq0BUOU=
|
||||
github.com/nspcc-dev/hrw/v2 v2.0.1/go.mod h1:iZAs5hT2q47EGq6AZ0FjaUI6ggntOi7vrY4utfzk5VA=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 h1:arN0Ypn+jawZpu1BND7TGRn44InAVIqKygndsx0y2no=
|
||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12 h1:mdxtlSU2I4oVZ/7AXTLKyz8uUPbDWikZw4DM8gvrddA=
|
||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12/go.mod h1:JdsEM1qgNukrWqgOBDChcYp8oY4XUzidcKaxY4hNJvQ=
|
||||
github.com/nspcc-dev/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-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=
|
||||
|
@ -163,10 +169,8 @@ 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-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
|
||||
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
|
||||
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/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
|
@ -194,8 +198,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/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4=
|
||||
github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4=
|
||||
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=
|
||||
|
@ -204,12 +208,12 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
|||
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.24.1 h1:gJdZuQIVWnMJTo+CmQMEP7/CAagNk/0jbcUPn3OWvD8=
|
||||
github.com/testcontainers/testcontainers-go v0.24.1/go.mod h1:MGBiAkCm86yXQoCiipmQCqZLVdk1uFqtMqaU1Or0MRk=
|
||||
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
||||
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
||||
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
|
||||
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
||||
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=
|
||||
|
@ -222,6 +226,14 @@ github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFi
|
|||
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=
|
||||
|
@ -230,8 +242,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.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
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.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||
|
@ -243,8 +255,8 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R
|
|||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
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=
|
||||
|
@ -258,33 +270,31 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
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.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
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.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
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/internal/examples/oracle
|
|||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec
|
||||
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-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -310,7 +310,7 @@ func getMethod(t *testing.T, ctr interop.ContractMD, name string, params []strin
|
|||
name = strings.TrimSuffix(name, "WithData")
|
||||
}
|
||||
|
||||
latestHF := config.LatestHardfork()
|
||||
latestHF := config.HFLatestKnown
|
||||
cMD := ctr.HFSpecificContractMD(&latestHF)
|
||||
md, ok := cMD.GetMethod(name, paramLen)
|
||||
require.True(t, ok, cMD.Manifest.Name, name, paramLen)
|
||||
|
|
|
@ -206,20 +206,6 @@ func TestNeoFSBlockFetcherValidation(t *testing.T) {
|
|||
shouldFail: true,
|
||||
errMsg: "BQueueSize (5) is lower than OIDBatchSize (10)",
|
||||
},
|
||||
{
|
||||
cfg: NeoFSBlockFetcher{
|
||||
InternalService: InternalService{Enabled: true},
|
||||
Timeout: time.Second,
|
||||
ContainerID: validContainerID,
|
||||
Addresses: []string{"127.0.0.1"},
|
||||
OIDBatchSize: 10,
|
||||
BQueueSize: 20,
|
||||
SkipIndexFilesSearch: false,
|
||||
IndexFileSize: 0,
|
||||
},
|
||||
shouldFail: true,
|
||||
errMsg: "IndexFileSize is not set",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
|
|
|
@ -38,14 +38,11 @@ func (cfg *NeoFSBlockFetcher) Validate() error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("invalid container ID: %w", err)
|
||||
}
|
||||
if cfg.BQueueSize < cfg.OIDBatchSize {
|
||||
if cfg.BQueueSize > 0 && cfg.BQueueSize < cfg.OIDBatchSize {
|
||||
return fmt.Errorf("BQueueSize (%d) is lower than OIDBatchSize (%d)", cfg.BQueueSize, cfg.OIDBatchSize)
|
||||
}
|
||||
if len(cfg.Addresses) == 0 {
|
||||
return errors.New("addresses are not set")
|
||||
}
|
||||
if !cfg.SkipIndexFilesSearch && cfg.IndexFileSize == 0 {
|
||||
return errors.New("IndexFileSize is not set")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ func (c Config) Blockchain() Blockchain {
|
|||
return Blockchain{
|
||||
ProtocolConfiguration: c.ProtocolConfiguration,
|
||||
Ledger: c.ApplicationConfiguration.Ledger,
|
||||
NeoFSBlockFetcher: c.ApplicationConfiguration.NeoFSBlockFetcher,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,6 +138,8 @@ func getEmbeddedConfig(configPath string) ([]byte, error) {
|
|||
return config.MainNetNeoFS, nil
|
||||
case fmt.Sprintf("%s/protocol.%s.yml", DefaultConfigPath, netmode.TestNetNeoFS):
|
||||
return config.TestNetNeoFS, nil
|
||||
case fmt.Sprintf("%s/protocol.%s.yml", DefaultConfigPath, netmode.UnitTestNet):
|
||||
return config.UnitTestNet, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("config '%s' doesn't exist and no matching embedded config was found", configPath)
|
||||
}
|
||||
|
|
|
@ -44,27 +44,44 @@ 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.
|
||||
hfLast
|
||||
)
|
||||
|
||||
// HFLatestStable is the latest known stable hardfork that is enabled by
|
||||
// default. The set above can contain other hardforks and even some name
|
||||
// placeholders, but they need to be enabled manually then. It can change
|
||||
// between releases even if the set of known hardforks is the same.
|
||||
const HFLatestStable = HFDomovoi
|
||||
|
||||
// HFLatestKnown is the latest known hardfork.
|
||||
const HFLatestKnown = hfLast >> 1
|
||||
|
||||
// StableHardforks is an ordered slice of all stable hardforks (before or
|
||||
// equal [HFLatestStable]).
|
||||
var StableHardforks []Hardfork
|
||||
|
||||
// Hardforks represents the ordered slice of all possible hardforks.
|
||||
var Hardforks []Hardfork
|
||||
|
||||
// hardforks holds a map of Hardfork string representation to its type.
|
||||
var hardforks map[string]Hardfork
|
||||
var hardforks = make(map[string]Hardfork)
|
||||
|
||||
func init() {
|
||||
var stableIndex int
|
||||
|
||||
for i := HFAspidochelone; i < hfLast; i = i << 1 {
|
||||
if i <= HFLatestStable {
|
||||
stableIndex++
|
||||
}
|
||||
Hardforks = append(Hardforks, i)
|
||||
hardforks[i.String()] = i
|
||||
}
|
||||
hardforks = make(map[string]Hardfork, len(Hardforks))
|
||||
for _, hf := range Hardforks {
|
||||
hardforks[hf.String()] = hf
|
||||
}
|
||||
StableHardforks = Hardforks[:stableIndex]
|
||||
}
|
||||
|
||||
// Cmp returns the result of hardforks comparison. It returns:
|
||||
|
@ -97,8 +114,3 @@ func IsHardforkValid(s string) bool {
|
|||
_, ok := hardforks[s]
|
||||
return ok
|
||||
}
|
||||
|
||||
// LatestHardfork returns latest known hardfork.
|
||||
func LatestHardfork() Hardfork {
|
||||
return hfLast >> 1
|
||||
}
|
||||
|
|
|
@ -14,11 +14,16 @@ type Ledger struct {
|
|||
KeepOnlyLatestState bool `yaml:"KeepOnlyLatestState"`
|
||||
// RemoveUntraceableBlocks specifies if old data should be removed.
|
||||
RemoveUntraceableBlocks bool `yaml:"RemoveUntraceableBlocks"`
|
||||
// RemoveUntraceableHeaders is used in addition to RemoveUntraceableBlocks
|
||||
// when headers need to be removed as well.
|
||||
RemoveUntraceableHeaders bool `yaml:"RemoveUntraceableHeaders"`
|
||||
// SaveStorageBatch enables storage batch saving before every persist.
|
||||
SaveStorageBatch bool `yaml:"SaveStorageBatch"`
|
||||
// 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
|
||||
|
@ -26,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
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru/v2"
|
||||
json "github.com/nspcc-dev/go-ordered-json"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/limits"
|
||||
|
@ -60,7 +61,23 @@ 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
|
||||
// blocks and GC interval is more like 10K, so this is sufficient for 80K
|
||||
// deviation and should be sufficient. If it's not, it's not a big issue
|
||||
// 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.
|
||||
|
@ -156,6 +173,19 @@ 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())
|
||||
gcBlockTimes *lru.Cache[uint32, uint64]
|
||||
|
||||
// Stop synchronization mechanisms.
|
||||
stopCh chan struct{}
|
||||
runToExitCh chan struct{}
|
||||
|
@ -270,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")
|
||||
|
@ -278,17 +311,30 @@ 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))
|
||||
}
|
||||
}
|
||||
if cfg.RemoveUntraceableHeaders && !cfg.RemoveUntraceableBlocks {
|
||||
return nil, errors.New("RemoveUntraceableHeaders is enabled, but RemoveUntraceableBlocks is not")
|
||||
}
|
||||
if cfg.Hardforks == nil {
|
||||
cfg.Hardforks = map[string]uint32{}
|
||||
for _, hf := range config.Hardforks {
|
||||
for _, hf := range config.StableHardforks {
|
||||
cfg.Hardforks[hf.String()] = 0
|
||||
}
|
||||
log.Info("Hardforks are not set, using default value")
|
||||
log.Info("Hardforks are not set, enabling all stable ones", zap.Stringer("latest", config.HFLatestStable))
|
||||
} else if len(cfg.Hardforks) != 0 {
|
||||
// Explicitly set the height of all old omitted hardforks to 0 for proper
|
||||
// IsHardforkEnabled behaviour.
|
||||
|
@ -321,6 +367,8 @@ 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
|
||||
|
||||
|
@ -417,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
|
||||
|
@ -454,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
|
||||
|
||||
|
@ -603,7 +656,7 @@ func (bc *Blockchain) jumpToStateInternal(p uint32, stage stateChangeStage) erro
|
|||
// After current state is updated, we need to remove outdated state-related data if so.
|
||||
// The only outdated data we might have is genesis-related data, so check it.
|
||||
if p-bc.config.MaxTraceableBlocks > 0 {
|
||||
err := cache.DeleteBlock(bc.GetHeaderHash(0))
|
||||
_, err := cache.DeleteBlock(bc.GetHeaderHash(0), false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to remove outdated state data for the genesis block: %w", err)
|
||||
}
|
||||
|
@ -797,7 +850,7 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
|
|||
keysCnt = new(int)
|
||||
)
|
||||
for i := height + 1; i <= currHeight; i++ {
|
||||
err := upperCache.DeleteBlock(bc.GetHeaderHash(i))
|
||||
_, err := upperCache.DeleteBlock(bc.GetHeaderHash(i), false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while removing block %d: %w", i, err)
|
||||
}
|
||||
|
@ -1070,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
|
||||
}
|
||||
}
|
||||
|
@ -1084,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 {
|
||||
|
@ -1094,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)
|
||||
}
|
||||
|
@ -1141,10 +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 {
|
||||
tgtBlock /= int64(bc.config.Ledger.GarbageCollectionPeriod)
|
||||
tgtBlock *= int64(bc.config.Ledger.GarbageCollectionPeriod)
|
||||
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
|
||||
}
|
||||
|
@ -1288,15 +1336,20 @@ func appendTokenTransferInfo(transferData *state.TokenTransferInfo,
|
|||
|
||||
func (bc *Blockchain) removeOldTransfers(index uint32) time.Duration {
|
||||
bc.log.Info("starting transfer data garbage collection", zap.Uint32("index", index))
|
||||
start := time.Now()
|
||||
h, err := bc.GetHeader(bc.GetHeaderHash(index))
|
||||
if err != nil {
|
||||
var (
|
||||
err error
|
||||
kept int64
|
||||
removed int64
|
||||
start = time.Now()
|
||||
ts, ok = bc.gcBlockTimes.Get(index)
|
||||
)
|
||||
|
||||
if !ok {
|
||||
dur := time.Since(start)
|
||||
bc.log.Error("failed to find block header for transfer GC", zap.Duration("time", dur), zap.Error(err))
|
||||
bc.log.Error("failed to get block timestamp transfer GC", zap.Duration("time", dur), zap.Uint32("index", index))
|
||||
return dur
|
||||
}
|
||||
var removed, kept int64
|
||||
var ts = h.Timestamp
|
||||
|
||||
prefixes := []byte{byte(storage.STNEP11Transfers), byte(storage.STNEP17Transfers)}
|
||||
|
||||
for i := range prefixes {
|
||||
|
@ -1622,7 +1675,10 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
|||
stop = start + 1
|
||||
}
|
||||
for index := start; index < stop; index++ {
|
||||
err := kvcache.DeleteBlock(bc.GetHeaderHash(index))
|
||||
ts, err := kvcache.DeleteBlock(bc.GetHeaderHash(index), bc.config.Ledger.RemoveUntraceableHeaders)
|
||||
if index%bc.config.Ledger.GarbageCollectionPeriod == 0 {
|
||||
_ = bc.gcBlockTimes.Add(index, ts)
|
||||
}
|
||||
if err != nil {
|
||||
bc.log.Warn("error while removing old block",
|
||||
zap.Uint32("index", index),
|
||||
|
@ -1717,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)
|
||||
|
@ -1774,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()
|
||||
|
@ -2125,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
|
||||
|
@ -2133,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
|
||||
}
|
||||
|
@ -2154,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),
|
||||
|
@ -2164,6 +2239,7 @@ func (bc *Blockchain) persist(isSync bool) (time.Duration, error) {
|
|||
// update monitoring metrics.
|
||||
updatePersistedHeightMetric(bHeight)
|
||||
}
|
||||
bc.persistCond.Signal()
|
||||
|
||||
return duration, nil
|
||||
}
|
||||
|
@ -2774,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)
|
||||
|
@ -3093,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)
|
||||
|
@ -106,6 +106,7 @@ func TestRemoveOldTransfers(t *testing.T) {
|
|||
|
||||
_, err = bc.dao.Persist()
|
||||
require.NoError(t, err)
|
||||
_ = bc.gcBlockTimes.Add(0, h.Timestamp)
|
||||
_ = bc.removeOldTransfers(0)
|
||||
|
||||
for i := range uint32(2) {
|
||||
|
@ -139,6 +140,33 @@ func TestRemoveOldTransfers(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func checkNewBlockchainErr(t *testing.T, cfg func(c *config.Config), store storage.Store, errText string) {
|
||||
unitTestNetCfg, err := config.Load("../../config", testchain.Network())
|
||||
require.NoError(t, err)
|
||||
cfg(&unitTestNetCfg)
|
||||
log := zaptest.NewLogger(t)
|
||||
_, err = NewBlockchain(store, unitTestNetCfg.Blockchain(), log)
|
||||
if len(errText) != 0 {
|
||||
require.Error(t, err)
|
||||
require.True(t, strings.Contains(err.Error(), errText))
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewBlockchainIncosistencies(t *testing.T) {
|
||||
t.Run("untraceable blocks/headers", func(t *testing.T) {
|
||||
checkNewBlockchainErr(t, func(c *config.Config) {
|
||||
c.ApplicationConfiguration.RemoveUntraceableHeaders = true
|
||||
}, storage.NewMemoryStore(), "RemoveUntraceableHeaders is enabled, but RemoveUntraceableBlocks is not")
|
||||
})
|
||||
t.Run("state exchange without state root", func(t *testing.T) {
|
||||
checkNewBlockchainErr(t, func(c *config.Config) {
|
||||
c.ProtocolConfiguration.P2PStateExchangeExtensions = true
|
||||
}, storage.NewMemoryStore(), "P2PStatesExchangeExtensions are enabled, but StateRootInHeader is off")
|
||||
})
|
||||
}
|
||||
|
||||
func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
|
||||
var (
|
||||
stateSyncInterval = 4
|
||||
|
@ -186,19 +214,6 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
|
|||
_, err := batch.Persist()
|
||||
require.NoError(t, err)
|
||||
|
||||
checkNewBlockchainErr := func(t *testing.T, cfg func(c *config.Config), store storage.Store, errText string) {
|
||||
unitTestNetCfg, err := config.Load("../../config", testchain.Network())
|
||||
require.NoError(t, err)
|
||||
cfg(&unitTestNetCfg)
|
||||
log := zaptest.NewLogger(t)
|
||||
_, err = NewBlockchain(store, unitTestNetCfg.Blockchain(), log)
|
||||
if len(errText) != 0 {
|
||||
require.Error(t, err)
|
||||
require.True(t, strings.Contains(err.Error(), errText))
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
boltCfg := func(c *config.Config) {
|
||||
spountCfg(c)
|
||||
c.ApplicationConfiguration.KeepOnlyLatestState = true
|
||||
|
@ -373,7 +388,6 @@ func TestNewBlockchain_InitHardforks(t *testing.T) {
|
|||
config.HFBasilisk.String(): 0,
|
||||
config.HFCockatrice.String(): 0,
|
||||
config.HFDomovoi.String(): 0,
|
||||
config.HFEchidna.String(): 0,
|
||||
}, bc.GetConfig().Hardforks)
|
||||
})
|
||||
t.Run("empty set", 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
|
||||
|
@ -765,17 +771,22 @@ func (dao *Simple) StoreAsBlock(block *block.Block, aer1 *state.AppExecResult, a
|
|||
}
|
||||
|
||||
// DeleteBlock removes the block from dao. It's not atomic, so make sure you're
|
||||
// using private MemCached instance here.
|
||||
func (dao *Simple) DeleteBlock(h util.Uint256) error {
|
||||
// using private MemCached instance here. It returns block timestamp for GC
|
||||
// convenience.
|
||||
func (dao *Simple) DeleteBlock(h util.Uint256, dropHeader bool) (uint64, error) {
|
||||
key := dao.makeExecutableKey(h)
|
||||
|
||||
b, err := dao.getBlock(key)
|
||||
if err != nil {
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
err = dao.storeHeader(key, &b.Header)
|
||||
if err != nil {
|
||||
return err
|
||||
if !dropHeader {
|
||||
err = dao.storeHeader(key, &b.Header)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
dao.Store.Delete(key)
|
||||
}
|
||||
|
||||
for _, tx := range b.Transactions {
|
||||
|
@ -787,7 +798,7 @@ func (dao *Simple) DeleteBlock(h util.Uint256) error {
|
|||
|
||||
v, err := dao.Store.Get(key)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve conflict record stub for %s (height %d, conflict %s): %w", tx.Hash().StringLE(), b.Index, hash.StringLE(), err)
|
||||
return 0, fmt.Errorf("failed to retrieve conflict record stub for %s (height %d, conflict %s): %w", tx.Hash().StringLE(), b.Index, hash.StringLE(), err)
|
||||
}
|
||||
// It might be a block since we allow transactions to have block hash in the Conflicts attribute.
|
||||
if v[0] != storage.ExecTransaction {
|
||||
|
@ -805,7 +816,7 @@ func (dao *Simple) DeleteBlock(h util.Uint256) error {
|
|||
sKey := append(key, s.Account.BytesBE()...)
|
||||
v, err := dao.Store.Get(sKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve conflict record for %s (height %d, conflict %s, signer %s): %w", tx.Hash().StringLE(), b.Index, hash.StringLE(), address.Uint160ToString(s.Account), err)
|
||||
return 0, fmt.Errorf("failed to retrieve conflict record for %s (height %d, conflict %s, signer %s): %w", tx.Hash().StringLE(), b.Index, hash.StringLE(), address.Uint160ToString(s.Account), err)
|
||||
}
|
||||
index = binary.LittleEndian.Uint32(v[1:])
|
||||
if index == b.Index {
|
||||
|
@ -815,7 +826,7 @@ func (dao *Simple) DeleteBlock(h util.Uint256) error {
|
|||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return b.Timestamp, nil
|
||||
}
|
||||
|
||||
// PurgeHeader completely removes specified header from dao. It differs from
|
||||
|
|
|
@ -74,6 +74,7 @@ func TestPutGetBlock(t *testing.T) {
|
|||
dao := NewSimple(storage.NewMemoryStore(), false)
|
||||
b := &block.Block{
|
||||
Header: block.Header{
|
||||
Timestamp: 42,
|
||||
Script: transaction.Witness{
|
||||
VerificationScript: []byte{byte(opcode.PUSH1)},
|
||||
InvocationScript: []byte{byte(opcode.NOP)},
|
||||
|
@ -107,6 +108,19 @@ func TestPutGetBlock(t *testing.T) {
|
|||
require.Equal(t, 2, len(gotAppExecResult))
|
||||
require.Equal(t, *appExecResult1, gotAppExecResult[0])
|
||||
require.Equal(t, *appExecResult2, gotAppExecResult[1])
|
||||
|
||||
ts, err := dao.DeleteBlock(hash, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(42), ts)
|
||||
gotBlock, err = dao.GetBlock(hash) // It's just a header, but it's still there.
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, gotBlock)
|
||||
|
||||
ts, err = dao.DeleteBlock(hash, true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(42), ts)
|
||||
_, err = dao.GetBlock(hash)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGetVersion_NoVersion(t *testing.T) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
func TestNamesASCII(t *testing.T) {
|
||||
cfg := config.ProtocolConfiguration{P2PSigExtensions: true}
|
||||
cs := NewContracts(cfg)
|
||||
latestHF := config.LatestHardfork()
|
||||
latestHF := config.HFLatestKnown
|
||||
for _, c := range cs.Contracts {
|
||||
require.True(t, isASCII(c.Metadata().Name))
|
||||
hfMD := c.Metadata().HFSpecificContractMD(&latestHF)
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
func TestNativeGetMethod(t *testing.T) {
|
||||
cfg := config.ProtocolConfiguration{P2PSigExtensions: true}
|
||||
cs := NewContracts(cfg)
|
||||
latestHF := config.LatestHardfork()
|
||||
latestHF := config.HFLatestKnown
|
||||
for _, c := range cs.Contracts {
|
||||
hfMD := c.Metadata().HFSpecificContractMD(&latestHF)
|
||||
t.Run(c.Metadata().Name, func(t *testing.T) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -139,6 +139,9 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
|
|||
mdDeploy := manState.Manifest.ABI.GetMethod("deploy", 2)
|
||||
require.NotNil(t, mdDeploy)
|
||||
t.Run("fail, bad call flag", func(t *testing.T) {
|
||||
bc, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
|
||||
c.Hardforks = nil
|
||||
})
|
||||
ic, err := bc.GetTestVM(trigger.Application, nil, nil)
|
||||
require.NoError(t, err)
|
||||
v := ic.SpawnVM()
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -401,6 +401,17 @@ func TestNEO_RecursiveGASMint(t *testing.T) {
|
|||
func TestNEO_GetCommitteeAddress(t *testing.T) {
|
||||
neoValidatorInvoker := newNeoValidatorsClient(t)
|
||||
e := neoValidatorInvoker.Executor
|
||||
cfg := neoValidatorInvoker.Chain.GetConfig()
|
||||
|
||||
maxHardforkHeight := uint32(0)
|
||||
for _, height := range cfg.Hardforks {
|
||||
if height > maxHardforkHeight {
|
||||
maxHardforkHeight = height
|
||||
}
|
||||
}
|
||||
for range maxHardforkHeight {
|
||||
neoValidatorInvoker.AddNewBlock(t)
|
||||
}
|
||||
standByCommitteePublicKeys, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee)
|
||||
require.NoError(t, err)
|
||||
slices.SortFunc(standByCommitteePublicKeys, (*keys.PublicKey).Cmp)
|
||||
|
@ -729,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 {
|
||||
|
@ -889,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)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue