mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-21 23:29:38 +00:00
Merge pull request #3150 from nspcc-dev/drop-deprecated
Drop deprecated things
This commit is contained in:
commit
2f747dd8d9
36 changed files with 89 additions and 2657 deletions
89
ROADMAP.md
89
ROADMAP.md
|
@ -26,95 +26,6 @@ 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.
|
||||
|
||||
## Old RPC client APIs
|
||||
|
||||
A huge set of RPC client APIs was deprecated in versions 0.99.2 and 0.99.3
|
||||
(August-September 2022), including very frequently used ones like
|
||||
SignAndPushInvocationTx, AddNetworkFee, TransferNEP17. A new set of
|
||||
invoker/actor/unwrap/nep17/etc packages was introduced decoupling these
|
||||
functions from RPC client and simplifying typical backend code. Please refer
|
||||
to rpcclient package documentation for specific replacements for each of these
|
||||
APIs and convert your code to using them.
|
||||
|
||||
While a lot of the code is already converted to new APIs, old ones still can
|
||||
be used in some code not known to us. Therefore we will remove old APIs not
|
||||
earlier than May 2023, with 0.103.0 release.
|
||||
|
||||
## WSClient Notifications channel and SubscribeFor* APIs
|
||||
|
||||
Version 0.99.5 of NeoGo introduces a new set of subscription APIs that gives
|
||||
more control to the WSClient user that can pass specific channels to be used
|
||||
for specific subscriptions now. Old APIs and generic Notifications channel are
|
||||
still available, but will be removed, so please convert your code to using new
|
||||
Receive* APIs.
|
||||
|
||||
Removal of these APIs is scheduled for May 2023 (~0.103.0 release).
|
||||
|
||||
## SecondsPerBlock protocol configuration
|
||||
|
||||
With 0.100.0 version SecondsPerBlock protocol configuration setting was
|
||||
deprecated and replaced by a bit more generic and precise TimePerBlock
|
||||
(allowing for subsecond time). An informational message is printed on node
|
||||
startup to inform about this, it's very easy to deal with this configuration
|
||||
change, just replace one line.
|
||||
|
||||
Removal of SecondsPerBlock is scheduled for May-June 2023 (~0.103.0 release).
|
||||
|
||||
## Services/node address and port configuration
|
||||
|
||||
Version 0.100.0 of NeoGo introduces a multiple binding addresses capability to
|
||||
the node's services (RPC server, TLS RPC configuration, Prometheus, Pprof) and
|
||||
the node itself. It allows to specify several listen addresses/ports using an
|
||||
array of "address:port" pairs in the service's `Addresses` config section and
|
||||
array of "address:port:announcedPort" tuples in the `ApplicationConfiguration`'s
|
||||
`Addresses` node config section. Deprecated `Address` and `Port` sections of
|
||||
`RPC`, `Prometheus`, `Pprof` subsections of the `ApplicationConfiguration`
|
||||
as far as the one of RPC server's `TLSConfig` are still available, but will be
|
||||
removed, so please convert your node configuration file to use new `P2P`-level
|
||||
`Addresses` section for the node services. Deprecated `Address`, `NodePort` and
|
||||
`AnnouncedPort` sections of `ApplicationConfiguration` will also be removed
|
||||
eventually, so please update your node configuration file to use `Addresses`
|
||||
section for the P2P addresses configuration.
|
||||
|
||||
Removal of these config sections is scheduled for May-June 2023 (~0.103.0 release).
|
||||
|
||||
## P2P application settings configuration
|
||||
|
||||
Version 0.100.0 of NeoGo marks the following P2P application settings as
|
||||
deprecated: `AttemptConnPeers`, `BroadcastFactor`, `DialTimeout`,
|
||||
`ExtensiblePoolSize`, `MaxPeers`, `MinPeers`, `PingInterval`, `PingTimeout`,
|
||||
`ProtoTickInterval`. These settings are moved to a separate `P2P` section of
|
||||
`ApplicationConfiguration`. The `DialTimeout`, `PingInterval`, `PingTimeout`,
|
||||
`ProtoTickInterval` settings are converted to more precise `Duration` format
|
||||
(allowing for subsecond time). Please, update your node configuration (all you
|
||||
need is to move specified settings under the `P2P` section and convert
|
||||
time-related settings to `Duration` format).
|
||||
|
||||
Removal of deprecated P2P related application settings is scheduled for May-June
|
||||
2023 (~0.103.0 release).
|
||||
|
||||
## Direct UnlockWallet consensus configuration
|
||||
|
||||
Top-level UnlockWallet section in ApplicationConfiguration was used as an
|
||||
implicit consensus service configuration, now this setting (with Enabled flag)
|
||||
is moved into a section of its own (Consensus). Old configurations are still
|
||||
supported, but this support will eventually be removed.
|
||||
|
||||
Removal of this compatibility code is scheduled for May-June 2023 (~0.103.0
|
||||
release).
|
||||
|
||||
## Node-specific configuration moved from Protocol to Application
|
||||
|
||||
GarbageCollectionPeriod, KeepOnlyLatestState, RemoveUntraceableBlocks,
|
||||
SaveStorageBatch and VerifyBlocks settings were moved from
|
||||
ProtocolConfiguration to ApplicationConfiguration in version 0.100.0. Old
|
||||
configurations are still supported, except for VerifyBlocks which is replaced
|
||||
by SkipBlockVerification with inverted meaning (and hence an inverted default)
|
||||
for security reasons.
|
||||
|
||||
Removal of these options from ProtocolConfiguration is scheduled for May-June
|
||||
2023 (~0.103.0 release).
|
||||
|
||||
## GetPeers RPC server response type changes and RPC client support
|
||||
|
||||
GetPeers RPC command returns a list of Peers where the port type has changed from
|
||||
|
|
|
@ -77,7 +77,8 @@ func TestServerStart(t *testing.T) {
|
|||
})
|
||||
t.Run("invalid consensus config", func(t *testing.T) {
|
||||
saveCfg(t, func(cfg *config.Config) {
|
||||
cfg.ApplicationConfiguration.UnlockWallet.Path = "bad_consensus_wallet.json"
|
||||
cfg.ApplicationConfiguration.Consensus.Enabled = true
|
||||
cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path = "bad_consensus_wallet.json"
|
||||
})
|
||||
e.RunWithError(t, baseCmd...)
|
||||
})
|
||||
|
|
|
@ -136,7 +136,6 @@ func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *m
|
|||
if err != nil {
|
||||
return nil, nil, nil, cli.NewExitError(err, 1)
|
||||
}
|
||||
configureAddresses(&cfg.ApplicationConfiguration)
|
||||
prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log)
|
||||
pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log)
|
||||
|
||||
|
@ -547,7 +546,6 @@ Main:
|
|||
break // Continue working.
|
||||
}
|
||||
}
|
||||
configureAddresses(&cfgnew.ApplicationConfiguration)
|
||||
switch sig {
|
||||
case sighup:
|
||||
if newLogLevel != zapcore.InvalidLevel {
|
||||
|
@ -648,24 +646,6 @@ Main:
|
|||
return nil
|
||||
}
|
||||
|
||||
// configureAddresses sets up addresses for RPC, Prometheus and Pprof depending from the provided config.
|
||||
// In case RPC or Prometheus or Pprof Address provided each of them will use it.
|
||||
// In case global Address (of the node) provided and RPC/Prometheus/Pprof don't have configured addresses they will
|
||||
// use global one. So Node and RPC and Prometheus and Pprof will run on one address.
|
||||
func configureAddresses(cfg *config.ApplicationConfiguration) {
|
||||
if cfg.Address != nil && *cfg.Address != "" { //nolint:staticcheck // SA1019: cfg.Address is deprecated
|
||||
if cfg.RPC.Address == nil || *cfg.RPC.Address == "" { //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
||||
cfg.RPC.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
||||
}
|
||||
if cfg.Prometheus.Address == nil || *cfg.Prometheus.Address == "" { //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
||||
cfg.Prometheus.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
||||
}
|
||||
if cfg.Pprof.Address == nil || *cfg.Pprof.Address == "" { //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
||||
cfg.Pprof.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initBlockChain initializes BlockChain with preselected DB.
|
||||
func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, error) {
|
||||
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)
|
||||
|
|
|
@ -324,64 +324,6 @@ func TestRestoreDB(t *testing.T) {
|
|||
require.NoError(t, restoreDB(ctx))
|
||||
}
|
||||
|
||||
// TestConfigureAddresses checks deprecated code compatibility, it should be removed
|
||||
// along with deprecated `Address` field removal.
|
||||
func TestConfigureAddresses(t *testing.T) {
|
||||
defaultAddress := "http://localhost:10333"
|
||||
customAddress := "http://localhost:10334"
|
||||
|
||||
t.Run("default addresses", func(t *testing.T) {
|
||||
cfg := &config.ApplicationConfiguration{
|
||||
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||
}
|
||||
configureAddresses(cfg)
|
||||
require.Equal(t, defaultAddress, *cfg.RPC.Address) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
||||
require.Equal(t, defaultAddress, *cfg.Prometheus.Address) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
||||
require.Equal(t, defaultAddress, *cfg.Pprof.Address) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
||||
})
|
||||
|
||||
t.Run("custom RPC address", func(t *testing.T) {
|
||||
cfg := &config.ApplicationConfiguration{
|
||||
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||
RPC: config.RPC{
|
||||
BasicService: config.BasicService{
|
||||
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||
},
|
||||
},
|
||||
}
|
||||
configureAddresses(cfg)
|
||||
require.Equal(t, *cfg.RPC.Address, customAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
||||
require.Equal(t, *cfg.Prometheus.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
||||
require.Equal(t, *cfg.Pprof.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
||||
})
|
||||
|
||||
t.Run("custom Pprof address", func(t *testing.T) {
|
||||
cfg := &config.ApplicationConfiguration{
|
||||
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||
Pprof: config.BasicService{
|
||||
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||
},
|
||||
}
|
||||
configureAddresses(cfg)
|
||||
require.Equal(t, *cfg.RPC.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
||||
require.Equal(t, *cfg.Prometheus.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
||||
require.Equal(t, *cfg.Pprof.Address, customAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
||||
})
|
||||
|
||||
t.Run("custom Prometheus address", func(t *testing.T) {
|
||||
cfg := &config.ApplicationConfiguration{
|
||||
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||
Prometheus: config.BasicService{
|
||||
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||
},
|
||||
}
|
||||
configureAddresses(cfg)
|
||||
require.Equal(t, *cfg.RPC.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
||||
require.Equal(t, *cfg.Prometheus.Address, customAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
||||
require.Equal(t, *cfg.Pprof.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
||||
})
|
||||
}
|
||||
|
||||
func TestInitBlockChain(t *testing.T) {
|
||||
t.Run("bad storage", func(t *testing.T) {
|
||||
_, _, err := initBlockChain(config.Config{}, nil)
|
||||
|
|
|
@ -30,6 +30,14 @@ import (
|
|||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// transferTarget represents target address, token amount and data for transfer.
|
||||
type transferTarget struct {
|
||||
Token util.Uint160
|
||||
Address util.Uint160
|
||||
Amount int64
|
||||
Data any
|
||||
}
|
||||
|
||||
var (
|
||||
tokenFlag = cli.StringFlag{
|
||||
Name: "token",
|
||||
|
@ -531,7 +539,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
|||
return cli.NewExitError("empty recipients list", 1)
|
||||
}
|
||||
var (
|
||||
recipients []rpcclient.TransferTarget
|
||||
recipients []transferTarget
|
||||
cosignersOffset = ctx.NArg()
|
||||
)
|
||||
cache := make(map[string]*wallet.Token)
|
||||
|
@ -564,7 +572,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
|
||||
}
|
||||
recipients = append(recipients, rpcclient.TransferTarget{
|
||||
recipients = append(recipients, transferTarget{
|
||||
Token: token.Hash,
|
||||
Address: addr,
|
||||
Amount: amount.Int64(),
|
||||
|
@ -690,7 +698,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
|||
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||
}
|
||||
|
||||
func makeMultiTransferNEP17(act *actor.Actor, recipients []rpcclient.TransferTarget) (*transaction.Transaction, error) {
|
||||
func makeMultiTransferNEP17(act *actor.Actor, recipients []transferTarget) (*transaction.Transaction, error) {
|
||||
scr := smartcontract.NewBuilder()
|
||||
for i := range recipients {
|
||||
scr.InvokeWithAssert(recipients[i].Token, "transfer", act.Sender(),
|
||||
|
|
|
@ -16,28 +16,16 @@ node-related settings described in the table below.
|
|||
|
||||
| Section | Type | Default value | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| Address | `string` | `0.0.0.0` | Node address that P2P protocol handler binds to. Warning: this field is deprecated, please, use `Addresses` instead. |
|
||||
| AnnouncedPort | `uint16` | Same as `NodePort` | Node port which should be used to announce node's port on P2P layer, it can differ from the `NodePort` the node is bound to (for example, if your node is behind NAT). Warning: this field is deprecated, please, use `Addresses` instead. |
|
||||
| AttemptConnPeers | `int` | `20` | Number of connection to try to establish when the connection count drops below the `MinPeers` value. Warning: this field is deprecated and moved to `P2P` section. |
|
||||
| BroadcastFactor | `int` | `0` | Multiplier that is used to determine the number of optimal gossip fan-out peer number for broadcasted messages (0-100). By default it's zero, node uses the most optimized value depending on the estimated network size (`2.5×log(size)`), so the node may have 20 peers and calculate that it needs to broadcast messages to just 10 of them. With BroadcastFactor set to 100 it will always send messages to all peers, any value in-between 0 and 100 is used for weighted calculation, for example if it's 30 then 13 neighbors will be used in the previous case. Warning: this field is deprecated and moved to `P2P` section. |
|
||||
| DBConfiguration | [DB Configuration](#DB-Configuration) | | Describes configuration for database. See the [DB Configuration](#DB-Configuration) section for details. |
|
||||
| DialTimeout | `int64` | `0` | Maximum duration a single dial may take in seconds. Warning: this field is deprecated and moved to `P2P` section. |
|
||||
| ExtensiblePoolSize | `int` | `20` | Maximum amount of the extensible payloads from a single sender stored in a local pool. Warning: this field is deprecated and moved to `P2P` section. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| MaxPeers | `int` | `100` | Maximum numbers of peers that can be connected to the server. Warning: this field is deprecated and moved to `P2P` section. |
|
||||
| MinPeers | `int` | `5` | Minimum number of peers for normal operation; when the node has less than this number of peers it tries to connect with some new ones. Warning: this field is deprecated and moved to `P2P` section. |
|
||||
| NodePort | `uint16` | `0`, which is any free port | The actual node port it is bound to. Warning: this field is deprecated, please, use `Addresses` instead. |
|
||||
| Oracle | [Oracle Configuration](#Oracle-Configuration) | | Oracle module configuration. See the [Oracle Configuration](#Oracle-Configuration) section for details. |
|
||||
| P2P | [P2P Configuration](#P2P-Configuration) | | Configuration values for P2P network interaction. See the [P2P Configuration](#P2P-Configuration) section for details. |
|
||||
| P2PNotary | [P2P Notary Configuration](#P2P-Notary-Configuration) | | P2P Notary module configuration. See the [P2P Notary Configuration](#P2P-Notary-Configuration) section for details. |
|
||||
| PingInterval | `int64` | `30` | Interval in seconds used in pinging mechanism for syncing blocks. Warning: this field is deprecated and moved to `P2P` section. |
|
||||
| PingTimeout | `int64` | `90` | Time to wait for pong (response for sent ping request). Warning: this field is deprecated and moved to `P2P` section. |
|
||||
| Pprof | [Metrics Services Configuration](#Metrics-Services-Configuration) | | Configuration for pprof service (profiling statistics gathering). See the [Metrics Services Configuration](#Metrics-Services-Configuration) section for details. |
|
||||
| Prometheus | [Metrics Services Configuration](#Metrics-Services-Configuration) | | Configuration for Prometheus (monitoring system). See the [Metrics Services Configuration](#Metrics-Services-Configuration) section for details |
|
||||
| ProtoTickInterval | `int64` | `5` | Duration in seconds between protocol ticks with each connected peer. Warning: this field is deprecated and moved to `P2P` section. |
|
||||
| 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`). |
|
||||
|
@ -45,7 +33,6 @@ node-related settings described in the table below.
|
|||
| SaveStorageBatch | `bool` | `false` | Enables storage batch saving before every persist. It is similar to StorageDump plugin for C# node. |
|
||||
| SkipBlockVerification | `bool` | `false` | Allows to disable verification of received/processed blocks (including cryptographic checks). |
|
||||
| StateRoot | [State Root Configuration](#State-Root-Configuration) | | State root module configuration. See the [State Root Configuration](#State-Root-Configuration) section for details. |
|
||||
| UnlockWallet | [Unlock Wallet Configuration](#Unlock-Wallet-Configuration) | | Node wallet configuration used for consensus (dBFT) operation. See the [Unlock Wallet Configuration](#Unlock-Wallet-Configuration) section for details. This section is deprecated and replaced by Consensus, it only exists for compatibility with old configuration files, but will be removed in future node versions. |
|
||||
|
||||
### P2P Configuration
|
||||
|
||||
|
@ -182,10 +169,6 @@ Prometheus:
|
|||
```
|
||||
where:
|
||||
- `Enabled` denotes whether the service is enabled.
|
||||
- `Address` is a service address to be running at. Warning: this field is deprecated,
|
||||
please, use `Addresses` instead.
|
||||
- `Port` is a service port to be bound to. Warning: this field is deprecated, please,
|
||||
use `Addresses` instead.
|
||||
- `Addresses` is a list of service addresses to be running at and listen to in
|
||||
the form of "host:port".
|
||||
|
||||
|
@ -219,8 +202,6 @@ RPC:
|
|||
```
|
||||
where:
|
||||
- `Enabled` denotes whether an RPC server should be started.
|
||||
- `Address` is an RPC server address to be running at. Warning: this field is
|
||||
deprecated, please, use `Addresses` instead.
|
||||
- `Addresses` is a list of RPC server addresses to be running at and listen to in
|
||||
the form of "host:port".
|
||||
- `EnableCORSWorkaround` turns on a set of origin-related behaviors that make
|
||||
|
@ -248,8 +229,6 @@ 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).
|
||||
- `Port` is an RPC server port it should be bound to. Warning: this field is
|
||||
deprecated, please, use `Addresses` instead.
|
||||
- `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
|
||||
|
@ -346,9 +325,7 @@ protocol-related settings described in the table below.
|
|||
| Section | Type | Default value | Description | Notes |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 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. |
|
||||
| GarbageCollectionPeriod | `uint32` | 10000 | Controls MPT garbage collection interval (in blocks) for configurations with `RemoveUntraceableBlocks` enabled and `KeepOnlyLatestState` disabled. In this mode the node stores a number of MPT trees (corresponding to `MaxTraceableBlocks` and `StateSyncInterval`), but the DB needs to be clean from old entries from time to time. Doing it too often will cause too much processing overhead, doing it too rarely will leave more useless data in the DB. This setting is deprecated in favor of the same setting in the ApplicationConfiguration and will be removed in future node versions. If both settings are used, ApplicationConfiguration is prioritized over this one. |
|
||||
| Hardforks | `map[string]uint32` | [] | The set of incompatible changes that affect node behaviour starting from the specified height. The default value is an empty set which should be interpreted as "each known hard-fork is applied from the zero blockchain height". The list of valid hard-fork names:<br>• `Aspidochelone` represents hard-fork introduced in [#2469](https://github.com/nspcc-dev/neo-go/pull/2469) (ported from the [reference](https://github.com/neo-project/neo/pull/2712)). It adjusts the prices of `System.Contract.CreateStandardAccount` and `System.Contract.CreateMultisigAccount` interops so that the resulting prices are in accordance with `sha256` method of native `CryptoLib` contract. 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. |
|
||||
| KeepOnlyLatestState | `bool` | `false` | Specifies if MPT should only store the latest state (or a set of latest states, see `P2PStateExcangeExtensions` section for details). If true, DB size will be smaller, but older roots won't be accessible. This value should remain the same for the same database. | This setting is deprecated in favor of the same setting in the ApplicationConfiguration and will be removed in future node versions. If both settings are used, setting any of them to true enables the function. |
|
||||
| Magic | `uint32` | `0` | Magic number which uniquely identifies Neo network. |
|
||||
| MaxBlockSize | `uint32` | `262144` | Maximum block size in bytes. |
|
||||
| MaxBlockSystemFee | `int64` | `900000000000` | Maximum overall transactions system fee per block. |
|
||||
|
@ -360,10 +337,7 @@ protocol-related settings described in the table below.
|
|||
| P2PNotaryRequestPayloadPoolSize | `int` | `1000` | Size of the node's P2P Notary request payloads memory pool where P2P Notary requests are stored before main or fallback transaction is completed and added to the chain.<br>This option is valid only if `P2PSigExtensions` are enabled. | Not supported by the C# node, thus may affect heterogeneous networks functionality. |
|
||||
| P2PSigExtensions | `bool` | `false` | Enables following additional Notary service related logic:<br>• Transaction attribute `NotaryAssisted`<br>• Network payload of the `P2PNotaryRequest` type<br>• Native `Notary` contract<br>• Notary node module | Not supported by the C# node, thus may affect heterogeneous networks functionality. |
|
||||
| P2PStateExchangeExtensions | `bool` | `false` | Enables the following P2P MPT state data exchange logic: <br>• `StateSyncInterval` protocol setting <br>• P2P commands `GetMPTDataCMD` and `MPTDataCMD` | Not supported by the C# node, thus may affect heterogeneous networks functionality. Can be supported either on MPT-complete node (`KeepOnlyLatestState`=`false`) or on light GC-enabled node (`RemoveUntraceableBlocks=true`) in which case `KeepOnlyLatestState` setting doesn't change the behavior, an appropriate set of MPTs is always stored (see `RemoveUntraceableBlocks`). |
|
||||
| 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`, then old blocks and MPT states will be removed up to the second latest state synchronisation point (see `StateSyncInterval`). | This setting is deprecated in favor of the same setting in the ApplicationConfiguration and will be removed in future node versions. If both settings are used, setting any of them to true enables the function. |
|
||||
| ReservedAttributes | `bool` | `false` | Allows to have reserved attributes range for experimental or private purposes. |
|
||||
| SaveStorageBatch | `bool` | `false` | Enables storage batch saving before every persist. It is similar to StorageDump plugin for C# node. | This setting is deprecated in favor of the same setting in the ApplicationConfiguration and will be removed in future node versions. If both settings are used, setting any of them to true enables the function. |
|
||||
| SecondsPerBlock | `int` | `15` | Minimal time that should pass before next block is accepted. Deprecated: please use TimePerBlock setting (which overrides anything set here), SecondsPerBlock will be removed in future versions. |
|
||||
| SeedList | `[]string` | [] | List of initial nodes addresses used to establish connectivity. |
|
||||
| StandbyCommittee | `[]string` | [] | List of public keys of standby committee validators are chosen from. |
|
||||
| StateRootInHeader | `bool` | `false` | Enables storing state root in block header. | Experimental protocol extension! |
|
||||
|
@ -371,5 +345,4 @@ protocol-related settings described in the table below.
|
|||
| TimePerBlock | `Duration` | `15s` | Minimal (and targeted for) time interval between blocks. Must be an integer number of milliseconds. |
|
||||
| ValidatorsCount | `uint32` | `0` | Number of validators set for the whole network lifetime, can't be set if `ValidatorsHistory` setting is used. |
|
||||
| ValidatorsHistory | map[uint32]uint32 | none | Number of consensus nodes to use after given height (see `CommitteeHistory` also). Heights where the change occurs must be divisible by the number of committee members at that height. Can't be used with `ValidatorsCount` not equal to zero. |
|
||||
| VerifyBlocks | `bool` | `false` | This setting is deprecated and no longer works, please use `SkipBlockVerification` in the `ApplicationConfiguration`, it will be removed in future node versions. |
|
||||
| VerifyTransactions | `bool` | `false` | Denotes whether to verify transactions in the received blocks. |
|
||||
|
|
|
@ -392,34 +392,17 @@ subpackage with an example written in Go doc.
|
|||
that includes simple-signature accounts and multisignature accounts where
|
||||
the client has one of the keys (in which case an invocation script is
|
||||
created that pushes just one signature onto the stack).
|
||||
10. Define lifetime for the fallback transaction. Let the `fallbackValidFor` be
|
||||
the lifetime. Let `N` be the current chain's height and `VUB` be
|
||||
`ValidUntilBlock` value estimated at step 3. Then, the notary node is trying to
|
||||
collect signatures for the main transaction from `N` up to
|
||||
`VUB-fallbackValidFor`. In case of failure after `VUB-fallbackValidFor`-th
|
||||
block is accepted, the notary node abandons attempts to complete the main transaction and
|
||||
tries to push all associated fallbacks. Use the following rules to define
|
||||
`fallbackValidFor`:
|
||||
- `fallbackValidFor` shouldn't be more than `MaxNotValidBeforeDelta` value.
|
||||
- Use notary package's GetMaxNotValidBeforeDelta to check `MaxNotValidBefore` value.
|
||||
11. Construct a script for the fallback transaction. The script may do something useful,
|
||||
i.g. invoke method of a contract. However, if you don't need to perform anything
|
||||
special on fallback invocation, you can use simple `opcode.RET` script.
|
||||
12. Sign and submit P2P notary request. Use
|
||||
[func (*Client) SignAndPushP2PNotaryRequest](https://pkg.go.dev/github.com/nspcc-dev/neo-go@v0.97.2/pkg/rpcclient#Client.SignAndPushP2PNotaryRequest) for it.
|
||||
10. Sign and submit P2P notary request. Use
|
||||
[func (*Actor) Notarize](https://pkg.go.dev/github.com/nspcc-dev/neo-go/pkg/rpcclient/notary#Actor.Notarize) for it.
|
||||
- Use the signed main transaction from step 9 as `mainTx` argument.
|
||||
- Use the fallback script from step 10 as `fallbackScript` argument.
|
||||
- Use `-1` as `fallbackSysFee` argument to define system fee by test
|
||||
invocation or provide any custom value.
|
||||
- Use `0` as `fallbackNetFee` argument not to add extra network fee to the
|
||||
fallback.
|
||||
- Use the `fallbackValidFor` estimated at step 9 as `fallbackValidFor` argument.
|
||||
- Use your account you'd like to send request (and fallback transaction) from
|
||||
to sign the request (and fallback transaction).
|
||||
|
||||
`SignAndPushP2PNotaryRequest` will construct and sign a fallback transaction,
|
||||
construct and sign a P2PNotaryRequest and submit it to the RPC node. The
|
||||
resulting notary request and an error are returned.
|
||||
`Notarize` will construct and sign a fallback transaction using `Actor`
|
||||
configuration (just a simple `RET` script by default), pack both transactions
|
||||
into a P2PNotaryRequest and submit it to the RPC node. It returns hashes of
|
||||
the main and fallback transactions as well as their `ValidUntilBlock` value.
|
||||
If you need more control over fallback transction use `Actor` options or
|
||||
[func (*Actor) SendRequest](https://pkg.go.dev/github.com/nspcc-dev/neo-go/pkg/rpcclient/notary#Actor.SendRequest)
|
||||
API.
|
||||
|
||||
After P2PNotaryRequests are sent, participants should wait for one of their
|
||||
transactions (main or fallback) to get accepted into one of subsequent blocks.
|
||||
|
|
|
@ -2,7 +2,6 @@ package config
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -14,51 +13,26 @@ import (
|
|||
type ApplicationConfiguration struct {
|
||||
Ledger `yaml:",inline"`
|
||||
|
||||
// Deprecated: please, use Addresses field of P2P section instead, this field will be removed in future versions.
|
||||
Address *string `yaml:"Address,omitempty"`
|
||||
// Deprecated: please, use Addresses field of P2P section instead, this field will be removed in future versions.
|
||||
AnnouncedNodePort *uint16 `yaml:"AnnouncedPort,omitempty"`
|
||||
// Deprecated: this option is moved to the P2P section.
|
||||
AttemptConnPeers int `yaml:"AttemptConnPeers"`
|
||||
// BroadcastFactor is the factor (0-100) controlling gossip fan-out number optimization.
|
||||
//
|
||||
// Deprecated: this option is moved to the P2P section.
|
||||
BroadcastFactor int `yaml:"BroadcastFactor"`
|
||||
DBConfiguration dbconfig.DBConfiguration `yaml:"DBConfiguration"`
|
||||
// Deprecated: this option is moved to the P2P section.
|
||||
DialTimeout int64 `yaml:"DialTimeout"`
|
||||
LogLevel string `yaml:"LogLevel"`
|
||||
LogPath string `yaml:"LogPath"`
|
||||
// Deprecated: this option is moved to the P2P section.
|
||||
MaxPeers int `yaml:"MaxPeers"`
|
||||
// Deprecated: this option is moved to the P2P section.
|
||||
MinPeers int `yaml:"MinPeers"`
|
||||
// Deprecated: please, use Addresses field of P2P section instead, this field will be removed in future versions.
|
||||
NodePort *uint16 `yaml:"NodePort,omitempty"`
|
||||
P2P P2P `yaml:"P2P"`
|
||||
// Deprecated: this option is moved to the P2P section.
|
||||
PingInterval int64 `yaml:"PingInterval"`
|
||||
// Deprecated: this option is moved to the P2P section.
|
||||
PingTimeout int64 `yaml:"PingTimeout"`
|
||||
Pprof BasicService `yaml:"Pprof"`
|
||||
Prometheus BasicService `yaml:"Prometheus"`
|
||||
// Deprecated: this option is moved to the P2P section.
|
||||
ProtoTickInterval int64 `yaml:"ProtoTickInterval"`
|
||||
Relay bool `yaml:"Relay"`
|
||||
Consensus Consensus `yaml:"Consensus"`
|
||||
RPC RPC `yaml:"RPC"`
|
||||
UnlockWallet Wallet `yaml:"UnlockWallet"`
|
||||
Oracle OracleConfiguration `yaml:"Oracle"`
|
||||
P2PNotary P2PNotary `yaml:"P2PNotary"`
|
||||
StateRoot StateRoot `yaml:"StateRoot"`
|
||||
// ExtensiblePoolSize is the maximum amount of the extensible payloads from a single sender.
|
||||
//
|
||||
// Deprecated: this option is moved to the P2P section.
|
||||
ExtensiblePoolSize int `yaml:"ExtensiblePoolSize"`
|
||||
|
||||
LogLevel string `yaml:"LogLevel"`
|
||||
LogPath string `yaml:"LogPath"`
|
||||
|
||||
P2P P2P `yaml:"P2P"`
|
||||
|
||||
Pprof BasicService `yaml:"Pprof"`
|
||||
Prometheus BasicService `yaml:"Prometheus"`
|
||||
|
||||
Relay bool `yaml:"Relay"`
|
||||
Consensus Consensus `yaml:"Consensus"`
|
||||
RPC RPC `yaml:"RPC"`
|
||||
Oracle OracleConfiguration `yaml:"Oracle"`
|
||||
P2PNotary P2PNotary `yaml:"P2PNotary"`
|
||||
StateRoot StateRoot `yaml:"StateRoot"`
|
||||
}
|
||||
|
||||
// EqualsButServices returns true when the o is the same as a except for services
|
||||
// (Oracle, P2PNotary, Pprof, Prometheus, RPC, StateRoot and UnlockWallet sections)
|
||||
// (Oracle, P2PNotary, Pprof, Prometheus, RPC and StateRoot sections)
|
||||
// and LogLevel field.
|
||||
func (a *ApplicationConfiguration) EqualsButServices(o *ApplicationConfiguration) bool {
|
||||
if len(a.P2P.Addresses) != len(o.P2P.Addresses) {
|
||||
|
@ -75,28 +49,16 @@ func (a *ApplicationConfiguration) EqualsButServices(o *ApplicationConfiguration
|
|||
return false
|
||||
}
|
||||
}
|
||||
if a.Address != o.Address || //nolint:staticcheck // SA1019: a.Address is deprecated
|
||||
a.AnnouncedNodePort != o.AnnouncedNodePort || //nolint:staticcheck // SA1019: a.AnnouncedNodePort is deprecated
|
||||
a.AttemptConnPeers != o.AttemptConnPeers || //nolint:staticcheck // SA1019: a.AttemptConnPeers is deprecated
|
||||
a.P2P.AttemptConnPeers != o.P2P.AttemptConnPeers ||
|
||||
a.BroadcastFactor != o.BroadcastFactor || //nolint:staticcheck // SA1019: a.BroadcastFactor is deprecated
|
||||
if a.P2P.AttemptConnPeers != o.P2P.AttemptConnPeers ||
|
||||
a.P2P.BroadcastFactor != o.P2P.BroadcastFactor ||
|
||||
a.DBConfiguration != o.DBConfiguration ||
|
||||
a.DialTimeout != o.DialTimeout || //nolint:staticcheck // SA1019: a.DialTimeout is deprecated
|
||||
a.P2P.DialTimeout != o.P2P.DialTimeout ||
|
||||
a.ExtensiblePoolSize != o.ExtensiblePoolSize || //nolint:staticcheck // SA1019: a.ExtensiblePoolSize is deprecated
|
||||
a.P2P.ExtensiblePoolSize != o.P2P.ExtensiblePoolSize ||
|
||||
a.LogPath != o.LogPath ||
|
||||
a.MaxPeers != o.MaxPeers || //nolint:staticcheck // SA1019: a.MaxPeers is deprecated
|
||||
a.P2P.MaxPeers != o.P2P.MaxPeers ||
|
||||
a.MinPeers != o.MinPeers || //nolint:staticcheck // SA1019: a.MinPeers is deprecated
|
||||
a.P2P.MinPeers != o.P2P.MinPeers ||
|
||||
a.NodePort != o.NodePort || //nolint:staticcheck // SA1019: a.NodePort is deprecated
|
||||
a.PingInterval != o.PingInterval || //nolint:staticcheck // SA1019: a.PingInterval is deprecated
|
||||
a.P2P.PingInterval != o.P2P.PingInterval ||
|
||||
a.PingTimeout != o.PingTimeout || //nolint:staticcheck // SA1019: a.PingTimeout is deprecated
|
||||
a.P2P.PingTimeout != o.P2P.PingTimeout ||
|
||||
a.ProtoTickInterval != o.ProtoTickInterval || //nolint:staticcheck // SA1019: a.ProtoTickInterval is deprecated
|
||||
a.P2P.ProtoTickInterval != o.P2P.ProtoTickInterval ||
|
||||
a.Relay != o.Relay {
|
||||
return false
|
||||
|
@ -112,27 +74,9 @@ type AnnounceableAddress struct {
|
|||
}
|
||||
|
||||
// GetAddresses parses returns the list of AnnounceableAddress containing information
|
||||
// gathered from both deprecated Address / NodePort / AnnouncedNodePort and newly
|
||||
// created Addresses fields.
|
||||
// gathered from Addresses.
|
||||
func (a *ApplicationConfiguration) GetAddresses() ([]AnnounceableAddress, error) {
|
||||
addrs := make([]AnnounceableAddress, 0, len(a.P2P.Addresses)+1)
|
||||
if a.Address != nil || a.NodePort != nil || a.AnnouncedNodePort != nil { //nolint:staticcheck // SA1019: a.Address is deprecated
|
||||
var (
|
||||
host string
|
||||
nodePort uint16
|
||||
)
|
||||
if a.Address != nil { //nolint:staticcheck // SA1019: a.Address is deprecated
|
||||
host = *a.Address //nolint:staticcheck // SA1019: a.Address is deprecated
|
||||
}
|
||||
if a.NodePort != nil { //nolint:staticcheck // SA1019: a.NodePort is deprecated
|
||||
nodePort = *a.NodePort //nolint:staticcheck // SA1019: a.NodePort is deprecated
|
||||
}
|
||||
addr := AnnounceableAddress{Address: net.JoinHostPort(host, strconv.Itoa(int(nodePort)))}
|
||||
if a.AnnouncedNodePort != nil { //nolint:staticcheck // SA1019: a.AnnouncedNodePort is deprecated
|
||||
addr.AnnouncedPort = *a.AnnouncedNodePort //nolint:staticcheck // SA1019: a.AnnouncedNodePort is deprecated
|
||||
}
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
addrs := make([]AnnounceableAddress, 0, len(a.P2P.Addresses))
|
||||
for i, addrStr := range a.P2P.Addresses {
|
||||
if len(addrStr) == 0 {
|
||||
return nil, fmt.Errorf("address #%d is empty", i)
|
||||
|
|
|
@ -29,7 +29,6 @@ func TestGetAddresses(t *testing.T) {
|
|||
}
|
||||
addr1 := "1.2.3.4"
|
||||
addr2 := "5.6.7.8"
|
||||
addr3 := "4.3.2.1"
|
||||
v6Plain0 := "3731:54:65fe:2::a7"
|
||||
v6Plain1 := "3731:54:65fe:2::1"
|
||||
v6Plain2 := "3731:54:65fe::a:1"
|
||||
|
@ -37,58 +36,7 @@ func TestGetAddresses(t *testing.T) {
|
|||
v6Plain4 := "3731:54:65fe:2::"
|
||||
port1 := uint16(1)
|
||||
port2 := uint16(2)
|
||||
port3 := uint16(3)
|
||||
cases := []testcase{
|
||||
// Compatibility with the old behaviour.
|
||||
{
|
||||
cfg: &ApplicationConfiguration{},
|
||||
expected: []AnnounceableAddress{{Address: ":0"}},
|
||||
},
|
||||
{
|
||||
cfg: &ApplicationConfiguration{Address: &addr1},
|
||||
expected: []AnnounceableAddress{{Address: addr1 + ":0"}},
|
||||
},
|
||||
{
|
||||
cfg: &ApplicationConfiguration{NodePort: &port1},
|
||||
expected: []AnnounceableAddress{{Address: ":1"}},
|
||||
},
|
||||
{
|
||||
cfg: &ApplicationConfiguration{AnnouncedNodePort: &port1},
|
||||
expected: []AnnounceableAddress{{Address: ":0", AnnouncedPort: port1}},
|
||||
},
|
||||
{
|
||||
cfg: &ApplicationConfiguration{Address: &addr1, NodePort: &port1},
|
||||
expected: []AnnounceableAddress{{Address: addr1 + ":1"}},
|
||||
},
|
||||
{
|
||||
cfg: &ApplicationConfiguration{Address: &addr1, AnnouncedNodePort: &port1},
|
||||
expected: []AnnounceableAddress{{Address: addr1 + ":0", AnnouncedPort: port1}},
|
||||
},
|
||||
{
|
||||
cfg: &ApplicationConfiguration{NodePort: &port1, AnnouncedNodePort: &port2},
|
||||
expected: []AnnounceableAddress{{Address: ":1", AnnouncedPort: port2}},
|
||||
},
|
||||
{
|
||||
cfg: &ApplicationConfiguration{NodePort: &port1, AnnouncedNodePort: &port2},
|
||||
expected: []AnnounceableAddress{{Address: ":1", AnnouncedPort: port2}},
|
||||
},
|
||||
{
|
||||
cfg: &ApplicationConfiguration{Address: &addr1, NodePort: &port1, AnnouncedNodePort: &port2},
|
||||
expected: []AnnounceableAddress{{Address: addr1 + ":1", AnnouncedPort: port2}},
|
||||
},
|
||||
// Compatibility with new multi-addresses.
|
||||
{
|
||||
cfg: &ApplicationConfiguration{
|
||||
Address: &addr1, NodePort: &port1, AnnouncedNodePort: &port2,
|
||||
P2P: P2P{Addresses: []string{addr1, addr2 + ":3", addr3 + ":1:3"}},
|
||||
},
|
||||
expected: []AnnounceableAddress{
|
||||
{Address: addr1 + ":1", AnnouncedPort: port2},
|
||||
{Address: addr1},
|
||||
{Address: addr2 + ":3"},
|
||||
{Address: addr3 + ":1", AnnouncedPort: port3},
|
||||
},
|
||||
},
|
||||
// Multi-addresses checks.
|
||||
{
|
||||
cfg: &ApplicationConfiguration{
|
||||
|
|
|
@ -1,38 +1,9 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// BasicService is used as a simple base for node services like Pprof, RPC or
|
||||
// Prometheus monitoring.
|
||||
type BasicService struct {
|
||||
Enabled bool `yaml:"Enabled"`
|
||||
// Deprecated: please, use Addresses section instead. This field will be removed later.
|
||||
Address *string `yaml:"Address,omitempty"`
|
||||
// Deprecated: please, use Addresses section instead. This field will be removed later.
|
||||
Port *string `yaml:"Port,omitempty"`
|
||||
// Addresses holds the list of bind addresses in the form of "address:port".
|
||||
Addresses []string `yaml:"Addresses"`
|
||||
}
|
||||
|
||||
// GetAddresses returns the set of unique (in terms of raw strings) pairs host:port
|
||||
// for the given basic service.
|
||||
func (s BasicService) GetAddresses() []string {
|
||||
addrs := make([]string, len(s.Addresses), len(s.Addresses)+1)
|
||||
copy(addrs, s.Addresses)
|
||||
if s.Address != nil || s.Port != nil { //nolint:staticcheck // SA1019: s.Address is deprecated
|
||||
var (
|
||||
addr string
|
||||
port string
|
||||
)
|
||||
if s.Address != nil { //nolint:staticcheck // SA1019: s.Address is deprecated
|
||||
addr = *s.Address //nolint:staticcheck // SA1019: s.Address is deprecated
|
||||
}
|
||||
if s.Port != nil { //nolint:staticcheck // SA1019: s.Port is deprecated
|
||||
port = *s.Port //nolint:staticcheck // SA1019: s.Port is deprecated
|
||||
}
|
||||
addrs = append(addrs, net.JoinHostPort(addr, port))
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBasicService_GetAddresses(t *testing.T) {
|
||||
addr := "1.2.3.4"
|
||||
port := "1234"
|
||||
s := BasicService{
|
||||
Enabled: false,
|
||||
Address: &addr,
|
||||
Port: &port,
|
||||
Addresses: []string{"1.2.3.4:1234", /* same as Address:Port */
|
||||
"3.4.5.6:1234", "2.3.4.5", ":1235", "2.3.4.5:1234",
|
||||
"3.4.5.6:1234" /* already in list */},
|
||||
}
|
||||
require.Equal(t, []string{
|
||||
"1.2.3.4:1234",
|
||||
"3.4.5.6:1234",
|
||||
"2.3.4.5",
|
||||
":1235",
|
||||
"2.3.4.5:1234",
|
||||
"3.4.5.6:1234",
|
||||
"1.2.3.4:1234",
|
||||
}, s.GetAddresses())
|
||||
}
|
|
@ -88,11 +88,6 @@ func LoadFile(configPath string) (Config, error) {
|
|||
return Config{}, fmt.Errorf("failed to unmarshal config YAML: %w", err)
|
||||
}
|
||||
|
||||
if len(config.ApplicationConfiguration.UnlockWallet.Path) > 0 && len(config.ApplicationConfiguration.Consensus.UnlockWallet.Path) == 0 {
|
||||
config.ApplicationConfiguration.Consensus.UnlockWallet = config.ApplicationConfiguration.UnlockWallet
|
||||
config.ApplicationConfiguration.Consensus.Enabled = true
|
||||
}
|
||||
|
||||
err = config.ProtocolConfiguration.Validate()
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
|
|
|
@ -16,12 +16,6 @@ type (
|
|||
ProtocolConfiguration struct {
|
||||
// CommitteeHistory stores committee size change history (height: size).
|
||||
CommitteeHistory map[uint32]uint32 `yaml:"CommitteeHistory"`
|
||||
// GarbageCollectionPeriod sets the number of blocks to wait before
|
||||
// starting the next MPT garbage collection cycle when RemoveUntraceableBlocks
|
||||
// option is used.
|
||||
//
|
||||
// Deprecated: please use the same setting in the ApplicationConfiguration, this field will be removed in future versions.
|
||||
GarbageCollectionPeriod uint32 `yaml:"GarbageCollectionPeriod"`
|
||||
|
||||
Magic netmode.Magic `yaml:"Magic"`
|
||||
MemPoolSize int `yaml:"MemPoolSize"`
|
||||
|
@ -34,16 +28,6 @@ type (
|
|||
// P2PNotaryRequestPayloadPoolSize specifies the memory pool size for P2PNotaryRequestPayloads.
|
||||
// It is valid only if P2PSigExtensions are enabled.
|
||||
P2PNotaryRequestPayloadPoolSize int `yaml:"P2PNotaryRequestPayloadPoolSize"`
|
||||
// KeepOnlyLatestState specifies if MPT should only store the latest state.
|
||||
// If true, DB size will be smaller, but older roots won't be accessible.
|
||||
// This value should remain the same for the same database.
|
||||
//
|
||||
// Deprecated: please use the same setting in the ApplicationConfiguration, this field will be removed in future versions.
|
||||
KeepOnlyLatestState bool `yaml:"KeepOnlyLatestState"`
|
||||
// RemoveUntraceableBlocks specifies if old data should be removed.
|
||||
//
|
||||
// Deprecated: please use the same setting in the ApplicationConfiguration, this field will be removed in future versions.
|
||||
RemoveUntraceableBlocks bool `yaml:"RemoveUntraceableBlocks"`
|
||||
// MaxBlockSize is the maximum block size in bytes.
|
||||
MaxBlockSize uint32 `yaml:"MaxBlockSize"`
|
||||
// MaxBlockSystemFee is the maximum overall system fee per block.
|
||||
|
@ -64,14 +48,7 @@ type (
|
|||
P2PStateExchangeExtensions bool `yaml:"P2PStateExchangeExtensions"`
|
||||
// ReservedAttributes allows to have reserved attributes range for experimental or private purposes.
|
||||
ReservedAttributes bool `yaml:"ReservedAttributes"`
|
||||
// SaveStorageBatch enables storage batch saving before every persist.
|
||||
//
|
||||
// Deprecated: please use the same setting in the ApplicationConfiguration, this field will be removed in future versions.
|
||||
SaveStorageBatch bool `yaml:"SaveStorageBatch"`
|
||||
// SecondsPerBlock is the time interval (in seconds) between blocks that consensus nodes work with.
|
||||
//
|
||||
// Deprecated: replaced by TimePerBlock, to be removed in future versions.
|
||||
SecondsPerBlock int `yaml:"SecondsPerBlock"`
|
||||
|
||||
SeedList []string `yaml:"SeedList"`
|
||||
StandbyCommittee []string `yaml:"StandbyCommittee"`
|
||||
// StateRooInHeader enables storing state root in block header.
|
||||
|
@ -85,10 +62,6 @@ type (
|
|||
ValidatorsCount uint32 `yaml:"ValidatorsCount"`
|
||||
// Validators stores history of changes to consensus node number (height: number).
|
||||
ValidatorsHistory map[uint32]uint32 `yaml:"ValidatorsHistory"`
|
||||
// Whether to verify received blocks.
|
||||
//
|
||||
// Deprecated: please use the same setting in the ApplicationConfiguration, this field will be removed in future versions.
|
||||
VerifyBlocks bool `yaml:"VerifyBlocks"`
|
||||
// Whether to verify transactions in the received blocks.
|
||||
VerifyTransactions bool `yaml:"VerifyTransactions"`
|
||||
}
|
||||
|
@ -106,9 +79,6 @@ type heightNumber struct {
|
|||
func (p *ProtocolConfiguration) Validate() error {
|
||||
var err error
|
||||
|
||||
if p.P2PStateExchangeExtensions && p.KeepOnlyLatestState && !p.RemoveUntraceableBlocks {
|
||||
return fmt.Errorf("P2PStateExchangeExtensions can be enabled either on MPT-complete node (KeepOnlyLatestState=false) or on light GC-enabled node (RemoveUntraceableBlocks=true)")
|
||||
}
|
||||
if p.TimePerBlock%time.Millisecond != 0 {
|
||||
return errors.New("TimePerBlock must be an integer number of milliseconds")
|
||||
}
|
||||
|
@ -244,9 +214,7 @@ func (p *ProtocolConfiguration) ShouldUpdateCommitteeAt(height uint32) bool {
|
|||
// Equals allows to compare two ProtocolConfiguration instances, returns true if
|
||||
// they're equal.
|
||||
func (p *ProtocolConfiguration) Equals(o *ProtocolConfiguration) bool {
|
||||
if p.GarbageCollectionPeriod != o.GarbageCollectionPeriod ||
|
||||
p.InitialGASSupply != o.InitialGASSupply ||
|
||||
p.KeepOnlyLatestState != o.KeepOnlyLatestState ||
|
||||
if p.InitialGASSupply != o.InitialGASSupply ||
|
||||
p.Magic != o.Magic ||
|
||||
p.MaxBlockSize != o.MaxBlockSize ||
|
||||
p.MaxBlockSystemFee != o.MaxBlockSystemFee ||
|
||||
|
@ -257,15 +225,11 @@ func (p *ProtocolConfiguration) Equals(o *ProtocolConfiguration) bool {
|
|||
p.P2PNotaryRequestPayloadPoolSize != o.P2PNotaryRequestPayloadPoolSize ||
|
||||
p.P2PSigExtensions != o.P2PSigExtensions ||
|
||||
p.P2PStateExchangeExtensions != o.P2PStateExchangeExtensions ||
|
||||
p.RemoveUntraceableBlocks != o.RemoveUntraceableBlocks ||
|
||||
p.ReservedAttributes != o.ReservedAttributes ||
|
||||
p.SaveStorageBatch != o.SaveStorageBatch ||
|
||||
p.SecondsPerBlock != o.SecondsPerBlock ||
|
||||
p.StateRootInHeader != o.StateRootInHeader ||
|
||||
p.StateSyncInterval != o.StateSyncInterval ||
|
||||
p.TimePerBlock != o.TimePerBlock ||
|
||||
p.ValidatorsCount != o.ValidatorsCount ||
|
||||
p.VerifyBlocks != o.VerifyBlocks ||
|
||||
p.VerifyTransactions != o.VerifyTransactions ||
|
||||
len(p.CommitteeHistory) != len(o.CommitteeHistory) ||
|
||||
len(p.Hardforks) != len(o.Hardforks) ||
|
||||
|
|
|
@ -10,15 +10,6 @@ import (
|
|||
|
||||
func TestProtocolConfigurationValidation(t *testing.T) {
|
||||
p := &ProtocolConfiguration{
|
||||
StandbyCommittee: []string{
|
||||
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
||||
},
|
||||
ValidatorsCount: 1,
|
||||
KeepOnlyLatestState: true,
|
||||
P2PStateExchangeExtensions: true,
|
||||
}
|
||||
require.Error(t, p.Validate())
|
||||
p = &ProtocolConfiguration{
|
||||
StandbyCommittee: []string{
|
||||
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
||||
},
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// TestRPC_UnmarshalBasicService is aimed to check that BasicService config of
|
||||
// RPC service can be properly unmarshalled. This test may be removed after
|
||||
// Address and Port config fields removal.
|
||||
func TestRPC_UnmarshalBasicService(t *testing.T) {
|
||||
data := `
|
||||
Enabled: true
|
||||
Port: 10332
|
||||
MaxGasInvoke: 15
|
||||
`
|
||||
cfg := &RPC{}
|
||||
err := yaml.Unmarshal([]byte(data), &cfg)
|
||||
require.NoError(t, err)
|
||||
require.True(t, cfg.Enabled)
|
||||
require.Equal(t, "10332", *cfg.Port)
|
||||
}
|
|
@ -257,15 +257,9 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
|
|||
zap.Uint16("MaxTransactionsPerBlock", cfg.MaxTransactionsPerBlock))
|
||||
}
|
||||
if cfg.TimePerBlock <= 0 {
|
||||
if cfg.SecondsPerBlock > 0 { //nolint:staticcheck // SA1019: cfg.SecondsPerBlock is deprecated
|
||||
cfg.TimePerBlock = time.Duration(cfg.SecondsPerBlock) * time.Second //nolint:staticcheck // SA1019: cfg.SecondsPerBlock is deprecated
|
||||
log.Info("TimePerBlock is not set, using deprecated SecondsPerBlock setting, consider updating your config",
|
||||
zap.Duration("TimePerBlock", cfg.TimePerBlock))
|
||||
} else {
|
||||
cfg.TimePerBlock = defaultTimePerBlock
|
||||
log.Info("TimePerBlock is not set or wrong, using default value",
|
||||
zap.Duration("TimePerBlock", cfg.TimePerBlock))
|
||||
}
|
||||
cfg.TimePerBlock = defaultTimePerBlock
|
||||
log.Info("TimePerBlock is not set or wrong, using default value",
|
||||
zap.Duration("TimePerBlock", cfg.TimePerBlock))
|
||||
}
|
||||
if cfg.MaxValidUntilBlockIncrement == 0 {
|
||||
const timePerDay = 24 * time.Hour
|
||||
|
@ -278,6 +272,9 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
|
|||
if !cfg.StateRootInHeader {
|
||||
return nil, errors.New("P2PStatesExchangeExtensions are enabled, but StateRootInHeader is off")
|
||||
}
|
||||
if cfg.KeepOnlyLatestState && !cfg.RemoveUntraceableBlocks {
|
||||
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
|
||||
log.Info("StateSyncInterval is not set or wrong, using default value",
|
||||
|
@ -305,13 +302,6 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl
|
|||
break
|
||||
}
|
||||
}
|
||||
// Compatibility with the old ProtocolConfiguration.
|
||||
if cfg.ProtocolConfiguration.GarbageCollectionPeriod > 0 && cfg.Ledger.GarbageCollectionPeriod == 0 { //nolint:staticcheck // SA1019: cfg.ProtocolConfiguration.GarbageCollectionPeriod is deprecated
|
||||
cfg.Ledger.GarbageCollectionPeriod = cfg.ProtocolConfiguration.GarbageCollectionPeriod //nolint:staticcheck // SA1019: cfg.ProtocolConfiguration.GarbageCollectionPeriod is deprecated
|
||||
}
|
||||
cfg.Ledger.KeepOnlyLatestState = cfg.Ledger.KeepOnlyLatestState || cfg.ProtocolConfiguration.KeepOnlyLatestState //nolint:staticcheck // SA1019: cfg.ProtocolConfiguration.KeepOnlyLatestState is deprecated
|
||||
cfg.Ledger.RemoveUntraceableBlocks = cfg.Ledger.RemoveUntraceableBlocks || cfg.ProtocolConfiguration.RemoveUntraceableBlocks //nolint:staticcheck // SA1019: cfg.ProtocolConfiguration.RemoveUntraceableBlocks is deprecated
|
||||
cfg.Ledger.SaveStorageBatch = cfg.Ledger.SaveStorageBatch || cfg.ProtocolConfiguration.SaveStorageBatch //nolint:staticcheck // SA1019: cfg.ProtocolConfiguration.SaveStorageBatch is deprecated
|
||||
|
||||
// Local config consistency checks.
|
||||
if cfg.Ledger.RemoveUntraceableBlocks && cfg.Ledger.GarbageCollectionPeriod == 0 {
|
||||
|
|
|
@ -219,7 +219,7 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
|
|||
checkNewBlockchainErr(t, func(c *config.Config) {
|
||||
boltCfg(c)
|
||||
c.ApplicationConfiguration.RemoveUntraceableBlocks = false
|
||||
}, bcSpout.dao.Store, "state jump was not completed, but P2PStateExchangeExtensions are disabled or archival node capability is on")
|
||||
}, bcSpout.dao.Store, "P2PStateExchangeExtensions can be enabled either on MPT-complete node")
|
||||
})
|
||||
t.Run("invalid state sync point", func(t *testing.T) {
|
||||
bcSpout.dao.Store.Put(bPrefix, []byte{byte(stateJumpStarted)})
|
||||
|
|
|
@ -37,14 +37,6 @@ func TestStateSyncModule_Init(t *testing.T) {
|
|||
c.Ledger.KeepOnlyLatestState = true
|
||||
c.Ledger.RemoveUntraceableBlocks = true
|
||||
}
|
||||
t.Run("error: module disabled by config", func(t *testing.T) {
|
||||
bcBolt, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
|
||||
boltCfg(c)
|
||||
c.Ledger.RemoveUntraceableBlocks = false
|
||||
})
|
||||
module := bcBolt.GetStateSyncModule()
|
||||
require.Error(t, module.Init(bcSpout.BlockHeight())) // module inactive (non-archival node)
|
||||
})
|
||||
|
||||
t.Run("inactive: spout chain is too low to start state sync process", func(t *testing.T) {
|
||||
bcBolt, _, _ := chain.NewMultiWithCustomConfig(t, boltCfg)
|
||||
|
|
|
@ -84,46 +84,6 @@ type (
|
|||
func NewServerConfig(cfg config.Config) (ServerConfig, error) {
|
||||
appConfig := cfg.ApplicationConfiguration
|
||||
protoConfig := cfg.ProtocolConfiguration
|
||||
timePerBlock := protoConfig.TimePerBlock
|
||||
if timePerBlock == 0 && protoConfig.SecondsPerBlock > 0 { //nolint:staticcheck // SA1019: protoConfig.SecondsPerBlock is deprecated
|
||||
timePerBlock = time.Duration(protoConfig.SecondsPerBlock) * time.Second //nolint:staticcheck // SA1019: protoConfig.SecondsPerBlock is deprecated
|
||||
}
|
||||
dialTimeout := appConfig.P2P.DialTimeout
|
||||
if dialTimeout == 0 && appConfig.DialTimeout > 0 { //nolint:staticcheck // SA1019: appConfig.DialTimeout is deprecated
|
||||
dialTimeout = time.Duration(appConfig.DialTimeout) * time.Second //nolint:staticcheck // SA1019: appConfig.DialTimeout is deprecated
|
||||
}
|
||||
protoTickInterval := appConfig.P2P.ProtoTickInterval
|
||||
if protoTickInterval == 0 && appConfig.ProtoTickInterval > 0 { //nolint:staticcheck // SA1019: appConfig.ProtoTickInterval is deprecated
|
||||
protoTickInterval = time.Duration(appConfig.ProtoTickInterval) * time.Second //nolint:staticcheck // SA1019: appConfig.ProtoTickInterval is deprecated
|
||||
}
|
||||
pingInterval := appConfig.P2P.PingInterval
|
||||
if pingInterval == 0 && appConfig.PingInterval > 0 { //nolint:staticcheck // SA1019: appConfig.PingInterval is deprecated
|
||||
pingInterval = time.Duration(appConfig.PingInterval) * time.Second //nolint:staticcheck // SA1019: appConfig.PingInterval is deprecated
|
||||
}
|
||||
pingTimeout := appConfig.P2P.PingTimeout
|
||||
if pingTimeout == 0 && appConfig.PingTimeout > 0 { //nolint:staticcheck // SA1019: appConfig.PingTimeout is deprecated
|
||||
pingTimeout = time.Duration(appConfig.PingTimeout) * time.Second //nolint:staticcheck // SA1019: appConfig.PingTimeout is deprecated
|
||||
}
|
||||
maxPeers := appConfig.P2P.MaxPeers
|
||||
if maxPeers == 0 && appConfig.MaxPeers > 0 { //nolint:staticcheck // SA1019: appConfig.MaxPeers is deprecated
|
||||
maxPeers = appConfig.MaxPeers //nolint:staticcheck // SA1019: appConfig.MaxPeers is deprecated
|
||||
}
|
||||
attemptConnPeers := appConfig.P2P.AttemptConnPeers
|
||||
if attemptConnPeers == 0 && appConfig.AttemptConnPeers > 0 { //nolint:staticcheck // SA1019: appConfig.AttemptConnPeers is deprecated
|
||||
attemptConnPeers = appConfig.AttemptConnPeers //nolint:staticcheck // SA1019: appConfig.AttemptConnPeers is deprecated
|
||||
}
|
||||
minPeers := appConfig.P2P.MinPeers
|
||||
if minPeers == 0 && appConfig.MinPeers > 0 { //nolint:staticcheck // SA1019: appConfig.MinPeers is deprecated
|
||||
minPeers = appConfig.MinPeers //nolint:staticcheck // SA1019: appConfig.MinPeers is deprecated
|
||||
}
|
||||
extPoolSize := appConfig.P2P.ExtensiblePoolSize
|
||||
if extPoolSize == 0 && appConfig.ExtensiblePoolSize > 0 { //nolint:staticcheck // SA1019: appConfig.ExtensiblePoolSize is deprecated
|
||||
extPoolSize = appConfig.ExtensiblePoolSize //nolint:staticcheck // SA1019: appConfig.ExtensiblePoolSize is deprecated
|
||||
}
|
||||
broadcastFactor := appConfig.P2P.BroadcastFactor
|
||||
if broadcastFactor > 0 && appConfig.BroadcastFactor > 0 { //nolint:staticcheck // SA1019: appConfig.BroadcastFactor is deprecated
|
||||
broadcastFactor = appConfig.BroadcastFactor //nolint:staticcheck // SA1019: appConfig.BroadcastFactor is deprecated
|
||||
}
|
||||
addrs, err := appConfig.GetAddresses()
|
||||
if err != nil {
|
||||
return ServerConfig{}, fmt.Errorf("failed to parse addresses: %w", err)
|
||||
|
@ -134,19 +94,19 @@ func NewServerConfig(cfg config.Config) (ServerConfig, error) {
|
|||
Net: protoConfig.Magic,
|
||||
Relay: appConfig.Relay,
|
||||
Seeds: protoConfig.SeedList,
|
||||
DialTimeout: dialTimeout,
|
||||
ProtoTickInterval: protoTickInterval,
|
||||
PingInterval: pingInterval,
|
||||
PingTimeout: pingTimeout,
|
||||
MaxPeers: maxPeers,
|
||||
AttemptConnPeers: attemptConnPeers,
|
||||
MinPeers: minPeers,
|
||||
TimePerBlock: timePerBlock,
|
||||
DialTimeout: appConfig.P2P.DialTimeout,
|
||||
ProtoTickInterval: appConfig.P2P.ProtoTickInterval,
|
||||
PingInterval: appConfig.P2P.PingInterval,
|
||||
PingTimeout: appConfig.P2P.PingTimeout,
|
||||
MaxPeers: appConfig.P2P.MaxPeers,
|
||||
AttemptConnPeers: appConfig.P2P.AttemptConnPeers,
|
||||
MinPeers: appConfig.P2P.MinPeers,
|
||||
TimePerBlock: protoConfig.TimePerBlock,
|
||||
OracleCfg: appConfig.Oracle,
|
||||
P2PNotaryCfg: appConfig.P2PNotary,
|
||||
StateRootCfg: appConfig.StateRoot,
|
||||
ExtensiblePoolSize: extPoolSize,
|
||||
BroadcastFactor: broadcastFactor,
|
||||
ExtensiblePoolSize: appConfig.P2P.ExtensiblePoolSize,
|
||||
BroadcastFactor: appConfig.P2P.BroadcastFactor,
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
|
|
@ -22,8 +22,6 @@ import (
|
|||
const (
|
||||
defaultDialTimeout = 4 * time.Second
|
||||
defaultRequestTimeout = 4 * time.Second
|
||||
// Number of blocks after which cache is expired.
|
||||
cacheTimeout = 100
|
||||
)
|
||||
|
||||
// Client represents the middleman for executing JSON RPC calls
|
||||
|
@ -74,18 +72,10 @@ type Options struct {
|
|||
|
||||
// cache stores cache values for the RPC client methods.
|
||||
type cache struct {
|
||||
initDone bool
|
||||
network netmode.Magic
|
||||
stateRootInHeader bool
|
||||
calculateValidUntilBlock calculateValidUntilBlockCache
|
||||
nativeHashes map[string]util.Uint160
|
||||
}
|
||||
|
||||
// calculateValidUntilBlockCache stores a cached number of validators and
|
||||
// cache expiration value in blocks.
|
||||
type calculateValidUntilBlockCache struct {
|
||||
validatorsCount uint32
|
||||
expiresAt uint32
|
||||
initDone bool
|
||||
network netmode.Magic
|
||||
stateRootInHeader bool
|
||||
nativeHashes map[string]util.Uint160
|
||||
}
|
||||
|
||||
// New returns a new Client ready to use. You should call Init method to
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"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"
|
||||
)
|
||||
|
||||
// InvokeAndPackIteratorResults creates a script containing System.Contract.Call
|
||||
// of the specified contract with the specified arguments. It assumes that the
|
||||
// specified operation will return iterator. The script traverses the resulting
|
||||
// iterator, packs all its values into array and pushes the resulting array on
|
||||
// stack. Constructed script is invoked via `invokescript` JSON-RPC API using
|
||||
// the provided signers. The result of the script invocation contains single array
|
||||
// stackitem on stack if invocation HALTed. InvokeAndPackIteratorResults can be
|
||||
// used to interact with JSON-RPC server where iterator sessions are disabled to
|
||||
// retrieve iterator values via single `invokescript` JSON-RPC call. It returns
|
||||
// maxIteratorResultItems items at max which is set to
|
||||
// config.DefaultMaxIteratorResultItems by default.
|
||||
//
|
||||
// Deprecated: please use more convenient and powerful invoker.Invoker interface with
|
||||
// CallAndExpandIterator method. This method will be removed in future versions.
|
||||
func (c *Client) InvokeAndPackIteratorResults(contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer, maxIteratorResultItems ...int) (*result.Invoke, error) {
|
||||
max := config.DefaultMaxIteratorResultItems
|
||||
if len(maxIteratorResultItems) != 0 {
|
||||
max = maxIteratorResultItems[0]
|
||||
}
|
||||
values, err := smartcontract.ExpandParameterToEmitable(smartcontract.Parameter{
|
||||
Type: smartcontract.ArrayType,
|
||||
Value: params,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("expanding params to emitable: %w", err)
|
||||
}
|
||||
bytes, err := smartcontract.CreateCallAndUnwrapIteratorScript(contract, operation, max, values.([]any)...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create iterator unwrapper script: %w", err)
|
||||
}
|
||||
return c.InvokeScript(bytes, signers)
|
||||
}
|
|
@ -27,8 +27,7 @@ type Internal struct {
|
|||
func NewInternal(ctx context.Context, register InternalHook) (*Internal, error) {
|
||||
c := &Internal{
|
||||
WSClient: WSClient{
|
||||
Client: Client{},
|
||||
Notifications: make(chan Notification),
|
||||
Client: Client{},
|
||||
|
||||
shutdown: make(chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
|
@ -67,7 +66,6 @@ eventloop:
|
|||
}
|
||||
}
|
||||
close(c.done)
|
||||
close(c.Notifications)
|
||||
c.ctxCancel()
|
||||
// ctx is cancelled, server is notified and will finish soon.
|
||||
drainloop:
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
// Various non-policy things from native contracts.
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nns"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// GetOraclePrice invokes `getPrice` method on a native Oracle contract.
|
||||
//
|
||||
// Deprecated: please use oracle subpackage.
|
||||
func (c *Client) GetOraclePrice() (int64, error) {
|
||||
oracleHash, err := c.GetNativeContractHash(nativenames.Oracle)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get native Oracle hash: %w", err)
|
||||
}
|
||||
return c.invokeNativeGetMethod(oracleHash, "getPrice")
|
||||
}
|
||||
|
||||
// GetNNSPrice invokes `getPrice` method on a NeoNameService contract with the specified hash.
|
||||
//
|
||||
// Deprecated: please use nns subpackage. This method will be removed in future versions.
|
||||
func (c *Client) GetNNSPrice(nnsHash util.Uint160) (int64, error) {
|
||||
return c.invokeNativeGetMethod(nnsHash, "getPrice")
|
||||
}
|
||||
|
||||
// GetGasPerBlock invokes `getGasPerBlock` method on a native NEO contract.
|
||||
//
|
||||
// Deprecated: please use neo subpackage. This method will be removed in future releases.
|
||||
func (c *Client) GetGasPerBlock() (int64, error) {
|
||||
return c.getFromNEO("getGasPerBlock")
|
||||
}
|
||||
|
||||
// GetCandidateRegisterPrice invokes `getRegisterPrice` method on native NEO contract.
|
||||
//
|
||||
// Deprecated: please use neo subpackage. This method will be removed in future releases.
|
||||
func (c *Client) GetCandidateRegisterPrice() (int64, error) {
|
||||
return c.getFromNEO("getRegisterPrice")
|
||||
}
|
||||
|
||||
func (c *Client) getFromNEO(meth string) (int64, error) {
|
||||
neoHash, err := c.GetNativeContractHash(nativenames.Neo)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get native NEO hash: %w", err)
|
||||
}
|
||||
return c.invokeNativeGetMethod(neoHash, meth)
|
||||
}
|
||||
|
||||
// GetDesignatedByRole invokes `getDesignatedByRole` method on a native RoleManagement contract.
|
||||
//
|
||||
// Deprecated: please use rolemgmt package.
|
||||
func (c *Client) GetDesignatedByRole(role noderoles.Role, index uint32) (keys.PublicKeys, error) {
|
||||
rmHash, err := c.GetNativeContractHash(nativenames.Designation)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get native RoleManagement hash: %w", err)
|
||||
}
|
||||
arr, err := unwrap.Array(c.reader.Call(rmHash, "getDesignatedByRole", int64(role), index))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pks := make(keys.PublicKeys, len(arr))
|
||||
for i, item := range arr {
|
||||
val, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid array element #%d: %s", i, item.Type())
|
||||
}
|
||||
pks[i], err = keys.NewPublicKeyFromBytes(val, elliptic.P256())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return pks, nil
|
||||
}
|
||||
|
||||
// NNSResolve invokes `resolve` method on a NameService contract with the specified hash.
|
||||
//
|
||||
// Deprecated: please use nns subpackage. This method will be removed in future versions.
|
||||
func (c *Client) NNSResolve(nnsHash util.Uint160, name string, typ nns.RecordType) (string, error) {
|
||||
if typ == nns.CNAME {
|
||||
return "", errors.New("can't resolve CNAME record type")
|
||||
}
|
||||
return unwrap.UTF8String(c.reader.Call(nnsHash, "resolve", name, int64(typ)))
|
||||
}
|
||||
|
||||
// NNSIsAvailable invokes `isAvailable` method on a NeoNameService contract with the specified hash.
|
||||
//
|
||||
// Deprecated: please use nns subpackage. This method will be removed in future versions.
|
||||
func (c *Client) NNSIsAvailable(nnsHash util.Uint160, name string) (bool, error) {
|
||||
return unwrap.Bool(c.reader.Call(nnsHash, "isAvailable", name))
|
||||
}
|
||||
|
||||
// NNSGetAllRecords returns iterator over records for a given name from NNS service.
|
||||
// First return value is the session ID, the second one is Iterator itself, the
|
||||
// third one is an error. Use TraverseIterator method to traverse iterator values or
|
||||
// TerminateSession to terminate opened iterator session. See TraverseIterator and
|
||||
// TerminateSession documentation for more details.
|
||||
//
|
||||
// Deprecated: please use nns subpackage. This method will be removed in future versions.
|
||||
func (c *Client) NNSGetAllRecords(nnsHash util.Uint160, name string) (uuid.UUID, result.Iterator, error) {
|
||||
return unwrap.SessionIterator(c.reader.Call(nnsHash, "getAllRecords", name))
|
||||
}
|
||||
|
||||
// NNSUnpackedGetAllRecords returns a set of records for a given name from NNS service
|
||||
// (config.DefaultMaxIteratorResultItems at max). It differs from NNSGetAllRecords in
|
||||
// that no iterator session is used to retrieve values from iterator. Instead, unpacking
|
||||
// VM script is created and invoked via `invokescript` JSON-RPC call.
|
||||
//
|
||||
// Deprecated: please use nns subpackage. This method will be removed in future versions.
|
||||
func (c *Client) NNSUnpackedGetAllRecords(nnsHash util.Uint160, name string) ([]nns.RecordState, error) {
|
||||
arr, err := unwrap.Array(c.reader.CallAndExpandIterator(nnsHash, "getAllRecords", config.DefaultMaxIteratorResultItems, name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := make([]nns.RecordState, len(arr))
|
||||
for i := range arr {
|
||||
rs, ok := arr[i].Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: not a struct", i)
|
||||
}
|
||||
if len(rs) != 3 {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: wrong number of elements", i)
|
||||
}
|
||||
name, err := rs[0].TryBytes()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: %w", i, err)
|
||||
}
|
||||
typ, err := rs[1].TryInteger()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: %w", i, err)
|
||||
}
|
||||
data, err := rs[2].TryBytes()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: %w", i, err)
|
||||
}
|
||||
u64Typ := typ.Uint64()
|
||||
if !typ.IsUint64() || u64Typ > 255 {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: bad type", i)
|
||||
}
|
||||
res[i] = nns.RecordState{
|
||||
Name: string(name),
|
||||
Type: nns.RecordType(u64Typ),
|
||||
Data: string(data),
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetNotaryServiceFeePerKey returns a reward per notary request key for the designated
|
||||
// notary nodes. It doesn't cache the result.
|
||||
//
|
||||
// Deprecated: please use the Notary contract wrapper from the notary subpackage. This
|
||||
// method will be removed in future versions.
|
||||
func (c *Client) GetNotaryServiceFeePerKey() (int64, error) {
|
||||
notaryHash, err := c.GetNativeContractHash(nativenames.Notary)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get native Notary hash: %w", err)
|
||||
}
|
||||
return c.invokeNativeGetMethod(notaryHash, "getNotaryServiceFeePerKey")
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
)
|
||||
|
||||
// nepDecimals invokes `decimals` NEP* method on the specified contract.
|
||||
func (c *Client) nepDecimals(tokenHash util.Uint160) (int64, error) {
|
||||
return unwrap.Int64(c.reader.Call(tokenHash, "decimals"))
|
||||
}
|
||||
|
||||
// nepSymbol invokes `symbol` NEP* method on the specified contract.
|
||||
func (c *Client) nepSymbol(tokenHash util.Uint160) (string, error) {
|
||||
return unwrap.PrintableASCIIString(c.reader.Call(tokenHash, "symbol"))
|
||||
}
|
||||
|
||||
// nepTotalSupply invokes `totalSupply` NEP* method on the specified contract.
|
||||
func (c *Client) nepTotalSupply(tokenHash util.Uint160) (int64, error) {
|
||||
return unwrap.Int64(c.reader.Call(tokenHash, "totalSupply"))
|
||||
}
|
||||
|
||||
// nepBalanceOf invokes `balanceOf` NEP* method on the specified contract.
|
||||
func (c *Client) nepBalanceOf(tokenHash, acc util.Uint160, tokenID []byte) (int64, error) {
|
||||
params := []any{acc}
|
||||
if tokenID != nil {
|
||||
params = append(params, tokenID)
|
||||
}
|
||||
return unwrap.Int64(c.reader.Call(tokenHash, "balanceOf", params...))
|
||||
}
|
||||
|
||||
// nepTokenInfo returns full NEP* token info.
|
||||
func (c *Client) nepTokenInfo(tokenHash util.Uint160, standard string) (*wallet.Token, error) {
|
||||
cs, err := c.GetContractStateByHash(tokenHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var isStandardOK bool
|
||||
for _, st := range cs.Manifest.SupportedStandards {
|
||||
if st == standard {
|
||||
isStandardOK = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isStandardOK {
|
||||
return nil, fmt.Errorf("token %s does not support %s standard", tokenHash.StringLE(), standard)
|
||||
}
|
||||
symbol, err := c.nepSymbol(tokenHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decimals, err := c.nepDecimals(tokenHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wallet.NewToken(tokenHash, cs.Manifest.Name, symbol, decimals, standard), nil
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"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/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
)
|
||||
|
||||
// NEP11Decimals invokes `decimals` NEP-11 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11Decimals(tokenHash util.Uint160) (int64, error) {
|
||||
return c.nepDecimals(tokenHash)
|
||||
}
|
||||
|
||||
// NEP11Symbol invokes `symbol` NEP-11 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11Symbol(tokenHash util.Uint160) (string, error) {
|
||||
return c.nepSymbol(tokenHash)
|
||||
}
|
||||
|
||||
// NEP11TotalSupply invokes `totalSupply` NEP-11 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11TotalSupply(tokenHash util.Uint160) (int64, error) {
|
||||
return c.nepTotalSupply(tokenHash)
|
||||
}
|
||||
|
||||
// NEP11BalanceOf invokes `balanceOf` NEP-11 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11BalanceOf(tokenHash, owner util.Uint160) (int64, error) {
|
||||
return c.nepBalanceOf(tokenHash, owner, nil)
|
||||
}
|
||||
|
||||
// NEP11TokenInfo returns full NEP-11 token info.
|
||||
//
|
||||
// Deprecated: please use Info method from the neptoken subpackage. This method
|
||||
// will be removed in future versions.
|
||||
func (c *Client) NEP11TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) {
|
||||
return c.nepTokenInfo(tokenHash, manifest.NEP11StandardName)
|
||||
}
|
||||
|
||||
// TransferNEP11 creates an invocation transaction that invokes 'transfer' method
|
||||
// on the given token to move the whole NEP-11 token with the specified token ID to
|
||||
// the given account and sends it to the network returning just a hash of it.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) TransferNEP11(acc *wallet.Account, to util.Uint160,
|
||||
tokenHash util.Uint160, tokenID string, data any, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP11TransferTx(acc, tokenHash, gas, cosigners, to, tokenID, data)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
||||
|
||||
return c.SignAndPushTx(tx, acc, cosigners)
|
||||
}
|
||||
|
||||
// CreateNEP11TransferTx creates an invocation transaction for the 'transfer'
|
||||
// method of the given contract (token) to move the whole (or the specified amount
|
||||
// of) NEP-11 token with the specified token ID to the given account and returns it.
|
||||
// The returned transaction is not signed. CreateNEP11TransferTx is also a
|
||||
// helper for TransferNEP11 and TransferNEP11D.
|
||||
// `args` for TransferNEP11: to util.Uint160, tokenID string, data interface{};
|
||||
// `args` for TransferNEP11D: from, to util.Uint160, amount int64, tokenID string, data interface{}.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) CreateNEP11TransferTx(acc *wallet.Account, tokenHash util.Uint160,
|
||||
gas int64, cosigners []SignerAccount, args ...any) (*transaction.Transaction, error) {
|
||||
script, err := smartcontract.CreateCallWithAssertScript(tokenHash, "transfer", args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create NEP-11 transfer script: %w", err)
|
||||
}
|
||||
return c.CreateTxFromScript(script, acc, -1, gas, append([]SignerAccount{{
|
||||
Signer: transaction.Signer{
|
||||
Account: acc.ScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc,
|
||||
}}, cosigners...))
|
||||
}
|
||||
|
||||
// NEP11TokensOf returns iterator over token IDs for the specified owner of the
|
||||
// specified NFT token. First return value is the session ID, the second one is
|
||||
// Iterator itself, the third one is an error. Use TraverseIterator method to
|
||||
// traverse iterator values or TerminateSession to terminate opened iterator
|
||||
// session. See TraverseIterator and TerminateSession documentation for more details.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11TokensOf(tokenHash util.Uint160, owner util.Uint160) (uuid.UUID, result.Iterator, error) {
|
||||
return unwrap.SessionIterator(c.reader.Call(tokenHash, "tokensOf", owner))
|
||||
}
|
||||
|
||||
// NEP11UnpackedTokensOf returns an array of token IDs for the specified owner of the specified NFT token
|
||||
// (config.DefaultMaxIteratorResultItems at max). It differs from NEP11TokensOf in that no iterator session
|
||||
// is used to retrieve values from iterator. Instead, unpacking VM script is created and invoked via
|
||||
// `invokescript` JSON-RPC call.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11UnpackedTokensOf(tokenHash util.Uint160, owner util.Uint160) ([][]byte, error) {
|
||||
return unwrap.ArrayOfBytes(c.reader.CallAndExpandIterator(tokenHash, "tokensOf", config.DefaultMaxIteratorResultItems, owner))
|
||||
}
|
||||
|
||||
// Non-divisible NFT methods section start.
|
||||
|
||||
// NEP11NDOwnerOf invokes `ownerOf` non-divisible NEP-11 method with the
|
||||
// specified token ID on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11NDOwnerOf(tokenHash util.Uint160, tokenID []byte) (util.Uint160, error) {
|
||||
return unwrap.Uint160(c.reader.Call(tokenHash, "ownerOf", tokenID))
|
||||
}
|
||||
|
||||
// Non-divisible NFT methods section end.
|
||||
|
||||
// Divisible NFT methods section start.
|
||||
|
||||
// TransferNEP11D creates an invocation transaction that invokes 'transfer'
|
||||
// method on the given token to move the specified amount of divisible NEP-11 assets
|
||||
// (in FixedN format using contract's number of decimals) to the given account and
|
||||
// sends it to the network returning just a hash of it.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) TransferNEP11D(acc *wallet.Account, to util.Uint160,
|
||||
tokenHash util.Uint160, amount int64, tokenID []byte, data any, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP11TransferTx(acc, tokenHash, gas, cosigners, acc.ScriptHash(), to, amount, tokenID, data)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
||||
|
||||
return c.SignAndPushTx(tx, acc, cosigners)
|
||||
}
|
||||
|
||||
// NEP11DBalanceOf invokes `balanceOf` divisible NEP-11 method on a
|
||||
// specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11DBalanceOf(tokenHash, owner util.Uint160, tokenID []byte) (int64, error) {
|
||||
return c.nepBalanceOf(tokenHash, owner, tokenID)
|
||||
}
|
||||
|
||||
// NEP11DOwnerOf returns iterator over the specified NEP-11 divisible token owners. First return value
|
||||
// is the session ID, the second one is Iterator itself, the third one is an error. Use TraverseIterator
|
||||
// method to traverse iterator values or TerminateSession to terminate opened iterator session. See
|
||||
// TraverseIterator and TerminateSession documentation for more details.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11DOwnerOf(tokenHash util.Uint160, tokenID []byte) (uuid.UUID, result.Iterator, error) {
|
||||
return unwrap.SessionIterator(c.reader.Call(tokenHash, "ownerOf", tokenID))
|
||||
}
|
||||
|
||||
// NEP11DUnpackedOwnerOf returns list of the specified NEP-11 divisible token owners
|
||||
// (config.DefaultMaxIteratorResultItems at max). It differs from NEP11DOwnerOf in that no
|
||||
// iterator session is used to retrieve values from iterator. Instead, unpacking VM
|
||||
// script is created and invoked via `invokescript` JSON-RPC call.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11DUnpackedOwnerOf(tokenHash util.Uint160, tokenID []byte) ([]util.Uint160, error) {
|
||||
arr, err := unwrap.ArrayOfBytes(c.reader.CallAndExpandIterator(tokenHash, "ownerOf", config.DefaultMaxIteratorResultItems, tokenID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
owners := make([]util.Uint160, len(arr))
|
||||
for i := range arr {
|
||||
owners[i], err = util.Uint160DecodeBytesBE(arr[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("not a Uint160 at %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
return owners, nil
|
||||
}
|
||||
|
||||
// Divisible NFT methods section end.
|
||||
|
||||
// Optional NFT methods section start.
|
||||
|
||||
// NEP11Properties invokes `properties` optional NEP-11 method on the
|
||||
// specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11Properties(tokenHash util.Uint160, tokenID []byte) (*stackitem.Map, error) {
|
||||
return unwrap.Map(c.reader.Call(tokenHash, "properties", tokenID))
|
||||
}
|
||||
|
||||
// NEP11Tokens returns iterator over the tokens minted by the contract. First return
|
||||
// value is the session ID, the second one is Iterator itself, the third one is an
|
||||
// error. Use TraverseIterator method to traverse iterator values or
|
||||
// TerminateSession to terminate opened iterator session. See TraverseIterator and
|
||||
// TerminateSession documentation for more details.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11Tokens(tokenHash util.Uint160) (uuid.UUID, result.Iterator, error) {
|
||||
return unwrap.SessionIterator(c.reader.Call(tokenHash, "tokens"))
|
||||
}
|
||||
|
||||
// NEP11UnpackedTokens returns list of the tokens minted by the contract
|
||||
// (config.DefaultMaxIteratorResultItems at max). It differs from NEP11Tokens in that no
|
||||
// iterator session is used to retrieve values from iterator. Instead, unpacking
|
||||
// VM script is created and invoked via `invokescript` JSON-RPC call.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11UnpackedTokens(tokenHash util.Uint160) ([][]byte, error) {
|
||||
return unwrap.ArrayOfBytes(c.reader.CallAndExpandIterator(tokenHash, "tokens", config.DefaultMaxIteratorResultItems))
|
||||
}
|
||||
|
||||
// Optional NFT methods section end.
|
|
@ -1,188 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
)
|
||||
|
||||
// TransferTarget represents target address, token amount and data for transfer.
|
||||
type TransferTarget struct {
|
||||
Token util.Uint160
|
||||
Address util.Uint160
|
||||
Amount int64
|
||||
Data any
|
||||
}
|
||||
|
||||
// SignerAccount represents combination of the transaction.Signer and the
|
||||
// corresponding wallet.Account.
|
||||
type SignerAccount struct {
|
||||
Signer transaction.Signer
|
||||
Account *wallet.Account
|
||||
}
|
||||
|
||||
// NEP17Decimals invokes `decimals` NEP-17 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP17Decimals(tokenHash util.Uint160) (int64, error) {
|
||||
return c.nepDecimals(tokenHash)
|
||||
}
|
||||
|
||||
// NEP17Symbol invokes `symbol` NEP-17 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP17Symbol(tokenHash util.Uint160) (string, error) {
|
||||
return c.nepSymbol(tokenHash)
|
||||
}
|
||||
|
||||
// NEP17TotalSupply invokes `totalSupply` NEP-17 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions. This method is also wrong since tokens can return values overflowing
|
||||
// int64.
|
||||
func (c *Client) NEP17TotalSupply(tokenHash util.Uint160) (int64, error) {
|
||||
return c.nepTotalSupply(tokenHash)
|
||||
}
|
||||
|
||||
// NEP17BalanceOf invokes `balanceOf` NEP-17 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions. This method is also wrong since tokens can return values overflowing
|
||||
// int64.
|
||||
func (c *Client) NEP17BalanceOf(tokenHash, acc util.Uint160) (int64, error) {
|
||||
return c.nepBalanceOf(tokenHash, acc, nil)
|
||||
}
|
||||
|
||||
// NEP17TokenInfo returns full NEP-17 token info.
|
||||
//
|
||||
// Deprecated: please use Info method from the neptoken subpackage. This method
|
||||
// will be removed in future versions.
|
||||
func (c *Client) NEP17TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) {
|
||||
return c.nepTokenInfo(tokenHash, manifest.NEP17StandardName)
|
||||
}
|
||||
|
||||
// CreateNEP17TransferTx creates an invocation transaction for the 'transfer'
|
||||
// method of the given contract (token) to move the specified amount of NEP-17 assets
|
||||
// (in FixedN format using contract's number of decimals) to the given account and
|
||||
// returns it. The returned transaction is not signed.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) CreateNEP17TransferTx(acc *wallet.Account, to util.Uint160,
|
||||
token util.Uint160, amount int64, gas int64, data any, cosigners []SignerAccount) (*transaction.Transaction, error) {
|
||||
return c.CreateNEP17MultiTransferTx(acc, gas, []TransferTarget{
|
||||
{Token: token,
|
||||
Address: to,
|
||||
Amount: amount,
|
||||
Data: data,
|
||||
},
|
||||
}, cosigners)
|
||||
}
|
||||
|
||||
// CreateNEP17MultiTransferTx creates an invocation transaction for performing
|
||||
// NEP-17 transfers from a single sender to multiple recipients with the given
|
||||
// data and cosigners. The transaction sender is included with the CalledByEntry
|
||||
// scope by default.
|
||||
//
|
||||
// Deprecated: please use nep17 package (when transferring the same token) or
|
||||
// [smartcontract.Builder] (when transferring multiple tokens), this method will
|
||||
// be removed in future versions.
|
||||
func (c *Client) CreateNEP17MultiTransferTx(acc *wallet.Account, gas int64,
|
||||
recipients []TransferTarget, cosigners []SignerAccount) (*transaction.Transaction, error) {
|
||||
from := acc.ScriptHash()
|
||||
b := smartcontract.NewBuilder()
|
||||
for i := range recipients {
|
||||
b.InvokeWithAssert(recipients[i].Token, "transfer",
|
||||
from, recipients[i].Address, recipients[i].Amount, recipients[i].Data)
|
||||
}
|
||||
script, err := b.Script()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create transfer script: %w", err)
|
||||
}
|
||||
return c.CreateTxFromScript(script, acc, -1, gas, append([]SignerAccount{{
|
||||
Signer: transaction.Signer{
|
||||
Account: from,
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc,
|
||||
}}, cosigners...))
|
||||
}
|
||||
|
||||
// CreateTxFromScript creates transaction and properly sets cosigners and NetworkFee.
|
||||
// If sysFee <= 0, it is determined via result of `invokescript` RPC. You should
|
||||
// initialize network magic with Init before calling CreateTxFromScript.
|
||||
//
|
||||
// Deprecated: please use actor.Actor API, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) CreateTxFromScript(script []byte, acc *wallet.Account, sysFee, netFee int64,
|
||||
cosigners []SignerAccount) (*transaction.Transaction, error) {
|
||||
signers, accounts, err := getSigners(acc, cosigners)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct tx signers: %w", err)
|
||||
}
|
||||
if sysFee < 0 {
|
||||
result, err := c.InvokeScript(script, signers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't add system fee to transaction: %w", err)
|
||||
}
|
||||
if result.State != "HALT" {
|
||||
return nil, fmt.Errorf("can't add system fee to transaction: bad vm state: %s due to an error: %s", result.State, result.FaultException)
|
||||
}
|
||||
sysFee = result.GasConsumed
|
||||
}
|
||||
|
||||
tx := transaction.New(script, sysFee)
|
||||
tx.Signers = signers
|
||||
|
||||
tx.ValidUntilBlock, err = c.CalculateValidUntilBlock()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add validUntilBlock to transaction: %w", err)
|
||||
}
|
||||
|
||||
err = c.AddNetworkFee(tx, netFee, accounts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add network fee: %w", err)
|
||||
}
|
||||
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
// TransferNEP17 creates an invocation transaction that invokes 'transfer' method
|
||||
// on the given token to move the specified amount of NEP-17 assets (in FixedN format
|
||||
// using contract's number of decimals) to the given account with the data specified and
|
||||
// sends it to the network returning just a hash of it. Cosigners argument
|
||||
// specifies a set of the transaction cosigners (may be nil or may include sender)
|
||||
// with a proper scope and the accounts to cosign the transaction. If cosigning is
|
||||
// impossible (e.g. due to locked cosigner's account) an error is returned.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) TransferNEP17(acc *wallet.Account, to util.Uint160, token util.Uint160,
|
||||
amount int64, gas int64, data any, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP17TransferTx(acc, to, token, amount, gas, data, cosigners)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
||||
|
||||
return c.SignAndPushTx(tx, acc, cosigners)
|
||||
}
|
||||
|
||||
// MultiTransferNEP17 is similar to TransferNEP17, buf allows to have multiple recipients.
|
||||
//
|
||||
// Deprecated: please use nep17 package (when transferring the same token) or
|
||||
// [smartcontract.Builder] (when transferring multiple tokens), this method will
|
||||
// be removed in future versions.
|
||||
func (c *Client) MultiTransferNEP17(acc *wallet.Account, gas int64, recipients []TransferTarget, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP17MultiTransferTx(acc, gas, recipients, cosigners)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
||||
|
||||
return c.SignAndPushTx(tx, acc, cosigners)
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// GetFeePerByte invokes `getFeePerByte` method on a native Policy contract.
|
||||
//
|
||||
// Deprecated: please use policy subpackage.
|
||||
func (c *Client) GetFeePerByte() (int64, error) {
|
||||
return c.invokeNativePolicyMethod("getFeePerByte")
|
||||
}
|
||||
|
||||
// GetExecFeeFactor invokes `getExecFeeFactor` method on a native Policy contract.
|
||||
//
|
||||
// Deprecated: please use policy subpackage.
|
||||
func (c *Client) GetExecFeeFactor() (int64, error) {
|
||||
return c.invokeNativePolicyMethod("getExecFeeFactor")
|
||||
}
|
||||
|
||||
// GetStoragePrice invokes `getStoragePrice` method on a native Policy contract.
|
||||
//
|
||||
// Deprecated: please use policy subpackage.
|
||||
func (c *Client) GetStoragePrice() (int64, error) {
|
||||
return c.invokeNativePolicyMethod("getStoragePrice")
|
||||
}
|
||||
|
||||
// GetMaxNotValidBeforeDelta invokes `getMaxNotValidBeforeDelta` method on a native Notary contract.
|
||||
//
|
||||
// Deprecated: please use notary subpackage. This method will be removed
|
||||
// in future versions.
|
||||
func (c *Client) GetMaxNotValidBeforeDelta() (int64, error) {
|
||||
notaryHash, err := c.GetNativeContractHash(nativenames.Notary)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get native Notary hash: %w", err)
|
||||
}
|
||||
return c.invokeNativeGetMethod(notaryHash, "getMaxNotValidBeforeDelta")
|
||||
}
|
||||
|
||||
// invokeNativePolicy method invokes Get* method on a native Policy contract.
|
||||
func (c *Client) invokeNativePolicyMethod(operation string) (int64, error) {
|
||||
policyHash, err := c.GetNativeContractHash(nativenames.Policy)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get native Policy hash: %w", err)
|
||||
}
|
||||
return c.invokeNativeGetMethod(policyHash, operation)
|
||||
}
|
||||
|
||||
func (c *Client) invokeNativeGetMethod(hash util.Uint160, operation string) (int64, error) {
|
||||
return unwrap.Int64(c.reader.Call(hash, operation))
|
||||
}
|
||||
|
||||
// IsBlocked invokes `isBlocked` method on native Policy contract.
|
||||
//
|
||||
// Deprecated: please use policy subpackage.
|
||||
func (c *Client) IsBlocked(hash util.Uint160) (bool, error) {
|
||||
policyHash, err := c.GetNativeContractHash(nativenames.Policy)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to get native Policy hash: %w", err)
|
||||
}
|
||||
return unwrap.Bool(c.reader.Call(policyHash, "isBlocked", hash))
|
||||
}
|
|
@ -9,27 +9,19 @@ import (
|
|||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativeprices"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
)
|
||||
|
||||
var errNetworkNotInitialized = errors.New("RPC client network is not initialized")
|
||||
|
@ -103,7 +95,7 @@ func (c *Client) getBlock(param any) (*block.Block, error) {
|
|||
return nil, err
|
||||
}
|
||||
r := io.NewBinReaderFromBuf(resp)
|
||||
sr, err := c.StateRootInHeader()
|
||||
sr, err := c.stateRootInHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -136,7 +128,7 @@ func (c *Client) getBlockVerbose(param any) (*result.Block, error) {
|
|||
resp = &result.Block{}
|
||||
err error
|
||||
)
|
||||
sr, err := c.StateRootInHeader()
|
||||
sr, err := c.stateRootInHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -171,7 +163,7 @@ func (c *Client) GetBlockHeader(hash util.Uint256) (*block.Header, error) {
|
|||
if err := c.performRequest("getblockheader", params, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr, err := c.StateRootInHeader()
|
||||
sr, err := c.stateRootInHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -844,234 +836,6 @@ func (c *Client) SubmitRawOracleResponse(ps []any) error {
|
|||
return c.performRequest("submitoracleresponse", ps, new(result.RelayResult))
|
||||
}
|
||||
|
||||
// SignAndPushInvocationTx signs and pushes the given script as an invocation
|
||||
// transaction using the given wif to sign it and the given cosigners to cosign it if
|
||||
// possible. It spends the amount of gas specified. It returns a hash of the
|
||||
// invocation transaction and an error. If one of the cosigners accounts is
|
||||
// neither contract-based nor unlocked, an error is returned.
|
||||
//
|
||||
// Deprecated: please use actor.Actor API, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sysfee int64, netfee fixedn.Fixed8, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tx, err := c.CreateTxFromScript(script, acc, sysfee, int64(netfee), cosigners)
|
||||
if err != nil {
|
||||
return util.Uint256{}, fmt.Errorf("failed to create tx: %w", err)
|
||||
}
|
||||
return c.SignAndPushTx(tx, acc, cosigners)
|
||||
}
|
||||
|
||||
// SignAndPushTx signs the given transaction using the given wif and cosigners and pushes
|
||||
// it to the chain. It returns a hash of the transaction and an error. If one of
|
||||
// the cosigners accounts is neither contract-based nor unlocked, an error is
|
||||
// returned.
|
||||
//
|
||||
// Deprecated: please use actor.Actor API, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) SignAndPushTx(tx *transaction.Transaction, acc *wallet.Account, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
var (
|
||||
txHash util.Uint256
|
||||
err error
|
||||
)
|
||||
m, err := c.GetNetwork()
|
||||
if err != nil {
|
||||
return txHash, fmt.Errorf("failed to sign tx: %w", err)
|
||||
}
|
||||
if err = acc.SignTx(m, tx); err != nil {
|
||||
return txHash, fmt.Errorf("failed to sign tx: %w", err)
|
||||
}
|
||||
// try to add witnesses for the rest of the signers
|
||||
for i, signer := range tx.Signers[1:] {
|
||||
var isOk bool
|
||||
for _, cosigner := range cosigners {
|
||||
if signer.Account == cosigner.Signer.Account {
|
||||
err = cosigner.Account.SignTx(m, tx)
|
||||
if err != nil { // then account is non-contract-based and locked, but let's provide more detailed error
|
||||
if paramNum := len(cosigner.Account.Contract.Parameters); paramNum != 0 && cosigner.Account.Contract.Deployed {
|
||||
return txHash, fmt.Errorf("failed to add contract-based witness for signer #%d (%s): "+
|
||||
"%d parameters must be provided to construct invocation script", i, address.Uint160ToString(signer.Account), paramNum)
|
||||
}
|
||||
return txHash, fmt.Errorf("failed to add witness for signer #%d (%s): account should be unlocked to add the signature. "+
|
||||
"Store partially-signed transaction and then use 'wallet sign' command to cosign it", i, address.Uint160ToString(signer.Account))
|
||||
}
|
||||
isOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isOk {
|
||||
return txHash, fmt.Errorf("failed to add witness for signer #%d (%s): account wasn't provided", i, address.Uint160ToString(signer.Account))
|
||||
}
|
||||
}
|
||||
txHash = tx.Hash()
|
||||
actualHash, err := c.SendRawTransaction(tx)
|
||||
if err != nil {
|
||||
return txHash, fmt.Errorf("failed to send tx: %w", err)
|
||||
}
|
||||
if !actualHash.Equals(txHash) {
|
||||
return actualHash, fmt.Errorf("sent and actual tx hashes mismatch:\n\tsent: %v\n\tactual: %v", txHash.StringLE(), actualHash.StringLE())
|
||||
}
|
||||
return txHash, nil
|
||||
}
|
||||
|
||||
// getSigners returns an array of transaction signers and corresponding accounts from
|
||||
// given sender and cosigners. If cosigners list already contains sender, the sender
|
||||
// will be placed at the start of the list.
|
||||
func getSigners(sender *wallet.Account, cosigners []SignerAccount) ([]transaction.Signer, []*wallet.Account, error) {
|
||||
var (
|
||||
signers []transaction.Signer
|
||||
accounts []*wallet.Account
|
||||
)
|
||||
from := sender.ScriptHash()
|
||||
s := transaction.Signer{
|
||||
Account: from,
|
||||
Scopes: transaction.None,
|
||||
}
|
||||
for _, c := range cosigners {
|
||||
if c.Signer.Account == from {
|
||||
s = c.Signer
|
||||
continue
|
||||
}
|
||||
signers = append(signers, c.Signer)
|
||||
accounts = append(accounts, c.Account)
|
||||
}
|
||||
signers = append([]transaction.Signer{s}, signers...)
|
||||
accounts = append([]*wallet.Account{sender}, accounts...)
|
||||
return signers, accounts, nil
|
||||
}
|
||||
|
||||
// SignAndPushP2PNotaryRequest creates and pushes a P2PNotary request constructed from the main
|
||||
// and fallback transactions using the given wif to sign it. It returns the request and an error.
|
||||
// Fallback transaction is constructed from the given script using the amount of gas specified.
|
||||
// For successful fallback transaction validation at least 2*transaction.NotaryServiceFeePerKey
|
||||
// GAS should be deposited to the Notary contract.
|
||||
// Main transaction should be constructed by the user. Several rules should be met for
|
||||
// successful main transaction acceptance:
|
||||
// 1. Native Notary contract should be a signer of the main transaction.
|
||||
// 2. Notary signer should have None scope.
|
||||
// 3. Main transaction should have dummy contract witness for Notary signer.
|
||||
// 4. Main transaction should have NotaryAssisted attribute with NKeys specified.
|
||||
// 5. NotaryAssisted attribute and dummy Notary witness (as long as the other incomplete witnesses)
|
||||
// should be paid for. Use CalculateNotaryWitness to calculate the amount of network fee to pay
|
||||
// for the attribute and Notary witness.
|
||||
// 6. Main transaction either shouldn't have all witnesses attached (in this case none of them
|
||||
// can be multisignature), or it only should have a partial multisignature.
|
||||
//
|
||||
// Note: client should be initialized before SignAndPushP2PNotaryRequest call.
|
||||
//
|
||||
// Deprecated: please use Actor from the notary subpackage. This method will be
|
||||
// deleted in future versions.
|
||||
func (c *Client) SignAndPushP2PNotaryRequest(mainTx *transaction.Transaction, fallbackScript []byte, fallbackSysFee int64, fallbackNetFee int64, fallbackValidFor uint32, acc *wallet.Account) (*payload.P2PNotaryRequest, error) {
|
||||
var err error
|
||||
notaryHash, err := c.GetNativeContractHash(nativenames.Notary)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get native Notary hash: %w", err)
|
||||
}
|
||||
from := acc.ScriptHash()
|
||||
signers := []transaction.Signer{{Account: notaryHash}, {Account: from}}
|
||||
if fallbackSysFee < 0 {
|
||||
result, err := c.InvokeScript(fallbackScript, signers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't add system fee to fallback transaction: %w", err)
|
||||
}
|
||||
if result.State != "HALT" {
|
||||
return nil, fmt.Errorf("can't add system fee to fallback transaction: bad vm state %s due to an error: %s", result.State, result.FaultException)
|
||||
}
|
||||
fallbackSysFee = result.GasConsumed
|
||||
}
|
||||
|
||||
maxNVBDelta, err := c.GetMaxNotValidBeforeDelta()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get MaxNotValidBeforeDelta")
|
||||
}
|
||||
if int64(fallbackValidFor) > maxNVBDelta {
|
||||
return nil, fmt.Errorf("fallback transaction should be valid for not more than %d blocks", maxNVBDelta)
|
||||
}
|
||||
fallbackTx := transaction.New(fallbackScript, fallbackSysFee)
|
||||
fallbackTx.Signers = signers
|
||||
fallbackTx.ValidUntilBlock = mainTx.ValidUntilBlock
|
||||
fallbackTx.Attributes = []transaction.Attribute{
|
||||
{
|
||||
Type: transaction.NotaryAssistedT,
|
||||
Value: &transaction.NotaryAssisted{NKeys: 0},
|
||||
},
|
||||
{
|
||||
Type: transaction.NotValidBeforeT,
|
||||
Value: &transaction.NotValidBefore{Height: fallbackTx.ValidUntilBlock - fallbackValidFor + 1},
|
||||
},
|
||||
{
|
||||
Type: transaction.ConflictsT,
|
||||
Value: &transaction.Conflicts{Hash: mainTx.Hash()},
|
||||
},
|
||||
}
|
||||
|
||||
fallbackTx.Scripts = []transaction.Witness{
|
||||
{
|
||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...),
|
||||
VerificationScript: []byte{},
|
||||
},
|
||||
{
|
||||
InvocationScript: []byte{},
|
||||
VerificationScript: acc.GetVerificationScript(),
|
||||
},
|
||||
}
|
||||
fallbackTx.NetworkFee, err = c.CalculateNetworkFee(fallbackTx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add network fee: %w", err)
|
||||
}
|
||||
fallbackTx.NetworkFee += fallbackNetFee
|
||||
m, err := c.GetNetwork()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to sign fallback tx: %w", err)
|
||||
}
|
||||
if err = acc.SignTx(m, fallbackTx); err != nil {
|
||||
return nil, fmt.Errorf("failed to sign fallback tx: %w", err)
|
||||
}
|
||||
fallbackHash := fallbackTx.Hash()
|
||||
req := &payload.P2PNotaryRequest{
|
||||
MainTransaction: mainTx,
|
||||
FallbackTransaction: fallbackTx,
|
||||
}
|
||||
req.Witness = transaction.Witness{
|
||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, acc.SignHashable(m, req)...),
|
||||
VerificationScript: acc.GetVerificationScript(),
|
||||
}
|
||||
actualHash, err := c.SubmitP2PNotaryRequest(req)
|
||||
if err != nil {
|
||||
return req, fmt.Errorf("failed to submit notary request: %w", err)
|
||||
}
|
||||
if !actualHash.Equals(fallbackHash) {
|
||||
return req, fmt.Errorf("sent and actual fallback tx hashes mismatch:\n\tsent: %v\n\tactual: %v", fallbackHash.StringLE(), actualHash.StringLE())
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// CalculateNotaryFee calculates network fee for one dummy Notary witness and NotaryAssisted attribute with NKeys specified.
|
||||
// The result should be added to the transaction's net fee for successful verification.
|
||||
//
|
||||
// Deprecated: NeoGo calculatenetworkfee method handles notary fees as well since 0.99.3, so
|
||||
// this method is just no longer needed and will be removed in future versions.
|
||||
func (c *Client) CalculateNotaryFee(nKeys uint8) (int64, error) {
|
||||
baseExecFee, err := c.GetExecFeeFactor()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get BaseExecFeeFactor: %w", err)
|
||||
}
|
||||
feePerByte, err := c.GetFeePerByte()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get FeePerByte: %w", err)
|
||||
}
|
||||
feePerKey, err := c.GetNotaryServiceFeePerKey()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get NotaryServiceFeePerKey: %w", err)
|
||||
}
|
||||
return int64((nKeys+1))*feePerKey + // fee for NotaryAssisted attribute
|
||||
fee.Opcode(baseExecFee, // Notary node witness
|
||||
opcode.PUSHDATA1, opcode.RET, // invocation script
|
||||
opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // System.Contract.CallNative
|
||||
nativeprices.NotaryVerificationPrice*baseExecFee + // Notary witness verification price
|
||||
feePerByte*int64(io.GetVarSize(make([]byte, 66))) + // invocation script per-byte fee
|
||||
feePerByte*int64(io.GetVarSize([]byte{})), // verification script per-byte fee
|
||||
nil
|
||||
}
|
||||
|
||||
// SubmitP2PNotaryRequest submits given P2PNotaryRequest payload to the RPC node.
|
||||
func (c *Client) SubmitP2PNotaryRequest(req *payload.P2PNotaryRequest) (util.Uint256, error) {
|
||||
var resp = new(result.RelayResult)
|
||||
|
@ -1103,113 +867,9 @@ func (c *Client) ValidateAddress(address string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// CalculateValidUntilBlock calculates ValidUntilBlock field for tx as
|
||||
// current blockchain height + number of validators. Number of validators
|
||||
// is the length of blockchain validators list got from GetNextBlockValidators()
|
||||
// method. Validators count is being cached and updated every 100 blocks.
|
||||
//
|
||||
// Deprecated: please use (*Actor).CalculateValidUntilBlock. This method will be
|
||||
// removed in future versions.
|
||||
func (c *Client) CalculateValidUntilBlock() (uint32, error) {
|
||||
var (
|
||||
result uint32
|
||||
validatorsCount uint32
|
||||
)
|
||||
blockCount, err := c.GetBlockCount()
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("can't get block count: %w", err)
|
||||
}
|
||||
|
||||
c.cacheLock.RLock()
|
||||
if c.cache.calculateValidUntilBlock.expiresAt > blockCount {
|
||||
validatorsCount = c.cache.calculateValidUntilBlock.validatorsCount
|
||||
c.cacheLock.RUnlock()
|
||||
} else {
|
||||
c.cacheLock.RUnlock()
|
||||
validators, err := c.GetNextBlockValidators()
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("can't get validators: %w", err)
|
||||
}
|
||||
validatorsCount = uint32(len(validators))
|
||||
c.cacheLock.Lock()
|
||||
c.cache.calculateValidUntilBlock = calculateValidUntilBlockCache{
|
||||
validatorsCount: validatorsCount,
|
||||
expiresAt: blockCount + cacheTimeout,
|
||||
}
|
||||
c.cacheLock.Unlock()
|
||||
}
|
||||
return blockCount + validatorsCount + 1, nil
|
||||
}
|
||||
|
||||
// AddNetworkFee adds network fee for each witness script and optional extra
|
||||
// network fee to transaction. `accs` is an array signer's accounts.
|
||||
//
|
||||
// Deprecated: please use CalculateNetworkFee or actor.Actor. This method will
|
||||
// be removed in future versions.
|
||||
func (c *Client) AddNetworkFee(tx *transaction.Transaction, extraFee int64, accs ...*wallet.Account) error {
|
||||
if len(tx.Signers) != len(accs) {
|
||||
return errors.New("number of signers must match number of scripts")
|
||||
}
|
||||
size := io.GetVarSize(tx)
|
||||
var ef int64
|
||||
for i, cosigner := range tx.Signers {
|
||||
if accs[i].Contract.Deployed {
|
||||
res, err := c.InvokeContractVerify(cosigner.Account, []smartcontract.Parameter{}, tx.Signers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to invoke verify: %w", err)
|
||||
}
|
||||
r, err := unwrap.Bool(res, err)
|
||||
if err != nil {
|
||||
return fmt.Errorf("signer #%d: %w", i, err)
|
||||
}
|
||||
if !r {
|
||||
return fmt.Errorf("signer #%d: `verify` returned `false`", i)
|
||||
}
|
||||
tx.NetworkFee += res.GasConsumed
|
||||
size += io.GetVarSize([]byte{}) * 2 // both scripts are empty
|
||||
continue
|
||||
}
|
||||
|
||||
if ef == 0 {
|
||||
var err error
|
||||
ef, err = c.GetExecFeeFactor()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't get `ExecFeeFactor`: %w", err)
|
||||
}
|
||||
}
|
||||
netFee, sizeDelta := fee.Calculate(ef, accs[i].Contract.Script)
|
||||
tx.NetworkFee += netFee
|
||||
size += sizeDelta
|
||||
}
|
||||
fee, err := c.GetFeePerByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tx.NetworkFee += int64(size)*fee + extraFee
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetNetwork returns the network magic of the RPC node the client connected to. It
|
||||
// requires Init to be done first, otherwise an error is returned.
|
||||
//
|
||||
// Deprecated: please use GetVersion (it has the same data in the Protocol section)
|
||||
// or actor subpackage. This method will be removed in future versions.
|
||||
func (c *Client) GetNetwork() (netmode.Magic, error) {
|
||||
c.cacheLock.RLock()
|
||||
defer c.cacheLock.RUnlock()
|
||||
|
||||
if !c.cache.initDone {
|
||||
return 0, errNetworkNotInitialized
|
||||
}
|
||||
return c.cache.network, nil
|
||||
}
|
||||
|
||||
// StateRootInHeader returns true if the state root is contained in the block header.
|
||||
// You should initialize Client cache with Init() before calling StateRootInHeader.
|
||||
//
|
||||
// Deprecated: please use GetVersion (it has the same data in the Protocol section).
|
||||
// This method will be removed in future versions.
|
||||
func (c *Client) StateRootInHeader() (bool, error) {
|
||||
// stateRootInHeader returns true if the state root is contained in the block header.
|
||||
// Requires Init() before use.
|
||||
func (c *Client) stateRootInHeader() (bool, error) {
|
||||
c.cacheLock.RLock()
|
||||
defer c.cacheLock.RUnlock()
|
||||
|
||||
|
@ -1219,29 +879,6 @@ func (c *Client) StateRootInHeader() (bool, error) {
|
|||
return c.cache.stateRootInHeader, nil
|
||||
}
|
||||
|
||||
// GetNativeContractHash returns native contract hash by its name.
|
||||
//
|
||||
// Deprecated: please use native contract subpackages that have hashes directly
|
||||
// (gas, management, neo, notary, oracle, policy, rolemgmt) or
|
||||
// GetContractStateByAddressOrName method that will return hash along with other
|
||||
// data.
|
||||
func (c *Client) GetNativeContractHash(name string) (util.Uint160, error) {
|
||||
c.cacheLock.RLock()
|
||||
hash, ok := c.cache.nativeHashes[name]
|
||||
c.cacheLock.RUnlock()
|
||||
if ok {
|
||||
return hash, nil
|
||||
}
|
||||
cs, err := c.GetContractStateByAddressOrName(name)
|
||||
if err != nil {
|
||||
return util.Uint160{}, err
|
||||
}
|
||||
c.cacheLock.Lock()
|
||||
c.cache.nativeHashes[name] = cs.Hash
|
||||
c.cacheLock.Unlock()
|
||||
return cs.Hash, nil
|
||||
}
|
||||
|
||||
// TraverseIterator returns a set of iterator values (maxItemsCount at max) for
|
||||
// the specified iterator and session. If result contains no elements, then either
|
||||
// Iterator has no elements or session was expired and terminated by the server.
|
||||
|
|
|
@ -2,7 +2,6 @@ package rpcclient
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/elliptic"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
|
@ -18,7 +17,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
|
@ -403,136 +401,6 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
},
|
||||
},
|
||||
},
|
||||
"getFeePerByte": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetFeePerByte()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"1000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(1000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getExecFeeFactor": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetExecFeeFactor()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"1000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(1000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getStoragePrice": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetStoragePrice()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"100000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(100000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getOraclePrice": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetOraclePrice()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"10000000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(10000000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getNNSPrice": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetNNSPrice(util.Uint160{1, 2, 3})
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"1000000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(1000000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getGasPerBlock": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetGasPerBlock()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"500000000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(500000000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getCandidateRegisterPrice": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetCandidateRegisterPrice()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"100000000000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(100000000000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getDesignatedByRole": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetDesignatedByRole(noderoles.P2PNotary, 10)
|
||||
},
|
||||
serverResponse: `{"id" : 1,"result" : {"stack" : [{"value" : [{"type":"ByteString","value":"Aw0WkQoDc8WqpG18xPMTEgfHO6gRTVtMN0Mw6zw06fzl"},{"type":"ByteString","value":"A+bmJ9wIaj96Ygr+uQQvQ0AaUrQmj2b3AGnztAOkU3/L"}],"type" : "Array"}],"exception" : null,"script" : "ERQSwB8ME2dldERlc2lnbmF0ZWRCeVJvbGUMFOKV45FUTBeK2U8D7E3N/3hTTs9JQWJ9W1I=","gasconsumed" : "2028150","state" : "HALT"}, "jsonrpc" : "2.0"}`,
|
||||
result: func(c *Client) any {
|
||||
pk1Bytes, _ := base64.StdEncoding.DecodeString("Aw0WkQoDc8WqpG18xPMTEgfHO6gRTVtMN0Mw6zw06fzl")
|
||||
pk1, err := keys.NewPublicKeyFromBytes(pk1Bytes, elliptic.P256())
|
||||
if err != nil {
|
||||
panic("invalid pub key #1 bytes")
|
||||
}
|
||||
pk2Bytes, _ := base64.StdEncoding.DecodeString("A+bmJ9wIaj96Ygr+uQQvQ0AaUrQmj2b3AGnztAOkU3/L")
|
||||
pk2, err := keys.NewPublicKeyFromBytes(pk2Bytes, elliptic.P256())
|
||||
if err != nil {
|
||||
panic("invalid pub key #2 bytes")
|
||||
}
|
||||
return keys.PublicKeys{pk1, pk2}
|
||||
},
|
||||
},
|
||||
},
|
||||
"getMaxNotValidBeforeDelta": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetMaxNotValidBeforeDelta()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMD2dldE1heEJsb2NrU2l6ZQwUmmGkbuyXuJMG186B8VtGIJHQCTJBYn1bUg==","stack":[{"type":"Integer","value":"262144"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(262144)
|
||||
},
|
||||
},
|
||||
},
|
||||
"isBlocked": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.IsBlocked(util.Uint160{1, 2, 3})
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMEmdldEJsb2NrZWRBY2NvdW50cwwUmmGkbuyXuJMG186B8VtGIJHQCTJBYn1bUg==","stack":[{"type":"Boolean","value":false}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return false
|
||||
},
|
||||
},
|
||||
},
|
||||
"getnep11balances": {
|
||||
{
|
||||
name: "positive",
|
||||
|
@ -2138,92 +2006,6 @@ func wrapInitResponse(r *params.In, resp string) string {
|
|||
return response
|
||||
}
|
||||
|
||||
func TestCalculateValidUntilBlock(t *testing.T) {
|
||||
var (
|
||||
getBlockCountCalled int
|
||||
getValidatorsCalled int
|
||||
)
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
r := params.NewRequest()
|
||||
err := r.DecodeData(req.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot decode request body: %s", req.Body)
|
||||
}
|
||||
var response string
|
||||
switch r.In.Method {
|
||||
case "getblockcount":
|
||||
getBlockCountCalled++
|
||||
response = `{"jsonrpc":"2.0","id":1,"result":50}`
|
||||
case "getnextblockvalidators":
|
||||
getValidatorsCalled++
|
||||
response = `{"id":1,"jsonrpc":"2.0","result":[{"publickey":"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2","votes":"0","active":true},{"publickey":"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e","votes":"0","active":true},{"publickey":"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699","votes":"0","active":true},{"publickey":"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62","votes":"0","active":true}]}`
|
||||
}
|
||||
requestHandler(t, r.In, w, response)
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
endpoint := srv.URL
|
||||
opts := Options{}
|
||||
c, err := New(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.getNextRequestID = getTestRequestID
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
validUntilBlock, err := c.CalculateValidUntilBlock()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, uint32(55), validUntilBlock)
|
||||
assert.Equal(t, 1, getBlockCountCalled)
|
||||
assert.Equal(t, 1, getValidatorsCalled)
|
||||
|
||||
// check, whether caching is working
|
||||
validUntilBlock, err = c.CalculateValidUntilBlock()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, uint32(55), validUntilBlock)
|
||||
assert.Equal(t, 2, getBlockCountCalled)
|
||||
assert.Equal(t, 1, getValidatorsCalled)
|
||||
}
|
||||
|
||||
func TestGetNetwork(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
r := params.NewRequest()
|
||||
err := r.DecodeData(req.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot decode request body: %s", req.Body)
|
||||
}
|
||||
// request handler already have `getversion` response wrapper
|
||||
requestHandler(t, r.In, w, "")
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
endpoint := srv.URL
|
||||
opts := Options{}
|
||||
|
||||
t.Run("bad", func(t *testing.T) {
|
||||
c, err := New(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.getNextRequestID = getTestRequestID
|
||||
// network was not initialised
|
||||
_, err = c.GetNetwork()
|
||||
require.ErrorIs(t, err, errNetworkNotInitialized)
|
||||
require.Equal(t, false, c.cache.initDone)
|
||||
})
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
c, err := New(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.getNextRequestID = getTestRequestID
|
||||
require.NoError(t, c.Init())
|
||||
m, err := c.GetNetwork()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, netmode.UnitTestNet, m)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUninitedClient(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
r := params.NewRequest()
|
||||
|
@ -2250,10 +2032,6 @@ func TestUninitedClient(t *testing.T) {
|
|||
require.Error(t, err)
|
||||
_, err = c.GetRawTransactionVerbose(util.Uint256{})
|
||||
require.Error(t, err)
|
||||
_, err = c.IsBlocked(util.Uint160{})
|
||||
require.Error(t, err)
|
||||
_, err = c.GetFeePerByte()
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func newTestNEF(script []byte) nef.File {
|
||||
|
|
|
@ -16,7 +16,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/rpcevent"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
|
@ -56,20 +55,6 @@ import (
|
|||
// CloseNotificationChannelIfFull option is on.
|
||||
type WSClient struct {
|
||||
Client
|
||||
// Notifications is a channel that is used to send events received from
|
||||
// the server. Client's code is supposed to be reading from this channel if
|
||||
// it wants to use subscription mechanism. Failing to do so will cause
|
||||
// WSClient to block even regular requests. This channel is not buffered.
|
||||
// In case of protocol error or upon connection closure, this channel will
|
||||
// be closed, so make sure to handle this. Make sure you're not changing the
|
||||
// received notifications, as it may affect the functionality of other
|
||||
// notification receivers.
|
||||
//
|
||||
// Deprecated: please, use custom channels with ReceiveBlocks, ReceiveTransactions,
|
||||
// ReceiveExecutionNotifications, ReceiveExecutions, ReceiveNotaryRequests
|
||||
// methods to subscribe for notifications. This field will be removed in future
|
||||
// versions.
|
||||
Notifications chan Notification
|
||||
|
||||
ws *websocket.Conn
|
||||
wsOpts WSOptions
|
||||
|
@ -360,56 +345,6 @@ func (r *notaryRequestReceiver) Close() {
|
|||
close(r.ch)
|
||||
}
|
||||
|
||||
// naiveReceiver is a structure leaved for deprecated single channel based notifications
|
||||
// delivering.
|
||||
//
|
||||
// Deprecated: this receiver must be removed after outdated subscriptions API removal.
|
||||
type naiveReceiver struct {
|
||||
eventID neorpc.EventID
|
||||
filter any
|
||||
ch chan<- Notification
|
||||
}
|
||||
|
||||
// EventID implements neorpc.Comparator interface.
|
||||
func (r *naiveReceiver) EventID() neorpc.EventID {
|
||||
return r.eventID
|
||||
}
|
||||
|
||||
// Filter implements neorpc.Comparator interface.
|
||||
func (r *naiveReceiver) Filter() any {
|
||||
return r.filter
|
||||
}
|
||||
|
||||
// Receiver implements notificationReceiver interface.
|
||||
func (r *naiveReceiver) Receiver() any {
|
||||
return r.ch
|
||||
}
|
||||
|
||||
// TrySend implements notificationReceiver interface.
|
||||
func (r *naiveReceiver) TrySend(ntf Notification, nonBlocking bool) (bool, bool) {
|
||||
if rpcevent.Matches(r, ntf) {
|
||||
if nonBlocking {
|
||||
select {
|
||||
case r.ch <- ntf:
|
||||
default:
|
||||
return true, true
|
||||
}
|
||||
} else {
|
||||
r.ch <- ntf
|
||||
}
|
||||
|
||||
return true, false
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
// Close implements notificationReceiver interface.
|
||||
func (r *naiveReceiver) Close() {
|
||||
r.ch <- Notification{
|
||||
Type: neorpc.MissedEventID, // backwards-compatible behaviour
|
||||
}
|
||||
}
|
||||
|
||||
// Notification represents a server-generated notification for client subscriptions.
|
||||
// Value can be one of *block.Block, *state.AppExecResult, *state.ContainedNotificationEvent
|
||||
// *transaction.Transaction or *subscriptions.NotaryRequestEvent based on Type.
|
||||
|
@ -485,8 +420,7 @@ func NewWS(ctx context.Context, endpoint string, opts WSOptions) (*WSClient, err
|
|||
return nil, err
|
||||
}
|
||||
wsc := &WSClient{
|
||||
Client: Client{},
|
||||
Notifications: make(chan Notification),
|
||||
Client: Client{},
|
||||
|
||||
ws: ws,
|
||||
wsOpts: opts,
|
||||
|
@ -566,7 +500,7 @@ readloop:
|
|||
ntf := Notification{Type: event}
|
||||
switch event {
|
||||
case neorpc.BlockEventID:
|
||||
sr, err := c.StateRootInHeader()
|
||||
sr, err := c.stateRootInHeader()
|
||||
if err != nil {
|
||||
// Client is not initialized.
|
||||
connCloseErr = fmt.Errorf("failed to fetch StateRootInHeader: %w", err)
|
||||
|
@ -634,21 +568,14 @@ readloop:
|
|||
}
|
||||
|
||||
// dropSubCh closes corresponding subscriber's channel and removes it from the
|
||||
// receivers map. If the channel belongs to a naive subscriber then it will be
|
||||
// closed manually without call to Close(). The channel is still being kept in
|
||||
// receivers map. The channel is still being kept in
|
||||
// the subscribers map as technically the server-side subscription still exists
|
||||
// and the user is responsible for unsubscription. This method must be called
|
||||
// under subscriptionsLock taken. It's the caller's duty to ensure dropSubCh
|
||||
// will be called once per channel, otherwise panic will occur.
|
||||
func (c *WSClient) dropSubCh(rcvrCh any, id string, ignoreCloseNotificationChannelIfFull bool) {
|
||||
if ignoreCloseNotificationChannelIfFull || c.wsOpts.CloseNotificationChannelIfFull {
|
||||
rcvr := c.subscriptions[id]
|
||||
_, ok := rcvr.(*naiveReceiver)
|
||||
if ok { // naiveReceiver uses c.Notifications that should be handled separately.
|
||||
close(c.Notifications)
|
||||
} else {
|
||||
c.subscriptions[id].Close()
|
||||
}
|
||||
c.subscriptions[id].Close()
|
||||
delete(c.receivers, rcvrCh)
|
||||
}
|
||||
}
|
||||
|
@ -778,29 +705,6 @@ func (c *WSClient) performSubscription(params []any, rcvr notificationReceiver)
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
// SubscribeForNewBlocks adds subscription for new block events to this instance
|
||||
// of the client. It can be filtered by primary consensus node index, nil value doesn't
|
||||
// add any filters.
|
||||
//
|
||||
// Deprecated: please, use ReceiveBlocks. This method will be removed in future versions.
|
||||
func (c *WSClient) SubscribeForNewBlocks(primary *int) (string, error) {
|
||||
var flt any
|
||||
if primary != nil {
|
||||
var f = neorpc.BlockFilter{Primary: primary}
|
||||
flt = *f.Copy()
|
||||
}
|
||||
params := []any{"block_added"}
|
||||
if flt != nil {
|
||||
params = append(params, flt)
|
||||
}
|
||||
r := &naiveReceiver{
|
||||
eventID: neorpc.BlockEventID,
|
||||
filter: flt,
|
||||
ch: c.Notifications,
|
||||
}
|
||||
return c.performSubscription(params, r)
|
||||
}
|
||||
|
||||
// ReceiveBlocks registers provided channel as a receiver for the new block events.
|
||||
// Events can be filtered by the given BlockFilter, nil value doesn't add any filter.
|
||||
// See WSClient comments for generic Receive* behaviour details.
|
||||
|
@ -820,29 +724,6 @@ func (c *WSClient) ReceiveBlocks(flt *neorpc.BlockFilter, rcvr chan<- *block.Blo
|
|||
return c.performSubscription(params, r)
|
||||
}
|
||||
|
||||
// SubscribeForNewTransactions adds subscription for new transaction events to
|
||||
// this instance of the client. It can be filtered by the sender and/or the signer, nil
|
||||
// value is treated as missing filter.
|
||||
//
|
||||
// Deprecated: please, use ReceiveTransactions. This method will be removed in future versions.
|
||||
func (c *WSClient) SubscribeForNewTransactions(sender *util.Uint160, signer *util.Uint160) (string, error) {
|
||||
var flt any
|
||||
if sender != nil || signer != nil {
|
||||
var f = neorpc.TxFilter{Sender: sender, Signer: signer}
|
||||
flt = *f.Copy()
|
||||
}
|
||||
params := []any{"transaction_added"}
|
||||
if flt != nil {
|
||||
params = append(params, flt)
|
||||
}
|
||||
r := &naiveReceiver{
|
||||
eventID: neorpc.TransactionEventID,
|
||||
filter: flt,
|
||||
ch: c.Notifications,
|
||||
}
|
||||
return c.performSubscription(params, r)
|
||||
}
|
||||
|
||||
// ReceiveTransactions registers provided channel as a receiver for new transaction
|
||||
// events. Events can be filtered by the given TxFilter, nil value doesn't add any
|
||||
// filter. See WSClient comments for generic Receive* behaviour details.
|
||||
|
@ -862,30 +743,6 @@ func (c *WSClient) ReceiveTransactions(flt *neorpc.TxFilter, rcvr chan<- *transa
|
|||
return c.performSubscription(params, r)
|
||||
}
|
||||
|
||||
// SubscribeForExecutionNotifications adds subscription for notifications
|
||||
// generated during transaction execution to this instance of the client. It can be
|
||||
// filtered by the contract's hash (that emits notifications), nil value puts no such
|
||||
// restrictions.
|
||||
//
|
||||
// Deprecated: please, use ReceiveExecutionNotifications. This method will be removed in future versions.
|
||||
func (c *WSClient) SubscribeForExecutionNotifications(contract *util.Uint160, name *string) (string, error) {
|
||||
var flt any
|
||||
if contract != nil || name != nil {
|
||||
var f = neorpc.NotificationFilter{Contract: contract, Name: name}
|
||||
flt = *f.Copy()
|
||||
}
|
||||
params := []any{"notification_from_execution"}
|
||||
if flt != nil {
|
||||
params = append(params, flt)
|
||||
}
|
||||
r := &naiveReceiver{
|
||||
eventID: neorpc.NotificationEventID,
|
||||
filter: flt,
|
||||
ch: c.Notifications,
|
||||
}
|
||||
return c.performSubscription(params, r)
|
||||
}
|
||||
|
||||
// ReceiveExecutionNotifications registers provided channel as a receiver for execution
|
||||
// events. Events can be filtered by the given NotificationFilter, nil value doesn't add
|
||||
// any filter. See WSClient comments for generic Receive* behaviour details.
|
||||
|
@ -905,33 +762,6 @@ func (c *WSClient) ReceiveExecutionNotifications(flt *neorpc.NotificationFilter,
|
|||
return c.performSubscription(params, r)
|
||||
}
|
||||
|
||||
// SubscribeForTransactionExecutions adds subscription for application execution
|
||||
// results generated during transaction execution to this instance of the client. It can
|
||||
// be filtered by state (HALT/FAULT) to check for successful or failing
|
||||
// transactions, nil value means no filtering.
|
||||
//
|
||||
// Deprecated: please, use ReceiveExecutions. This method will be removed in future versions.
|
||||
func (c *WSClient) SubscribeForTransactionExecutions(state *string) (string, error) {
|
||||
var flt any
|
||||
if state != nil {
|
||||
if *state != "HALT" && *state != "FAULT" {
|
||||
return "", errors.New("bad state parameter")
|
||||
}
|
||||
var f = neorpc.ExecutionFilter{State: state}
|
||||
flt = *f.Copy()
|
||||
}
|
||||
params := []any{"transaction_executed"}
|
||||
if flt != nil {
|
||||
params = append(params, flt)
|
||||
}
|
||||
r := &naiveReceiver{
|
||||
eventID: neorpc.ExecutionEventID,
|
||||
filter: flt,
|
||||
ch: c.Notifications,
|
||||
}
|
||||
return c.performSubscription(params, r)
|
||||
}
|
||||
|
||||
// ReceiveExecutions registers provided channel as a receiver for
|
||||
// application execution result events generated during transaction execution.
|
||||
// Events can be filtered by the given ExecutionFilter, nil value doesn't add any filter.
|
||||
|
@ -957,30 +787,6 @@ func (c *WSClient) ReceiveExecutions(flt *neorpc.ExecutionFilter, rcvr chan<- *s
|
|||
return c.performSubscription(params, r)
|
||||
}
|
||||
|
||||
// SubscribeForNotaryRequests adds subscription for notary request payloads
|
||||
// addition or removal events to this instance of client. It can be filtered by
|
||||
// request sender's hash, or main tx signer's hash, nil value puts no such
|
||||
// restrictions.
|
||||
//
|
||||
// Deprecated: please, use ReceiveNotaryRequests. This method will be removed in future versions.
|
||||
func (c *WSClient) SubscribeForNotaryRequests(sender *util.Uint160, mainSigner *util.Uint160) (string, error) {
|
||||
var flt any
|
||||
if sender != nil || mainSigner != nil {
|
||||
var f = neorpc.TxFilter{Sender: sender, Signer: mainSigner}
|
||||
flt = *f.Copy()
|
||||
}
|
||||
params := []any{"notary_request_event"}
|
||||
if flt != nil {
|
||||
params = append(params, flt)
|
||||
}
|
||||
r := &naiveReceiver{
|
||||
eventID: neorpc.NotaryRequestEventID,
|
||||
filter: flt,
|
||||
ch: c.Notifications,
|
||||
}
|
||||
return c.performSubscription(params, r)
|
||||
}
|
||||
|
||||
// ReceiveNotaryRequests registers provided channel as a receiver for notary request
|
||||
// payload addition or removal events. Events can be filtered by the given TxFilter
|
||||
// where sender corresponds to notary request sender (the second fallback transaction
|
||||
|
|
|
@ -205,31 +205,23 @@ func TestWSClientEvents(t *testing.T) {
|
|||
wsc.receivers[chan<- *state.AppExecResult(aerCh3)] = []string{"6"}
|
||||
// MissedEvent must close the channels above.
|
||||
|
||||
wsc.subscriptions["7"] = &naiveReceiver{eventID: neorpc.BlockEventID, ch: wsc.Notifications}
|
||||
wsc.subscriptions["8"] = &naiveReceiver{eventID: neorpc.BlockEventID, ch: wsc.Notifications} // check duplicating subscriptions
|
||||
wsc.subscriptions["9"] = &naiveReceiver{eventID: neorpc.ExecutionEventID, ch: wsc.Notifications} // check different events
|
||||
wsc.receivers[wsc.Notifications] = []string{"7", "8", "9"}
|
||||
wsc.subscriptionsLock.Unlock()
|
||||
|
||||
var (
|
||||
b1Cnt, b2Cnt int
|
||||
aer1Cnt, aer2Cnt, aer3Cnt int
|
||||
ntfCnt int
|
||||
defaultCount int
|
||||
expectedb1Cnt, expectedb2Cnt = 1, 1 // single Block event
|
||||
expectedaer1Cnt, expectedaer2Cnt, expectedaer3Cnt = 2, 2, 0 // two HALTED AERs
|
||||
expectedntfCnt = 1 // single notification event
|
||||
expectedDefaultCnt = 1 + 2 + 1 // single Block event + two AERs + missed event
|
||||
expectedb1Cnt, expectedb2Cnt = 1, 1 // single Block event
|
||||
expectedaer1Cnt, expectedaer2Cnt, expectedaer3Cnt = 2, 2, 0 // two HALTED AERs
|
||||
expectedntfCnt = 1 // single notification event
|
||||
aer *state.AppExecResult
|
||||
)
|
||||
for b1Cnt+b2Cnt+
|
||||
aer1Cnt+aer2Cnt+aer3Cnt+
|
||||
ntfCnt+
|
||||
defaultCount !=
|
||||
ntfCnt !=
|
||||
expectedb1Cnt+expectedb2Cnt+
|
||||
expectedaer1Cnt+expectedaer2Cnt+expectedaer3Cnt+
|
||||
expectedntfCnt+
|
||||
expectedDefaultCnt {
|
||||
expectedntfCnt {
|
||||
select {
|
||||
case _, ok = <-bCh1:
|
||||
if ok {
|
||||
|
@ -256,10 +248,6 @@ func TestWSClientEvents(t *testing.T) {
|
|||
if ok {
|
||||
ntfCnt++
|
||||
}
|
||||
case _, ok = <-wsc.Notifications:
|
||||
if ok {
|
||||
defaultCount++
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("timeout waiting for event")
|
||||
}
|
||||
|
@ -270,7 +258,6 @@ func TestWSClientEvents(t *testing.T) {
|
|||
assert.Equal(t, expectedaer2Cnt, aer2Cnt)
|
||||
assert.Equal(t, expectedaer3Cnt, aer3Cnt)
|
||||
assert.Equal(t, expectedntfCnt, ntfCnt)
|
||||
assert.Equal(t, expectedDefaultCnt, defaultCount)
|
||||
|
||||
// Channels must be closed by server
|
||||
_, ok = <-bCh1
|
||||
|
|
|
@ -24,7 +24,7 @@ func NewPprofService(cfg config.BasicService, log *zap.Logger) *Service {
|
|||
handler.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
handler.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
|
||||
addrs := cfg.GetAddresses()
|
||||
addrs := cfg.Addresses
|
||||
srvs := make([]*http.Server, len(addrs))
|
||||
for i, addr := range addrs {
|
||||
srvs[i] = &http.Server{
|
||||
|
|
|
@ -17,7 +17,7 @@ func NewPrometheusService(cfg config.BasicService, log *zap.Logger) *Service {
|
|||
return nil
|
||||
}
|
||||
|
||||
addrs := cfg.GetAddresses()
|
||||
addrs := cfg.Addresses
|
||||
srvs := make([]*http.Server, len(addrs))
|
||||
for i, addr := range addrs {
|
||||
srvs[i] = &http.Server{
|
||||
|
|
|
@ -31,7 +31,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||
|
@ -544,7 +543,7 @@ func TestClientNotary(t *testing.T) {
|
|||
require.Error(t, err) // Can't be withdrawn until 1111.
|
||||
}
|
||||
|
||||
func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
||||
func TestCalculateNetworkFee_Base(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
@ -555,27 +554,8 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
getAccounts := func(t *testing.T, n int) []*wallet.Account {
|
||||
accs := make([]*wallet.Account, n)
|
||||
var err error
|
||||
for i := range accs {
|
||||
accs[i], err = wallet.NewAccount()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
return accs
|
||||
}
|
||||
|
||||
feePerByte := chain.FeePerByte()
|
||||
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
|
||||
accs := getAccounts(t, 2)
|
||||
tx.Signers = []transaction.Signer{{
|
||||
Account: accs[0].PrivateKey().GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
}}
|
||||
require.Error(t, c.AddNetworkFee(tx, extraFee, accs[0], accs[1])) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
})
|
||||
t.Run("Simple", func(t *testing.T) {
|
||||
acc0 := wallet.NewAccountFromPrivateKey(testchain.PrivateKeyByID(0))
|
||||
check := func(t *testing.T, extraFee int64) {
|
||||
|
@ -593,16 +573,12 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
}
|
||||
actualCalculatedNetFee, err := c.CalculateNetworkFee(tx)
|
||||
require.NoError(t, err)
|
||||
|
||||
tx.Scripts = nil
|
||||
require.NoError(t, c.AddNetworkFee(tx, extraFee, acc0)) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
actual := tx.NetworkFee
|
||||
tx.NetworkFee = actualCalculatedNetFee + extraFee
|
||||
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), tx))
|
||||
cFee, _ := fee.Calculate(chain.GetBaseExecFee(), acc0.Contract.Script)
|
||||
expected := int64(io.GetVarSize(tx))*feePerByte + cFee + extraFee
|
||||
|
||||
require.Equal(t, expected, actual)
|
||||
require.Equal(t, expected, actualCalculatedNetFee+extraFee)
|
||||
err = chain.VerifyTx(tx)
|
||||
if extraFee < 0 {
|
||||
|
@ -658,12 +634,9 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
}
|
||||
actualCalculatedNetFee, err := c.CalculateNetworkFee(tx)
|
||||
require.NoError(t, err)
|
||||
tx.NetworkFee = actualCalculatedNetFee + extraFee
|
||||
|
||||
tx.Scripts = nil
|
||||
|
||||
require.NoError(t, c.AddNetworkFee(tx, extraFee, acc0, acc1)) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
actual := tx.NetworkFee
|
||||
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), tx))
|
||||
tx.Scripts = append(tx.Scripts, transaction.Witness{
|
||||
InvocationScript: testchain.Sign(tx),
|
||||
|
@ -673,7 +646,6 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
cFeeM, _ := fee.Calculate(chain.GetBaseExecFee(), acc1.Contract.Script)
|
||||
expected := int64(io.GetVarSize(tx))*feePerByte + cFee + cFeeM + extraFee
|
||||
|
||||
require.Equal(t, expected, actual)
|
||||
require.Equal(t, expected, actualCalculatedNetFee+extraFee)
|
||||
err = chain.VerifyTx(tx)
|
||||
if extraFee < 0 {
|
||||
|
@ -732,12 +704,11 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
}
|
||||
actual, err := c.CalculateNetworkFee(tx)
|
||||
require.NoError(t, err)
|
||||
tx.Scripts = nil
|
||||
tx.NetworkFee = actual + extraFee
|
||||
|
||||
require.NoError(t, c.AddNetworkFee(tx, extraFee, acc0, acc1)) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
tx.Scripts = nil
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), tx))
|
||||
tx.Scripts = append(tx.Scripts, transaction.Witness{})
|
||||
require.Equal(t, tx.NetworkFee, actual+extraFee)
|
||||
err = chain.VerifyTx(tx)
|
||||
if extraFee < 0 {
|
||||
require.Error(t, err)
|
||||
|
@ -759,37 +730,6 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
check(t, -1)
|
||||
})
|
||||
})
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
tx := newTx(t)
|
||||
acc0, err := wallet.NewAccount()
|
||||
require.NoError(t, err)
|
||||
tx.Signers = []transaction.Signer{
|
||||
{
|
||||
Account: acc0.PrivateKey().GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
{
|
||||
Account: h,
|
||||
Scopes: transaction.Global,
|
||||
},
|
||||
}
|
||||
require.Error(t, c.AddNetworkFee(tx, 10, acc0, acc1)) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
})
|
||||
t.Run("InvalidContract", func(t *testing.T) {
|
||||
tx := newTx(t)
|
||||
acc0 := wallet.NewAccountFromPrivateKey(priv)
|
||||
tx.Signers = []transaction.Signer{
|
||||
{
|
||||
Account: acc0.PrivateKey().GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
{
|
||||
Account: util.Uint160{},
|
||||
Scopes: transaction.Global,
|
||||
},
|
||||
}
|
||||
require.Error(t, c.AddNetworkFee(tx, 10, acc0, acc1)) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -863,160 +803,6 @@ func TestCalculateNetworkFee(t *testing.T) {
|
|||
})
|
||||
})
|
||||
}
|
||||
func TestSignAndPushInvocationTx(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
priv0 := testchain.PrivateKeyByID(0)
|
||||
acc0 := wallet.NewAccountFromPrivateKey(priv0)
|
||||
|
||||
verifyWithoutParamsCtr, err := util.Uint160DecodeStringLE(verifyContractHash)
|
||||
require.NoError(t, err)
|
||||
acc1 := &wallet.Account{
|
||||
Address: address.Uint160ToString(verifyWithoutParamsCtr),
|
||||
Contract: &wallet.Contract{
|
||||
Parameters: []wallet.ContractParam{},
|
||||
Deployed: true,
|
||||
},
|
||||
Default: false,
|
||||
}
|
||||
|
||||
verifyWithParamsCtr, err := util.Uint160DecodeStringLE(verifyWithArgsContractHash)
|
||||
require.NoError(t, err)
|
||||
acc2 := &wallet.Account{
|
||||
Address: address.Uint160ToString(verifyWithParamsCtr),
|
||||
Contract: &wallet.Contract{
|
||||
Parameters: []wallet.ContractParam{
|
||||
{Name: "argString", Type: smartcontract.StringType},
|
||||
{Name: "argInt", Type: smartcontract.IntegerType},
|
||||
{Name: "argBool", Type: smartcontract.BoolType},
|
||||
},
|
||||
Deployed: true,
|
||||
},
|
||||
Default: false,
|
||||
}
|
||||
|
||||
priv3 := testchain.PrivateKeyByID(3)
|
||||
acc3 := wallet.NewAccountFromPrivateKey(priv3)
|
||||
|
||||
check := func(t *testing.T, h util.Uint256) {
|
||||
mp := chain.GetMemPool()
|
||||
tx, ok := mp.TryGetValue(h)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, h, tx.Hash())
|
||||
require.EqualValues(t, 30, tx.SystemFee)
|
||||
}
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
t.Run("signer0: sig", func(t *testing.T) {
|
||||
h, err := c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc0, 30, 0, []rpcclient.SignerAccount{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv0.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc0,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
check(t, h)
|
||||
})
|
||||
t.Run("signer0: sig; signer1: sig", func(t *testing.T) {
|
||||
h, err := c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc0, 30, 0, []rpcclient.SignerAccount{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv0.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc0,
|
||||
},
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv3.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc3,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
check(t, h)
|
||||
})
|
||||
t.Run("signer0: sig; signer1: contract-based paramless", func(t *testing.T) {
|
||||
h, err := c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc0, 30, 0, []rpcclient.SignerAccount{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv0.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc0,
|
||||
},
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: verifyWithoutParamsCtr,
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc1,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
check(t, h)
|
||||
})
|
||||
})
|
||||
t.Run("error", func(t *testing.T) {
|
||||
t.Run("signer0: sig; signer1: contract-based with params", func(t *testing.T) {
|
||||
_, err := c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc0, 30, 0, []rpcclient.SignerAccount{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv0.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc0,
|
||||
},
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: verifyWithParamsCtr,
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc2,
|
||||
},
|
||||
})
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("signer0: sig; signer1: locked sig", func(t *testing.T) {
|
||||
pk, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
acc4 := &wallet.Account{
|
||||
Address: address.Uint160ToString(pk.GetScriptHash()),
|
||||
Contract: &wallet.Contract{
|
||||
Script: pk.PublicKey().GetVerificationScript(),
|
||||
Parameters: []wallet.ContractParam{{Name: "parameter0", Type: smartcontract.SignatureType}},
|
||||
},
|
||||
}
|
||||
_, err = c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc0, 30, 0, []rpcclient.SignerAccount{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv0.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc0,
|
||||
},
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: util.Uint160{1, 2, 3},
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc4,
|
||||
},
|
||||
})
|
||||
require.Error(t, err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestNotaryActor(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChainAndServices(t, false, true, false)
|
||||
|
@ -1049,92 +835,6 @@ func TestNotaryActor(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSignAndPushP2PNotaryRequest(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChainAndServices(t, false, true, false)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
acc, err := wallet.NewAccount()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("client wasn't initialized", func(t *testing.T) {
|
||||
_, err := c.SignAndPushP2PNotaryRequest(transaction.New([]byte{byte(opcode.RET)}, 123), []byte{byte(opcode.RET)}, -1, 0, 100, acc) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
||||
require.NotNil(t, err)
|
||||
})
|
||||
|
||||
require.NoError(t, c.Init())
|
||||
t.Run("bad fallback script", func(t *testing.T) {
|
||||
_, err := c.SignAndPushP2PNotaryRequest(nil, []byte{byte(opcode.ASSERT)}, -1, 0, 0, acc) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
||||
require.NotNil(t, err)
|
||||
})
|
||||
|
||||
t.Run("too large fallbackValidFor", func(t *testing.T) {
|
||||
_, err := c.SignAndPushP2PNotaryRequest(nil, []byte{byte(opcode.RET)}, -1, 0, 141, acc) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
||||
require.NotNil(t, err)
|
||||
})
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
sender := testchain.PrivateKeyByID(0) // owner of the deposit in testchain
|
||||
acc := wallet.NewAccountFromPrivateKey(sender)
|
||||
expected := transaction.Transaction{
|
||||
Attributes: []transaction.Attribute{{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 1}}},
|
||||
Script: []byte{byte(opcode.RET)},
|
||||
ValidUntilBlock: chain.BlockHeight() + 5,
|
||||
Signers: []transaction.Signer{{Account: util.Uint160{1, 5, 9}}},
|
||||
Scripts: []transaction.Witness{{
|
||||
InvocationScript: []byte{1, 4, 7},
|
||||
VerificationScript: []byte{3, 6, 9},
|
||||
}},
|
||||
}
|
||||
mainTx := expected
|
||||
_ = expected.Hash()
|
||||
req, err := c.SignAndPushP2PNotaryRequest(&mainTx, []byte{byte(opcode.RET)}, -1, 0, 6, acc) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
||||
require.NoError(t, err)
|
||||
|
||||
// check that request was correctly completed
|
||||
require.Equal(t, expected, *req.MainTransaction) // main tx should be the same
|
||||
require.ElementsMatch(t, []transaction.Attribute{
|
||||
{
|
||||
Type: transaction.NotaryAssistedT,
|
||||
Value: &transaction.NotaryAssisted{NKeys: 0},
|
||||
},
|
||||
{
|
||||
Type: transaction.NotValidBeforeT,
|
||||
Value: &transaction.NotValidBefore{Height: chain.BlockHeight()},
|
||||
},
|
||||
{
|
||||
Type: transaction.ConflictsT,
|
||||
Value: &transaction.Conflicts{Hash: mainTx.Hash()},
|
||||
},
|
||||
}, req.FallbackTransaction.Attributes)
|
||||
require.Equal(t, []transaction.Signer{
|
||||
{Account: chain.GetNotaryContractScriptHash()},
|
||||
{Account: acc.PrivateKey().GetScriptHash()},
|
||||
}, req.FallbackTransaction.Signers)
|
||||
|
||||
// it shouldn't be an error to add completed fallback to the chain
|
||||
w, err := wallet.NewWalletFromFile(notaryPath)
|
||||
require.NoError(t, err)
|
||||
ntr := w.Accounts[0]
|
||||
err = ntr.Decrypt(notaryPass, w.Scrypt)
|
||||
require.NoError(t, err)
|
||||
req.FallbackTransaction.Scripts[0] = transaction.Witness{
|
||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, ntr.PrivateKey().SignHashable(uint32(testchain.Network()), req.FallbackTransaction)...),
|
||||
VerificationScript: []byte{},
|
||||
}
|
||||
b := testchain.NewBlock(t, chain, 1, 0, req.FallbackTransaction)
|
||||
require.NoError(t, chain.AddBlock(b))
|
||||
appLogs, err := chain.GetAppExecResults(req.FallbackTransaction.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(appLogs))
|
||||
appLog := appLogs[0]
|
||||
require.Equal(t, vmstate.Halt, appLog.VMState)
|
||||
require.Equal(t, appLog.GasConsumed, req.FallbackTransaction.SystemFee)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetRawNotaryPoolAndTransaction(t *testing.T) {
|
||||
var (
|
||||
mainHash1, fallbackHash1, mainHash2, fallbackHash2 util.Uint256
|
||||
|
@ -1266,20 +966,6 @@ func TestGetRawNotaryPoolAndTransaction(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestCalculateNotaryFee(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("client not initialized", func(t *testing.T) {
|
||||
_, err := c.CalculateNotaryFee(0) //nolint:staticcheck // SA1019: c.CalculateNotaryFee is deprecated
|
||||
require.NoError(t, err) // Do not require client initialisation for this.
|
||||
})
|
||||
}
|
||||
|
||||
func TestPing(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
|
@ -1294,35 +980,6 @@ func TestPing(t *testing.T) {
|
|||
require.Error(t, c.Ping())
|
||||
}
|
||||
|
||||
func TestCreateTxFromScript(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
priv := testchain.PrivateKey(0)
|
||||
acc := wallet.NewAccountFromPrivateKey(priv)
|
||||
t.Run("NoSystemFee", func(t *testing.T) {
|
||||
tx, err := c.CreateTxFromScript([]byte{byte(opcode.PUSH1)}, acc, -1, 10, nil) //nolint:staticcheck // SA1019: c.CreateTxFromScript is deprecated
|
||||
require.NoError(t, err)
|
||||
require.True(t, tx.ValidUntilBlock > chain.BlockHeight())
|
||||
require.EqualValues(t, 30, tx.SystemFee) // PUSH1
|
||||
require.True(t, len(tx.Signers) == 1)
|
||||
require.Equal(t, acc.PrivateKey().GetScriptHash(), tx.Signers[0].Account)
|
||||
})
|
||||
t.Run("ProvideSystemFee", func(t *testing.T) {
|
||||
tx, err := c.CreateTxFromScript([]byte{byte(opcode.PUSH1)}, acc, 123, 10, nil) //nolint:staticcheck // SA1019: c.CreateTxFromScript is deprecated
|
||||
require.NoError(t, err)
|
||||
require.True(t, tx.ValidUntilBlock > chain.BlockHeight())
|
||||
require.EqualValues(t, 123, tx.SystemFee)
|
||||
require.True(t, len(tx.Signers) == 1)
|
||||
require.Equal(t, acc.PrivateKey().GetScriptHash(), tx.Signers[0].Account)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateNEP17TransferTx(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
|
@ -1885,21 +1542,6 @@ func TestClient_IteratorSessions(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestClient_GetNotaryServiceFeePerKey(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
var defaultNotaryServiceFeePerKey int64 = 1000_0000
|
||||
actual, err := c.GetNotaryServiceFeePerKey() //nolint:staticcheck // SA1019: c.GetNotaryServiceFeePerKey is deprecated
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, defaultNotaryServiceFeePerKey, actual)
|
||||
}
|
||||
|
||||
func TestClient_States(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
|
@ -1973,63 +1615,6 @@ func TestClientOracle(t *testing.T) {
|
|||
require.Equal(t, newPrice, actual)
|
||||
}
|
||||
|
||||
func TestClient_InvokeAndPackIteratorResults(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
// storageItemsCount is the amount of storage items stored in Storage contract, it's hard-coded in the contract code.
|
||||
const storageItemsCount = 255
|
||||
expected := make([][]byte, storageItemsCount)
|
||||
for i := 0; i < storageItemsCount; i++ {
|
||||
expected[i] = stackitem.NewBigInteger(big.NewInt(int64(i))).Bytes()
|
||||
}
|
||||
sort.Slice(expected, func(i, j int) bool {
|
||||
if len(expected[i]) != len(expected[j]) {
|
||||
return len(expected[i]) < len(expected[j])
|
||||
}
|
||||
return bytes.Compare(expected[i], expected[j]) < 0
|
||||
})
|
||||
storageHash, err := util.Uint160DecodeStringLE(storageContractHash)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("default max items constraint", func(t *testing.T) {
|
||||
res, err := c.InvokeAndPackIteratorResults(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil) //nolint:staticcheck // SA1019: c.InvokeAndPackIteratorResults is deprecated
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, stackitem.ArrayT, res.Stack[0].Type())
|
||||
arr, ok := res.Stack[0].Value().([]stackitem.Item)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, config.DefaultMaxIteratorResultItems, len(arr))
|
||||
|
||||
for i := range arr {
|
||||
require.Equal(t, stackitem.ByteArrayT, arr[i].Type())
|
||||
require.Equal(t, expected[i], arr[i].Value().([]byte))
|
||||
}
|
||||
})
|
||||
t.Run("custom max items constraint", func(t *testing.T) {
|
||||
max := 123
|
||||
res, err := c.InvokeAndPackIteratorResults(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil, max) //nolint:staticcheck // SA1019: c.InvokeAndPackIteratorResults is deprecated
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, stackitem.ArrayT, res.Stack[0].Type())
|
||||
arr, ok := res.Stack[0].Value().([]stackitem.Item)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, max, len(arr))
|
||||
|
||||
for i := range arr {
|
||||
require.Equal(t, stackitem.ByteArrayT, arr[i].Type())
|
||||
require.Equal(t, expected[i], arr[i].Value().([]byte))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestClient_Iterator_SessionConfigVariations(t *testing.T) {
|
||||
var expected [][]byte
|
||||
storageHash, err := util.Uint160DecodeStringLE(storageContractHash)
|
||||
|
@ -2481,89 +2066,6 @@ func TestWSClient_SubscriptionsCompat(t *testing.T) {
|
|||
bCount++
|
||||
return b1, primary, sender, ntfName, st
|
||||
}
|
||||
checkDeprecated := func(t *testing.T, filtered bool) {
|
||||
var (
|
||||
bID, txID, ntfID, aerID string
|
||||
err error
|
||||
)
|
||||
b, primary, sender, ntfName, st := getData(t)
|
||||
if filtered {
|
||||
bID, err = c.SubscribeForNewBlocks(&primary) //nolint:staticcheck // SA1019: c.SubscribeForNewBlocks is deprecated
|
||||
require.NoError(t, err)
|
||||
txID, err = c.SubscribeForNewTransactions(&sender, nil) //nolint:staticcheck // SA1019: c.SubscribeForNewTransactions is deprecated
|
||||
require.NoError(t, err)
|
||||
ntfID, err = c.SubscribeForExecutionNotifications(nil, &ntfName) //nolint:staticcheck // SA1019: c.SubscribeForExecutionNotifications is deprecated
|
||||
require.NoError(t, err)
|
||||
aerID, err = c.SubscribeForTransactionExecutions(&st) //nolint:staticcheck // SA1019: c.SubscribeForTransactionExecutions is deprecated
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
bID, err = c.SubscribeForNewBlocks(nil) //nolint:staticcheck // SA1019: c.SubscribeForNewBlocks is deprecated
|
||||
require.NoError(t, err)
|
||||
txID, err = c.SubscribeForNewTransactions(nil, nil) //nolint:staticcheck // SA1019: c.SubscribeForNewTransactions is deprecated
|
||||
require.NoError(t, err)
|
||||
ntfID, err = c.SubscribeForExecutionNotifications(nil, nil) //nolint:staticcheck // SA1019: c.SubscribeForExecutionNotifications is deprecated
|
||||
require.NoError(t, err)
|
||||
aerID, err = c.SubscribeForTransactionExecutions(nil) //nolint:staticcheck // SA1019: c.SubscribeForTransactionExecutions is deprecated
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
var (
|
||||
lock sync.RWMutex
|
||||
received byte
|
||||
exitCh = make(chan struct{})
|
||||
)
|
||||
go func() {
|
||||
dispatcher:
|
||||
for {
|
||||
select {
|
||||
case ntf := <-c.Notifications: //nolint:staticcheck // SA1019: c.Notifications is deprecated
|
||||
lock.Lock()
|
||||
switch ntf.Type {
|
||||
case neorpc.BlockEventID:
|
||||
received |= 1
|
||||
case neorpc.TransactionEventID:
|
||||
received |= 1 << 1
|
||||
case neorpc.NotificationEventID:
|
||||
received |= 1 << 2
|
||||
case neorpc.ExecutionEventID:
|
||||
received |= 1 << 3
|
||||
}
|
||||
lock.Unlock()
|
||||
case <-exitCh:
|
||||
break dispatcher
|
||||
}
|
||||
}
|
||||
drainLoop:
|
||||
for {
|
||||
select {
|
||||
case <-c.Notifications: //nolint:staticcheck // SA1019: c.Notifications is deprecated
|
||||
default:
|
||||
break drainLoop
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Accept the next block and wait for events.
|
||||
require.NoError(t, chain.AddBlock(b))
|
||||
assert.Eventually(t, func() bool {
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
|
||||
return received == 1<<4-1
|
||||
}, time.Second, 100*time.Millisecond)
|
||||
|
||||
require.NoError(t, c.Unsubscribe(bID))
|
||||
require.NoError(t, c.Unsubscribe(txID))
|
||||
require.NoError(t, c.Unsubscribe(ntfID))
|
||||
require.NoError(t, c.Unsubscribe(aerID))
|
||||
exitCh <- struct{}{}
|
||||
}
|
||||
t.Run("deprecated, filtered", func(t *testing.T) {
|
||||
checkDeprecated(t, true)
|
||||
})
|
||||
t.Run("deprecated, non-filtered", func(t *testing.T) {
|
||||
checkDeprecated(t, false)
|
||||
})
|
||||
|
||||
checkRelevant := func(t *testing.T, filtered bool) {
|
||||
b, primary, sender, ntfName, st := getData(t)
|
||||
|
|
|
@ -21,11 +21,7 @@ func TestLocalClient(t *testing.T) {
|
|||
// No addresses configured -> RPC server listens nothing (but it
|
||||
// has MaxGasInvoke, sessions and other stuff).
|
||||
cfg.ApplicationConfiguration.RPC.BasicService.Enabled = true
|
||||
cfg.ApplicationConfiguration.RPC.BasicService.Address = nil //nolint:staticcheck // SA1019: cfg.ApplicationConfiguration.RPC.BasicService.Address is deprecated
|
||||
cfg.ApplicationConfiguration.RPC.BasicService.Port = nil //nolint:staticcheck // SA1019: cfg.ApplicationConfiguration.RPC.BasicService.Port is deprecated
|
||||
cfg.ApplicationConfiguration.RPC.BasicService.Addresses = nil
|
||||
cfg.ApplicationConfiguration.RPC.TLSConfig.Address = nil //nolint:staticcheck // SA1019: cfg.ApplicationConfiguration.RPC.TLSConfig.Address is deprecated
|
||||
cfg.ApplicationConfiguration.RPC.TLSConfig.Port = nil //nolint:staticcheck // SA1019: cfg.ApplicationConfiguration.RPC.TLSConfig.Port is deprecated
|
||||
cfg.ApplicationConfiguration.RPC.TLSConfig.Addresses = nil
|
||||
})
|
||||
// RPC server listens nothing (not exposed in any way), but it works for internal clients.
|
||||
|
|
|
@ -267,7 +267,7 @@ var rpcWsHandlers = map[string]func(*Server, params.Params, *subscriber) (any, *
|
|||
// untyped nil or non-nil structure implementing OracleHandler interface.
|
||||
func New(chain Ledger, conf config.RPC, coreServer *network.Server,
|
||||
orc OracleHandler, log *zap.Logger, errChan chan<- error) Server {
|
||||
addrs := conf.GetAddresses()
|
||||
addrs := conf.Addresses
|
||||
httpServers := make([]*http.Server, len(addrs))
|
||||
for i, addr := range addrs {
|
||||
httpServers[i] = &http.Server{
|
||||
|
@ -277,7 +277,7 @@ func New(chain Ledger, conf config.RPC, coreServer *network.Server,
|
|||
|
||||
var tlsServers []*http.Server
|
||||
if cfg := conf.TLSConfig; cfg.Enabled {
|
||||
addrs := cfg.GetAddresses()
|
||||
addrs := cfg.Addresses
|
||||
tlsServers = make([]*http.Server, len(addrs))
|
||||
for i, addr := range addrs {
|
||||
tlsServers[i] = &http.Server{
|
||||
|
|
Loading…
Reference in a new issue