config: add a special Blockchain type to configure Blockchain

And include some node-specific configurations there with backwards
compatibility. Note that in the future we'll remove Ledger's
fields from the ProtocolConfiguration and it'll be possible to access them in
Blockchain directly (not via .Ledger).

The other option tried was using two configuration types separately, but that
incurs more changes to the codebase, single structure that behaves almost like
the old one is better for backwards compatibility.

Fixes #2676.
This commit is contained in:
Roman Khimov 2022-12-06 16:34:38 +03:00
parent 199a6de737
commit 7589733017
42 changed files with 287 additions and 202 deletions

View file

@ -145,3 +145,13 @@ supported, but this support will eventually be removed.
Removal of this compatibility code is scheduled for May-June 2023 (~0.103.0 Removal of this compatibility code is scheduled for May-June 2023 (~0.103.0
release). 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.
Removal of these options from ProtocolConfiguration is scheduled for May-June
2023 (~0.103.0 release).

View file

@ -235,7 +235,7 @@ func restoreDB(ctx *cli.Context) error {
dumpDir := ctx.String("dump") dumpDir := ctx.String("dump")
if dumpDir != "" { if dumpDir != "" {
cfg.ProtocolConfiguration.SaveStorageBatch = true cfg.ApplicationConfiguration.SaveStorageBatch = true
} }
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log) chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
@ -384,7 +384,7 @@ func mkConsensus(config config.Consensus, tpb time.Duration, chain *core.Blockch
Logger: log, Logger: log,
Broadcast: serv.BroadcastExtensible, Broadcast: serv.BroadcastExtensible,
Chain: chain, Chain: chain,
ProtocolConfiguration: chain.GetConfig(), ProtocolConfiguration: chain.GetConfig().ProtocolConfiguration,
RequestTx: serv.RequestTx, RequestTx: serv.RequestTx,
StopTxFlow: serv.StopTxFlow, StopTxFlow: serv.StopTxFlow,
Wallet: config.UnlockWallet, Wallet: config.UnlockWallet,
@ -658,7 +658,7 @@ func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, stora
return nil, nil, cli.NewExitError(fmt.Errorf("could not initialize storage: %w", err), 1) return nil, nil, cli.NewExitError(fmt.Errorf("could not initialize storage: %w", err), 1)
} }
chain, err := core.NewBlockchain(store, cfg.ProtocolConfiguration, log) chain, err := core.NewBlockchain(store, cfg.Blockchain(), log)
if err != nil { if err != nil {
errText := "could not initialize blockchain: %w" errText := "could not initialize blockchain: %w"
errArgs := []interface{}{err} errArgs := []interface{}{err}

View file

@ -468,7 +468,7 @@ func NewWithConfig(printLogotype bool, onExit func(int), c *readline.Config, cfg
onExit(i) onExit(i)
} }
chain, err := core.NewBlockchain(store, cfg.ProtocolConfiguration, fLog) chain, err := core.NewBlockchain(store, cfg.Blockchain(), fLog)
if err != nil { if err != nil {
return nil, cli.NewExitError(fmt.Errorf("could not initialize blockchain: %w", err), 1) return nil, cli.NewExitError(fmt.Errorf("could not initialize blockchain: %w", err), 1)
} }

View file

@ -122,7 +122,7 @@ func newTestVMClIWithState(t *testing.T) *executor {
} }
store, err := storage.NewLevelDBStore(opts) store, err := storage.NewLevelDBStore(opts)
require.NoError(t, err) require.NoError(t, err)
customConfig := func(c *config.ProtocolConfiguration) { customConfig := func(c *config.Blockchain) {
c.StateRootInHeader = true // Need for P2PStateExchangeExtensions check. c.StateRootInHeader = true // Need for P2PStateExchangeExtensions check.
c.P2PSigExtensions = true // Need for basic chain initializer. c.P2PSigExtensions = true // Need for basic chain initializer.
} }

View file

@ -24,6 +24,8 @@ node-related settings described in the table below.
| DialTimeout | `int64` | `0` | Maximum duration a single dial may take in seconds. Warning: this field is deprecated and moved to `P2P` section. | | 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. | | 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"). | | 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. | | 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. | | 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. | | 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. |
@ -38,9 +40,12 @@ node-related settings described in the table below.
| ProtoTickInterval | `int64` | `5` | Duration in seconds between protocol ticks with each connected peer. Warning: this field is deprecated and moved to `P2P` section. | | 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. | | 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. | | 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`). |
| RPC | [RPC Configuration](#RPC-Configuration) | | Describes [RPC subsystem](rpc.md) configuration. See the [RPC Configuration](#RPC-Configuration) for details. | | RPC | [RPC Configuration](#RPC-Configuration) | | Describes [RPC subsystem](rpc.md) configuration. See the [RPC Configuration](#RPC-Configuration) for details. |
| SaveStorageBatch | `bool` | `false` | Enables storage batch saving before every persist. It is similar to StorageDump plugin for C# node. |
| StateRoot | [State Root Configuration](#State-Root-Configuration) | | State root module configuration. See the [State Root Configuration](#State-Root-Configuration) section for details. | | 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. | | 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. |
| VerifyBlocks | `bool` | `false` | Denotes whether to verify the received blocks. |
### P2P Configuration ### P2P Configuration
@ -335,9 +340,9 @@ protocol-related settings described in the table below.
| Section | Type | Default value | Description | Notes | | Section | Type | Default value | Description | Notes |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| CommitteeHistory | map[uint32]int | none | Number of committee members after the given height, for example `{0: 1, 20: 4}` sets up a chain with one committee member since the genesis and then changes the setting to 4 committee members at the height of 20. `StandbyCommittee` committee setting must have the number of keys equal or exceeding the highest value in this option. Blocks numbers where the change happens must be divisible by the old and by the new values simultaneously. If not set, committee size is derived from the `StandbyCommittee` setting and never changes. | | CommitteeHistory | map[uint32]int | 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. | | 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. `Aspidochelone` is also includes [#2519](https://github.com/nspcc-dev/neo-go/pull/2519) (ported from the [reference](https://github.com/neo-project/neo/pull/2749)). It adjusts the price of `System.Runtime.GetRandom` interop and fixes its vulnerability. | | 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. `Aspidochelone` is also includes [#2519](https://github.com/nspcc-dev/neo-go/pull/2519) (ported from the [reference](https://github.com/neo-project/neo/pull/2749)). It adjusts the price of `System.Runtime.GetRandom` interop and fixes its vulnerability. |
| 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. | | | 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. | | Magic | `uint32` | `0` | Magic number which uniquely identifies Neo network. |
| MaxBlockSize | `uint32` | `262144` | Maximum block size in bytes. | | MaxBlockSize | `uint32` | `262144` | Maximum block size in bytes. |
| MaxBlockSystemFee | `int64` | `900000000000` | Maximum overall transactions system fee per block. | | MaxBlockSystemFee | `int64` | `900000000000` | Maximum overall transactions system fee per block. |
@ -349,9 +354,9 @@ 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. | | 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 attributes `NotValidBefore`, `Conflicts` and `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. | | P2PSigExtensions | `bool` | `false` | Enables following additional Notary service related logic:<br>• Transaction attributes `NotValidBefore`, `Conflicts` and `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`). | | 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`). | | 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. | | 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. | | 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. | | 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. | | SeedList | `[]string` | [] | List of initial nodes addresses used to establish connectivity. |
| StandbyCommittee | `[]string` | [] | List of public keys of standby committee validators are chosen from. | | StandbyCommittee | `[]string` | [] | List of public keys of standby committee validators are chosen from. |
@ -360,5 +365,5 @@ 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. | | TimePerBlock | `Duration` | `15s` | Minimal (and targeted for) time interval between blocks. Must be an integer number of milliseconds. |
| ValidatorsCount | `int` | `0` | Number of validators set for the whole network lifetime, can't be set if `ValidatorsHistory` setting is used. | | ValidatorsCount | `int` | `0` | Number of validators set for the whole network lifetime, can't be set if `ValidatorsHistory` setting is used. |
| ValidatorsHistory | map[uint32]int | 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. | | ValidatorsHistory | map[uint32]int | 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` | Denotes whether to verify the received blocks. | | VerifyBlocks | `bool` | `false` | Denotes whether to verify the received blocks. | 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. |
| VerifyTransactions | `bool` | `false` | Denotes whether to verify transactions in the received blocks. | | VerifyTransactions | `bool` | `false` | Denotes whether to verify transactions in the received blocks. |

View file

@ -65,7 +65,7 @@ func generateOracleContract(t *testing.T, saveState bool) {
// native hashes and saves the generated NEF and manifest to `management_contract` folder. // native hashes and saves the generated NEF and manifest to `management_contract` folder.
// Set `saveState` flag to true and run the test to rewrite NEF and manifest files. // Set `saveState` flag to true and run the test to rewrite NEF and manifest files.
func generateManagementHelperContracts(t *testing.T, saveState bool) { func generateManagementHelperContracts(t *testing.T, saveState bool) {
bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true c.P2PSigExtensions = true
}) })
e := neotest.NewExecutor(t, bc, validator, committee) e := neotest.NewExecutor(t, bc, validator, committee)

View file

@ -23,7 +23,7 @@ import (
// FakeChain implements the Blockchainer interface, but does not provide real functionality. // FakeChain implements the Blockchainer interface, but does not provide real functionality.
type FakeChain struct { type FakeChain struct {
config.ProtocolConfiguration config.Blockchain
*mempool.Pool *mempool.Pool
blocksCh []chan *block.Block blocksCh []chan *block.Block
Blockheight uint32 Blockheight uint32
@ -56,19 +56,19 @@ func NewFakeChain() *FakeChain {
} }
// NewFakeChainWithCustomCfg returns a new FakeChain structure with the specified protocol configuration. // NewFakeChainWithCustomCfg returns a new FakeChain structure with the specified protocol configuration.
func NewFakeChainWithCustomCfg(protocolCfg func(c *config.ProtocolConfiguration)) *FakeChain { func NewFakeChainWithCustomCfg(protocolCfg func(c *config.Blockchain)) *FakeChain {
cfg := config.ProtocolConfiguration{Magic: netmode.UnitTestNet, P2PNotaryRequestPayloadPoolSize: 10} cfg := config.Blockchain{ProtocolConfiguration: config.ProtocolConfiguration{Magic: netmode.UnitTestNet, P2PNotaryRequestPayloadPoolSize: 10}}
if protocolCfg != nil { if protocolCfg != nil {
protocolCfg(&cfg) protocolCfg(&cfg)
} }
return &FakeChain{ return &FakeChain{
Pool: mempool.New(10, 0, false), Pool: mempool.New(10, 0, false),
PoolTxF: func(*transaction.Transaction) error { return nil }, PoolTxF: func(*transaction.Transaction) error { return nil },
poolTxWithData: func(*transaction.Transaction, interface{}, *mempool.Pool) error { return nil }, poolTxWithData: func(*transaction.Transaction, interface{}, *mempool.Pool) error { return nil },
blocks: make(map[util.Uint256]*block.Block), blocks: make(map[util.Uint256]*block.Block),
hdrHashes: make(map[uint32]util.Uint256), hdrHashes: make(map[uint32]util.Uint256),
txs: make(map[util.Uint256]*transaction.Transaction), txs: make(map[util.Uint256]*transaction.Transaction),
ProtocolConfiguration: cfg, Blockchain: cfg,
} }
} }
@ -159,8 +159,8 @@ func (chain *FakeChain) RegisterPostBlock(f func(func(*transaction.Transaction,
} }
// GetConfig implements the Blockchainer interface. // GetConfig implements the Blockchainer interface.
func (chain *FakeChain) GetConfig() config.ProtocolConfiguration { func (chain *FakeChain) GetConfig() config.Blockchain {
return chain.ProtocolConfiguration return chain.Blockchain
} }
// CalculateClaimable implements the Blockchainer interface. // CalculateClaimable implements the Blockchainer interface.

View file

@ -139,7 +139,7 @@ func NewTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockch
memoryStore := storage.NewMemoryStore() memoryStore := storage.NewMemoryStore()
logger := zaptest.NewLogger(t) logger := zaptest.NewLogger(t)
chain, err := core.NewBlockchain(memoryStore, cfg.ProtocolConfiguration, logger) chain, err := core.NewBlockchain(memoryStore, cfg.Blockchain(), logger)
require.NoError(t, err, "could not create chain") require.NoError(t, err, "could not create chain")
if run { if run {
@ -155,7 +155,7 @@ func NewTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockch
Logger: zap.NewNop(), Logger: zap.NewNop(),
Broadcast: netSrv.BroadcastExtensible, Broadcast: netSrv.BroadcastExtensible,
Chain: chain, Chain: chain,
ProtocolConfiguration: chain.GetConfig(), ProtocolConfiguration: cfg.ProtocolConfiguration,
RequestTx: netSrv.RequestTx, RequestTx: netSrv.RequestTx,
StopTxFlow: netSrv.StopTxFlow, StopTxFlow: netSrv.StopTxFlow,
Wallet: cfg.ApplicationConfiguration.Consensus.UnlockWallet, Wallet: cfg.ApplicationConfiguration.Consensus.UnlockWallet,

View file

@ -12,6 +12,8 @@ import (
// ApplicationConfiguration config specific to the node. // ApplicationConfiguration config specific to the node.
type ApplicationConfiguration struct { type ApplicationConfiguration struct {
Ledger `yaml:",inline"`
// Deprecated: please, use Addresses field of P2P section instead, this field will be removed in future versions. // Deprecated: please, use Addresses field of P2P section instead, this field will be removed in future versions.
Address *string `yaml:"Address,omitempty"` Address *string `yaml:"Address,omitempty"`
// Deprecated: please, use Addresses field of P2P section instead, this field will be removed in future versions. // Deprecated: please, use Addresses field of P2P section instead, this field will be removed in future versions.

View file

@ -35,6 +35,15 @@ func (c Config) GenerateUserAgent() string {
return fmt.Sprintf(UserAgentFormat, Version) return fmt.Sprintf(UserAgentFormat, Version)
} }
// Blockchain generates a Blockchain configuration based on Protocol and
// Application settings.
func (c Config) Blockchain() Blockchain {
return Blockchain{
ProtocolConfiguration: c.ProtocolConfiguration,
Ledger: c.ApplicationConfiguration.Ledger,
}
}
// Load attempts to load the config from the given // Load attempts to load the config from the given
// path for the given netMode. // path for the given netMode.
func Load(path string, netMode netmode.Magic) (Config, error) { func Load(path string, netMode netmode.Magic) (Config, error) {

View file

@ -0,0 +1,28 @@
package config
// Ledger contains core node-specific settings that are not
// a part of the ProtocolConfiguration (which is common for every node on the
// network).
type Ledger struct {
// GarbageCollectionPeriod sets the number of blocks to wait before
// starting the next MPT garbage collection cycle when RemoveUntraceableBlocks
// option is used.
GarbageCollectionPeriod uint32 `yaml:"GarbageCollectionPeriod"`
// 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.
KeepOnlyLatestState bool `yaml:"KeepOnlyLatestState"`
// RemoveUntraceableBlocks specifies if old data should be removed.
RemoveUntraceableBlocks bool `yaml:"RemoveUntraceableBlocks"`
// SaveStorageBatch enables storage batch saving before every persist.
SaveStorageBatch bool `yaml:"SaveStorageBatch"`
// VerifyBlocks controls block verification checks (including cryptography).
VerifyBlocks bool `yaml:"VerifyBlocks"`
}
// Blockchain is a set of settings for core.Blockchain to use, it includes protocol
// settings and local node-specific ones.
type Blockchain struct {
ProtocolConfiguration
Ledger
}

View file

@ -19,6 +19,8 @@ type (
// GarbageCollectionPeriod sets the number of blocks to wait before // GarbageCollectionPeriod sets the number of blocks to wait before
// starting the next MPT garbage collection cycle when RemoveUntraceableBlocks // starting the next MPT garbage collection cycle when RemoveUntraceableBlocks
// option is used. // option is used.
//
// Deprecated: please use the same setting in the ApplicationConfiguration, this field will be removed in future versions.
GarbageCollectionPeriod uint32 `yaml:"GarbageCollectionPeriod"` GarbageCollectionPeriod uint32 `yaml:"GarbageCollectionPeriod"`
Magic netmode.Magic `yaml:"Magic"` Magic netmode.Magic `yaml:"Magic"`
@ -35,8 +37,12 @@ type (
// KeepOnlyLatestState specifies if MPT should only store the latest state. // KeepOnlyLatestState specifies if MPT should only store the latest state.
// If true, DB size will be smaller, but older roots won't be accessible. // 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 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"` KeepOnlyLatestState bool `yaml:"KeepOnlyLatestState"`
// RemoveUntraceableBlocks specifies if old data should be removed. // 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"` RemoveUntraceableBlocks bool `yaml:"RemoveUntraceableBlocks"`
// MaxBlockSize is the maximum block size in bytes. // MaxBlockSize is the maximum block size in bytes.
MaxBlockSize uint32 `yaml:"MaxBlockSize"` MaxBlockSize uint32 `yaml:"MaxBlockSize"`
@ -59,6 +65,8 @@ type (
// ReservedAttributes allows to have reserved attributes range for experimental or private purposes. // ReservedAttributes allows to have reserved attributes range for experimental or private purposes.
ReservedAttributes bool `yaml:"ReservedAttributes"` ReservedAttributes bool `yaml:"ReservedAttributes"`
// SaveStorageBatch enables storage batch saving before every persist. // 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"` SaveStorageBatch bool `yaml:"SaveStorageBatch"`
// SecondsPerBlock is the time interval (in seconds) between blocks that consensus nodes work with. // SecondsPerBlock is the time interval (in seconds) between blocks that consensus nodes work with.
// //
@ -78,6 +86,8 @@ type (
// Validators stores history of changes to consensus node number (height: number). // Validators stores history of changes to consensus node number (height: number).
ValidatorsHistory map[uint32]int `yaml:"ValidatorsHistory"` ValidatorsHistory map[uint32]int `yaml:"ValidatorsHistory"`
// Whether to verify received blocks. // 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"` VerifyBlocks bool `yaml:"VerifyBlocks"`
// Whether to verify transactions in the received blocks. // Whether to verify transactions in the received blocks.
VerifyTransactions bool `yaml:"VerifyTransactions"` VerifyTransactions bool `yaml:"VerifyTransactions"`

View file

@ -44,7 +44,7 @@ const nsInMs = 1000000
type Ledger interface { type Ledger interface {
AddBlock(block *coreb.Block) error AddBlock(block *coreb.Block) error
ApplyPolicyToTxSet([]*transaction.Transaction) []*transaction.Transaction ApplyPolicyToTxSet([]*transaction.Transaction) []*transaction.Transaction
GetConfig() config.ProtocolConfiguration GetConfig() config.Blockchain
GetMemPool() *mempool.Pool GetMemPool() *mempool.Pool
GetNextBlockValidators() ([]*keys.PublicKey, error) GetNextBlockValidators() ([]*keys.PublicKey, error)
GetStateRoot(height uint32) (*state.MPTRoot, error) GetStateRoot(height uint32) (*state.MPTRoot, error)
@ -708,7 +708,7 @@ func (s *service) newBlockFromContext(ctx *dbft.Context) block.Block {
var validators keys.PublicKeys var validators keys.PublicKeys
var err error var err error
cfg := s.Chain.GetConfig() cfg := s.Chain.GetConfig().ProtocolConfiguration
if cfg.ShouldUpdateCommitteeAt(ctx.BlockIndex) { if cfg.ShouldUpdateCommitteeAt(ctx.BlockIndex) {
validators, err = s.Chain.GetValidators() validators, err = s.Chain.GetValidators()
} else { } else {

View file

@ -50,7 +50,7 @@ func TestNewWatchingService(t *testing.T) {
Logger: zaptest.NewLogger(t), Logger: zaptest.NewLogger(t),
Broadcast: func(*npayload.Extensible) {}, Broadcast: func(*npayload.Extensible) {},
Chain: bc, Chain: bc,
ProtocolConfiguration: bc.GetConfig(), ProtocolConfiguration: bc.GetConfig().ProtocolConfiguration,
RequestTx: func(...util.Uint256) {}, RequestTx: func(...util.Uint256) {},
StopTxFlow: func() {}, StopTxFlow: func() {},
TimePerBlock: bc.GetConfig().TimePerBlock, TimePerBlock: bc.GetConfig().TimePerBlock,
@ -495,7 +495,7 @@ func newTestServiceWithChain(t *testing.T, bc *core.Blockchain) *service {
Logger: zaptest.NewLogger(t), Logger: zaptest.NewLogger(t),
Broadcast: func(*npayload.Extensible) {}, Broadcast: func(*npayload.Extensible) {},
Chain: bc, Chain: bc,
ProtocolConfiguration: bc.GetConfig(), ProtocolConfiguration: bc.GetConfig().ProtocolConfiguration,
RequestTx: func(...util.Uint256) {}, RequestTx: func(...util.Uint256) {},
StopTxFlow: func() {}, StopTxFlow: func() {},
TimePerBlock: bc.GetConfig().TimePerBlock, TimePerBlock: bc.GetConfig().TimePerBlock,
@ -519,7 +519,7 @@ func newSingleTestChain(t *testing.T) *core.Blockchain {
cfg, err := config.LoadFile(configPath) cfg, err := config.LoadFile(configPath)
require.NoError(t, err, "could not load config") require.NoError(t, err, "could not load config")
chain, err := core.NewBlockchain(storage.NewMemoryStore(), cfg.ProtocolConfiguration, zaptest.NewLogger(t)) chain, err := core.NewBlockchain(storage.NewMemoryStore(), cfg.Blockchain(), zaptest.NewLogger(t))
require.NoError(t, err, "could not create chain") require.NoError(t, err, "could not create chain")
go chain.Run() go chain.Run()
@ -532,7 +532,7 @@ func newTestChain(t *testing.T, stateRootInHeader bool) *core.Blockchain {
require.NoError(t, err) require.NoError(t, err)
unitTestNetCfg.ProtocolConfiguration.StateRootInHeader = stateRootInHeader unitTestNetCfg.ProtocolConfiguration.StateRootInHeader = stateRootInHeader
chain, err := core.NewBlockchain(storage.NewMemoryStore(), unitTestNetCfg.ProtocolConfiguration, zaptest.NewLogger(t)) chain, err := core.NewBlockchain(storage.NewMemoryStore(), unitTestNetCfg.Blockchain(), zaptest.NewLogger(t))
require.NoError(t, err) require.NoError(t, err)
go chain.Run() go chain.Run()

View file

@ -37,7 +37,7 @@ var (
func TestCreateBasicChain(t *testing.T) { func TestCreateBasicChain(t *testing.T) {
const saveChain = false const saveChain = false
bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(cfg *config.ProtocolConfiguration) { bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(cfg *config.Blockchain) {
cfg.P2PSigExtensions = true cfg.P2PSigExtensions = true
}) })
e := neotest.NewExecutor(t, bc, validators, committee) e := neotest.NewExecutor(t, bc, validators, committee)

View file

@ -116,7 +116,7 @@ var (
type Blockchain struct { type Blockchain struct {
HeaderHashes HeaderHashes
config config.ProtocolConfiguration config config.Blockchain
// The only way chain state changes is by adding blocks, so we can't // The only way chain state changes is by adding blocks, so we can't
// allow concurrent block additions. It differs from the next lock in // allow concurrent block additions. It differs from the next lock in
@ -218,11 +218,12 @@ type transferData struct {
// NewBlockchain returns a new blockchain object the will use the // NewBlockchain returns a new blockchain object the will use the
// given Store as its underlying storage. For it to work correctly you need // given Store as its underlying storage. For it to work correctly you need
// to spawn a goroutine for its Run method after this initialization. // to spawn a goroutine for its Run method after this initialization.
func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.Logger) (*Blockchain, error) { func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Blockchain, error) {
if log == nil { if log == nil {
return nil, errors.New("empty logger") return nil, errors.New("empty logger")
} }
// Protocol configuration fixups/checks.
if cfg.InitialGASSupply <= 0 { if cfg.InitialGASSupply <= 0 {
cfg.InitialGASSupply = fixedn.Fixed8(defaultInitialGAS) cfg.InitialGASSupply = fixedn.Fixed8(defaultInitialGAS)
log.Info("initial gas supply is not set or wrong, setting default value", zap.String("InitialGASSupply", cfg.InitialGASSupply.String())) log.Info("initial gas supply is not set or wrong, setting default value", zap.String("InitialGASSupply", cfg.InitialGASSupply.String()))
@ -280,10 +281,6 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
zap.Int("StateSyncInterval", cfg.StateSyncInterval)) zap.Int("StateSyncInterval", cfg.StateSyncInterval))
} }
} }
if cfg.RemoveUntraceableBlocks && cfg.GarbageCollectionPeriod == 0 {
cfg.GarbageCollectionPeriod = defaultGCPeriod
log.Info("GarbageCollectionPeriod is not set or wrong, using default value", zap.Uint32("GarbageCollectionPeriod", cfg.GarbageCollectionPeriod))
}
if len(cfg.NativeUpdateHistories) == 0 { if len(cfg.NativeUpdateHistories) == 0 {
cfg.NativeUpdateHistories = map[string][]uint32{} cfg.NativeUpdateHistories = map[string][]uint32{}
log.Info("NativeActivations are not set, using default values") log.Info("NativeActivations are not set, using default values")
@ -292,6 +289,20 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
cfg.Hardforks = map[string]uint32{} cfg.Hardforks = map[string]uint32{}
log.Info("Hardforks are not set, using default value") log.Info("Hardforks are not set, using default value")
} }
// 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
cfg.Ledger.VerifyBlocks = cfg.Ledger.VerifyBlocks || cfg.ProtocolConfiguration.VerifyBlocks //nolint:staticcheck // SA1019: cfg.ProtocolConfiguration.VerifyBlocks is deprecated
// Local config consistency checks.
if cfg.Ledger.RemoveUntraceableBlocks && cfg.Ledger.GarbageCollectionPeriod == 0 {
cfg.Ledger.GarbageCollectionPeriod = defaultGCPeriod
log.Info("GarbageCollectionPeriod is not set or wrong, using default value", zap.Uint32("GarbageCollectionPeriod", cfg.Ledger.GarbageCollectionPeriod))
}
bc := &Blockchain{ bc := &Blockchain{
config: cfg, config: cfg,
dao: dao.NewSimple(s, cfg.StateRootInHeader, cfg.P2PSigExtensions), dao: dao.NewSimple(s, cfg.StateRootInHeader, cfg.P2PSigExtensions),
@ -304,10 +315,10 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
events: make(chan bcEvent), events: make(chan bcEvent),
subCh: make(chan interface{}), subCh: make(chan interface{}),
unsubCh: make(chan interface{}), unsubCh: make(chan interface{}),
contracts: *native.NewContracts(cfg), contracts: *native.NewContracts(cfg.ProtocolConfiguration),
} }
bc.stateRoot = stateroot.NewModule(bc.GetConfig(), bc.VerifyWitness, bc.log, bc.dao.Store) bc.stateRoot = stateroot.NewModule(cfg, bc.VerifyWitness, bc.log, bc.dao.Store)
bc.contracts.Designate.StateRootService = bc.stateRoot bc.contracts.Designate.StateRootService = bc.stateRoot
if err := bc.init(); err != nil { if err := bc.init(); err != nil {
@ -370,13 +381,13 @@ func (bc *Blockchain) init() error {
StateRootInHeader: bc.config.StateRootInHeader, StateRootInHeader: bc.config.StateRootInHeader,
P2PSigExtensions: bc.config.P2PSigExtensions, P2PSigExtensions: bc.config.P2PSigExtensions,
P2PStateExchangeExtensions: bc.config.P2PStateExchangeExtensions, P2PStateExchangeExtensions: bc.config.P2PStateExchangeExtensions,
KeepOnlyLatestState: bc.config.KeepOnlyLatestState, KeepOnlyLatestState: bc.config.Ledger.KeepOnlyLatestState,
Value: version, Value: version,
} }
bc.dao.PutVersion(ver) bc.dao.PutVersion(ver)
bc.dao.Version = ver bc.dao.Version = ver
bc.persistent.Version = ver bc.persistent.Version = ver
genesisBlock, err := CreateGenesisBlock(bc.config) genesisBlock, err := CreateGenesisBlock(bc.config.ProtocolConfiguration)
if err != nil { if err != nil {
return err return err
} }
@ -401,9 +412,9 @@ func (bc *Blockchain) init() error {
return fmt.Errorf("P2PStateExchangeExtensions setting mismatch (old=%t, new=%t)", return fmt.Errorf("P2PStateExchangeExtensions setting mismatch (old=%t, new=%t)",
ver.P2PStateExchangeExtensions, bc.config.P2PStateExchangeExtensions) ver.P2PStateExchangeExtensions, bc.config.P2PStateExchangeExtensions)
} }
if ver.KeepOnlyLatestState != bc.config.KeepOnlyLatestState { if ver.KeepOnlyLatestState != bc.config.Ledger.KeepOnlyLatestState {
return fmt.Errorf("KeepOnlyLatestState setting mismatch (old=%v, new=%v)", return fmt.Errorf("KeepOnlyLatestState setting mismatch (old=%v, new=%v)",
ver.KeepOnlyLatestState, bc.config.KeepOnlyLatestState) ver.KeepOnlyLatestState, bc.config.Ledger.KeepOnlyLatestState)
} }
bc.dao.Version = ver bc.dao.Version = ver
bc.persistent.Version = ver bc.persistent.Version = ver
@ -432,7 +443,7 @@ func (bc *Blockchain) init() error {
if (stateChStage[0] & stateResetBit) != 0 { if (stateChStage[0] & stateResetBit) != 0 {
return bc.resetStateInternal(stateSyncPoint, stateChangeStage(stateChStage[0]&(^stateResetBit))) return bc.resetStateInternal(stateSyncPoint, stateChangeStage(stateChStage[0]&(^stateResetBit)))
} }
if !(bc.GetConfig().P2PStateExchangeExtensions && bc.GetConfig().RemoveUntraceableBlocks) { if !(bc.config.P2PStateExchangeExtensions && bc.config.Ledger.RemoveUntraceableBlocks) {
return errors.New("state jump was not completed, but P2PStateExchangeExtensions are disabled or archival node capability is on. " + return errors.New("state jump was not completed, but P2PStateExchangeExtensions are disabled or archival node capability is on. " +
"To start an archival node drop the database manually and restart the node") "To start an archival node drop the database manually and restart the node")
} }
@ -647,10 +658,10 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
bc.log.Info("chain is at the proper state", zap.Uint32("height", height)) bc.log.Info("chain is at the proper state", zap.Uint32("height", height))
return nil return nil
} }
if bc.config.KeepOnlyLatestState { if bc.config.Ledger.KeepOnlyLatestState {
return fmt.Errorf("KeepOnlyLatestState is enabled, state for height %d is outdated and removed from the storage", height) return fmt.Errorf("KeepOnlyLatestState is enabled, state for height %d is outdated and removed from the storage", height)
} }
if bc.config.RemoveUntraceableBlocks && currHeight >= bc.config.MaxTraceableBlocks { if bc.config.Ledger.RemoveUntraceableBlocks && currHeight >= bc.config.MaxTraceableBlocks {
return fmt.Errorf("RemoveUntraceableBlocks is enabled, a necessary batch of traceable blocks has already been removed") return fmt.Errorf("RemoveUntraceableBlocks is enabled, a necessary batch of traceable blocks has already been removed")
} }
} }
@ -727,7 +738,7 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
pStorageStart := p pStorageStart := p
var mode = mpt.ModeAll var mode = mpt.ModeAll
if bc.config.RemoveUntraceableBlocks { if bc.config.Ledger.RemoveUntraceableBlocks {
mode |= mpt.ModeGCFlag mode |= mpt.ModeGCFlag
} }
trieStore := mpt.NewTrieStore(sr.Root, mode, cache.Store) trieStore := mpt.NewTrieStore(sr.Root, mode, cache.Store)
@ -919,14 +930,14 @@ func (bc *Blockchain) Run() {
var oldPersisted uint32 var oldPersisted uint32
var gcDur time.Duration var gcDur time.Duration
if bc.config.RemoveUntraceableBlocks { if bc.config.Ledger.RemoveUntraceableBlocks {
oldPersisted = atomic.LoadUint32(&bc.persistedHeight) oldPersisted = atomic.LoadUint32(&bc.persistedHeight)
} }
dur, err := bc.persist(nextSync) dur, err := bc.persist(nextSync)
if err != nil { if err != nil {
bc.log.Warn("failed to persist blockchain", zap.Error(err)) bc.log.Warn("failed to persist blockchain", zap.Error(err))
} }
if bc.config.RemoveUntraceableBlocks { if bc.config.Ledger.RemoveUntraceableBlocks {
gcDur = bc.tryRunGC(oldPersisted) gcDur = bc.tryRunGC(oldPersisted)
} }
nextSync = dur > persistInterval*2 nextSync = dur > persistInterval*2
@ -955,14 +966,14 @@ func (bc *Blockchain) tryRunGC(oldHeight uint32) time.Duration {
} }
} }
// Always round to the GCP. // Always round to the GCP.
tgtBlock /= int64(bc.config.GarbageCollectionPeriod) tgtBlock /= int64(bc.config.Ledger.GarbageCollectionPeriod)
tgtBlock *= int64(bc.config.GarbageCollectionPeriod) tgtBlock *= int64(bc.config.Ledger.GarbageCollectionPeriod)
// Count periods. // Count periods.
oldHeight /= bc.config.GarbageCollectionPeriod oldHeight /= bc.config.Ledger.GarbageCollectionPeriod
newHeight /= bc.config.GarbageCollectionPeriod newHeight /= bc.config.Ledger.GarbageCollectionPeriod
if tgtBlock > int64(bc.config.GarbageCollectionPeriod) && newHeight != oldHeight { if tgtBlock > int64(bc.config.Ledger.GarbageCollectionPeriod) && newHeight != oldHeight {
tgtBlock /= int64(bc.config.GarbageCollectionPeriod) tgtBlock /= int64(bc.config.Ledger.GarbageCollectionPeriod)
tgtBlock *= int64(bc.config.GarbageCollectionPeriod) tgtBlock *= int64(bc.config.Ledger.GarbageCollectionPeriod)
dur = bc.stateRoot.GC(uint32(tgtBlock), bc.store) dur = bc.stateRoot.GC(uint32(tgtBlock), bc.store)
dur += bc.removeOldTransfers(uint32(tgtBlock)) dur += bc.removeOldTransfers(uint32(tgtBlock))
} }
@ -1298,12 +1309,12 @@ func (bc *Blockchain) AddBlock(block *block.Block) error {
} }
if block.Index == bc.HeaderHeight()+1 { if block.Index == bc.HeaderHeight()+1 {
err := bc.addHeaders(bc.config.VerifyBlocks, &block.Header) err := bc.addHeaders(bc.config.Ledger.VerifyBlocks, &block.Header)
if err != nil { if err != nil {
return err return err
} }
} }
if bc.config.VerifyBlocks { if bc.config.Ledger.VerifyBlocks {
merkle := block.ComputeMerkleRoot() merkle := block.ComputeMerkleRoot()
if !block.MerkleRoot.Equals(merkle) { if !block.MerkleRoot.Equals(merkle) {
return errors.New("invalid block: MerkleRoot mismatch") return errors.New("invalid block: MerkleRoot mismatch")
@ -1333,7 +1344,7 @@ func (bc *Blockchain) AddBlock(block *block.Block) error {
// AddHeaders processes the given headers and add them to the // AddHeaders processes the given headers and add them to the
// HeaderHashList. It expects headers to be sorted by index. // HeaderHashList. It expects headers to be sorted by index.
func (bc *Blockchain) AddHeaders(headers ...*block.Header) error { func (bc *Blockchain) AddHeaders(headers ...*block.Header) error {
return bc.addHeaders(bc.config.VerifyBlocks, headers...) return bc.addHeaders(bc.config.Ledger.VerifyBlocks, headers...)
} }
// addHeaders is an internal implementation of AddHeaders (`verify` parameter // addHeaders is an internal implementation of AddHeaders (`verify` parameter
@ -1415,7 +1426,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
transCache = make(map[util.Uint160]transferData) transCache = make(map[util.Uint160]transferData)
) )
kvcache.StoreAsCurrentBlock(block) kvcache.StoreAsCurrentBlock(block)
if bc.config.RemoveUntraceableBlocks { if bc.config.Ledger.RemoveUntraceableBlocks {
var start, stop uint32 var start, stop uint32
if bc.config.P2PStateExchangeExtensions { if bc.config.P2PStateExchangeExtensions {
// remove batch of old blocks starting from P2-MaxTraceableBlocks-StateSyncInterval up to P2-MaxTraceableBlocks // remove batch of old blocks starting from P2-MaxTraceableBlocks-StateSyncInterval up to P2-MaxTraceableBlocks
@ -1567,7 +1578,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
} }
} }
if bc.config.SaveStorageBatch { if bc.config.Ledger.SaveStorageBatch {
bc.lastBatch = cache.GetBatch() bc.lastBatch = cache.GetBatch()
} }
// Every persist cycle we also compact our in-memory MPT. It's flushed // Every persist cycle we also compact our in-memory MPT. It's flushed
@ -1878,7 +1889,7 @@ func (bc *Blockchain) GetTokenLastUpdated(acc util.Uint160) (map[int32]uint32, e
if err != nil { if err != nil {
return nil, err return nil, err
} }
if bc.config.P2PStateExchangeExtensions && bc.config.RemoveUntraceableBlocks { if bc.config.P2PStateExchangeExtensions && bc.config.Ledger.RemoveUntraceableBlocks {
if _, ok := info.LastUpdated[bc.contracts.NEO.ID]; !ok { if _, ok := info.LastUpdated[bc.contracts.NEO.ID]; !ok {
nBalance, lub := bc.contracts.NEO.BalanceOf(bc.dao, acc) nBalance, lub := bc.contracts.NEO.BalanceOf(bc.dao, acc)
if nBalance.Sign() != 0 { if nBalance.Sign() != 0 {
@ -2121,7 +2132,7 @@ func (bc *Blockchain) GetNatives() []state.NativeContract {
} }
// GetConfig returns the config stored in the blockchain. // GetConfig returns the config stored in the blockchain.
func (bc *Blockchain) GetConfig() config.ProtocolConfiguration { func (bc *Blockchain) GetConfig() config.Blockchain {
return bc.config return bc.config
} }
@ -2584,7 +2595,7 @@ func (bc *Blockchain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *
// GetTestHistoricVM returns an interop context with VM set up for a test run. // GetTestHistoricVM returns an interop context with VM set up for a test run.
func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transaction, nextBlockHeight uint32) (*interop.Context, error) { func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transaction, nextBlockHeight uint32) (*interop.Context, error) {
if bc.config.KeepOnlyLatestState { if bc.config.Ledger.KeepOnlyLatestState {
return nil, errors.New("only latest state is supported") return nil, errors.New("only latest state is supported")
} }
b, err := bc.getFakeNextBlock(nextBlockHeight) b, err := bc.getFakeNextBlock(nextBlockHeight)
@ -2592,7 +2603,7 @@ func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transact
return nil, fmt.Errorf("failed to create fake block for height %d: %w", nextBlockHeight, err) return nil, fmt.Errorf("failed to create fake block for height %d: %w", nextBlockHeight, err)
} }
var mode = mpt.ModeAll var mode = mpt.ModeAll
if bc.config.RemoveUntraceableBlocks { if bc.config.Ledger.RemoveUntraceableBlocks {
if b.Index < bc.BlockHeight()-bc.config.MaxTraceableBlocks { if b.Index < bc.BlockHeight()-bc.config.MaxTraceableBlocks {
return nil, fmt.Errorf("state for height %d is outdated and removed from the storage", b.Index) return nil, fmt.Errorf("state for height %d is outdated and removed from the storage", b.Index)
} }

View file

@ -32,21 +32,21 @@ func TestVerifyHeader(t *testing.T) {
t.Run("Hash", func(t *testing.T) { t.Run("Hash", func(t *testing.T) {
h := prev.Hash() h := prev.Hash()
h[0] = ^h[0] h[0] = ^h[0]
hdr := newBlock(bc.config, 1, h).Header hdr := newBlock(bc.config.ProtocolConfiguration, 1, h).Header
require.True(t, errors.Is(bc.verifyHeader(&hdr, &prev), ErrHdrHashMismatch)) require.True(t, errors.Is(bc.verifyHeader(&hdr, &prev), ErrHdrHashMismatch))
}) })
t.Run("Index", func(t *testing.T) { t.Run("Index", func(t *testing.T) {
hdr := newBlock(bc.config, 3, prev.Hash()).Header hdr := newBlock(bc.config.ProtocolConfiguration, 3, prev.Hash()).Header
require.True(t, errors.Is(bc.verifyHeader(&hdr, &prev), ErrHdrIndexMismatch)) require.True(t, errors.Is(bc.verifyHeader(&hdr, &prev), ErrHdrIndexMismatch))
}) })
t.Run("Timestamp", func(t *testing.T) { t.Run("Timestamp", func(t *testing.T) {
hdr := newBlock(bc.config, 1, prev.Hash()).Header hdr := newBlock(bc.config.ProtocolConfiguration, 1, prev.Hash()).Header
hdr.Timestamp = 0 hdr.Timestamp = 0
require.True(t, errors.Is(bc.verifyHeader(&hdr, &prev), ErrHdrInvalidTimestamp)) require.True(t, errors.Is(bc.verifyHeader(&hdr, &prev), ErrHdrInvalidTimestamp))
}) })
}) })
t.Run("Valid", func(t *testing.T) { t.Run("Valid", func(t *testing.T) {
hdr := newBlock(bc.config, 1, prev.Hash()).Header hdr := newBlock(bc.config.ProtocolConfiguration, 1, prev.Hash()).Header
require.NoError(t, bc.verifyHeader(&hdr, &prev)) require.NoError(t, bc.verifyHeader(&hdr, &prev))
}) })
} }
@ -144,12 +144,12 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
maxTraceable uint32 = 6 maxTraceable uint32 = 6
) )
spountCfg := func(c *config.Config) { spountCfg := func(c *config.Config) {
c.ProtocolConfiguration.RemoveUntraceableBlocks = true c.ApplicationConfiguration.RemoveUntraceableBlocks = true
c.ProtocolConfiguration.StateRootInHeader = true c.ProtocolConfiguration.StateRootInHeader = true
c.ProtocolConfiguration.P2PStateExchangeExtensions = true c.ProtocolConfiguration.P2PStateExchangeExtensions = true
c.ProtocolConfiguration.StateSyncInterval = stateSyncInterval c.ProtocolConfiguration.StateSyncInterval = stateSyncInterval
c.ProtocolConfiguration.MaxTraceableBlocks = maxTraceable c.ProtocolConfiguration.MaxTraceableBlocks = maxTraceable
c.ProtocolConfiguration.KeepOnlyLatestState = true c.ApplicationConfiguration.KeepOnlyLatestState = true
} }
bcSpout := newTestChainWithCustomCfg(t, spountCfg) bcSpout := newTestChainWithCustomCfg(t, spountCfg)
@ -190,7 +190,7 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
cfg(&unitTestNetCfg) cfg(&unitTestNetCfg)
log := zaptest.NewLogger(t) log := zaptest.NewLogger(t)
_, err = NewBlockchain(store, unitTestNetCfg.ProtocolConfiguration, log) _, err = NewBlockchain(store, unitTestNetCfg.Blockchain(), log)
if len(errText) != 0 { if len(errText) != 0 {
require.Error(t, err) require.Error(t, err)
require.True(t, strings.Contains(err.Error(), errText)) require.True(t, strings.Contains(err.Error(), errText))
@ -200,7 +200,7 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
} }
boltCfg := func(c *config.Config) { boltCfg := func(c *config.Config) {
spountCfg(c) spountCfg(c)
c.ProtocolConfiguration.KeepOnlyLatestState = true c.ApplicationConfiguration.KeepOnlyLatestState = true
} }
// manually store statejump stage to check statejump recover process // manually store statejump stage to check statejump recover process
bPrefix[0] = byte(storage.SYSStateChangeStage) bPrefix[0] = byte(storage.SYSStateChangeStage)
@ -219,7 +219,7 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
bcSpout.dao.Store.Put([]byte{byte(storage.SYSStateSyncPoint)}, point) bcSpout.dao.Store.Put([]byte{byte(storage.SYSStateSyncPoint)}, point)
checkNewBlockchainErr(t, func(c *config.Config) { checkNewBlockchainErr(t, func(c *config.Config) {
boltCfg(c) boltCfg(c)
c.ProtocolConfiguration.RemoveUntraceableBlocks = false 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, "state jump was not completed, but P2PStateExchangeExtensions are disabled or archival node capability is on")
}) })
t.Run("invalid state sync point", func(t *testing.T) { t.Run("invalid state sync point", func(t *testing.T) {

View file

@ -62,7 +62,7 @@ func newLevelDBForTestingWithPath(t testing.TB, dbPath string) (storage.Store, s
func TestBlockchain_StartFromExistingDB(t *testing.T) { func TestBlockchain_StartFromExistingDB(t *testing.T) {
ps, path := newLevelDBForTestingWithPath(t, "") ps, path := newLevelDBForTestingWithPath(t, "")
customConfig := func(c *config.ProtocolConfiguration) { customConfig := func(c *config.Blockchain) {
c.StateRootInHeader = true // Need for P2PStateExchangeExtensions check. c.StateRootInHeader = true // Need for P2PStateExchangeExtensions check.
c.P2PSigExtensions = true // Need for basic chain initializer. c.P2PSigExtensions = true // Need for basic chain initializer.
} }
@ -106,7 +106,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
}) })
t.Run("mismatch StateRootInHeader", func(t *testing.T) { t.Run("mismatch StateRootInHeader", func(t *testing.T) {
ps = newPS(t) ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.ProtocolConfiguration) { _, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c) customConfig(c)
c.StateRootInHeader = false c.StateRootInHeader = false
}, ps) }, ps)
@ -115,7 +115,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
}) })
t.Run("mismatch P2PSigExtensions", func(t *testing.T) { t.Run("mismatch P2PSigExtensions", func(t *testing.T) {
ps = newPS(t) ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.ProtocolConfiguration) { _, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c) customConfig(c)
c.P2PSigExtensions = false c.P2PSigExtensions = false
}, ps) }, ps)
@ -124,7 +124,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
}) })
t.Run("mismatch P2PStateExchangeExtensions", func(t *testing.T) { t.Run("mismatch P2PStateExchangeExtensions", func(t *testing.T) {
ps = newPS(t) ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.ProtocolConfiguration) { _, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c) customConfig(c)
c.StateRootInHeader = true c.StateRootInHeader = true
c.P2PStateExchangeExtensions = true c.P2PStateExchangeExtensions = true
@ -134,9 +134,9 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
}) })
t.Run("mismatch KeepOnlyLatestState", func(t *testing.T) { t.Run("mismatch KeepOnlyLatestState", func(t *testing.T) {
ps = newPS(t) ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.ProtocolConfiguration) { _, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c) customConfig(c)
c.KeepOnlyLatestState = true c.Ledger.KeepOnlyLatestState = true
}, ps) }, ps)
require.Error(t, err) require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "KeepOnlyLatestState setting mismatch"), err) require.True(t, strings.Contains(err.Error(), "KeepOnlyLatestState setting mismatch"), err)
@ -228,7 +228,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
*/ */
t.Run("invalid native contract deactivation", func(t *testing.T) { t.Run("invalid native contract deactivation", func(t *testing.T) {
ps = newPS(t) ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.ProtocolConfiguration) { _, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c) customConfig(c)
c.NativeUpdateHistories = map[string][]uint32{ c.NativeUpdateHistories = map[string][]uint32{
nativenames.Policy: {0}, nativenames.Policy: {0},
@ -291,7 +291,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
} }
func TestBlockchain_AddHeaders(t *testing.T) { func TestBlockchain_AddHeaders(t *testing.T) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
c.StateRootInHeader = true c.StateRootInHeader = true
}) })
e := neotest.NewExecutor(t, bc, acc, acc) e := neotest.NewExecutor(t, bc, acc, acc)
@ -342,7 +342,7 @@ func TestBlockchain_AddHeaders(t *testing.T) {
} }
func TestBlockchain_AddBlockStateRoot(t *testing.T) { func TestBlockchain_AddBlockStateRoot(t *testing.T) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
c.StateRootInHeader = true c.StateRootInHeader = true
}) })
e := neotest.NewExecutor(t, bc, acc, acc) e := neotest.NewExecutor(t, bc, acc, acc)
@ -371,7 +371,7 @@ func TestBlockchain_AddBlockStateRoot(t *testing.T) {
} }
func TestBlockchain_AddHeadersStateRoot(t *testing.T) { func TestBlockchain_AddHeadersStateRoot(t *testing.T) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
c.StateRootInHeader = true c.StateRootInHeader = true
}) })
e := neotest.NewExecutor(t, bc, acc, acc) e := neotest.NewExecutor(t, bc, acc, acc)
@ -401,7 +401,7 @@ func TestBlockchain_AddHeadersStateRoot(t *testing.T) {
} }
func TestBlockchain_AddBadBlock(t *testing.T) { func TestBlockchain_AddBadBlock(t *testing.T) {
check := func(t *testing.T, b *block.Block, cfg func(c *config.ProtocolConfiguration)) { check := func(t *testing.T, b *block.Block, cfg func(c *config.Blockchain)) {
bc, _ := chain.NewSingleWithCustomConfig(t, cfg) bc, _ := chain.NewSingleWithCustomConfig(t, cfg)
err := bc.AddBlock(b) err := bc.AddBlock(b)
if cfg == nil { if cfg == nil {
@ -420,25 +420,25 @@ func TestBlockchain_AddBadBlock(t *testing.T) {
b := e.NewUnsignedBlock(t, tx) b := e.NewUnsignedBlock(t, tx)
e.SignBlock(b) e.SignBlock(b)
check(t, b, nil) check(t, b, nil)
check(t, b, func(c *config.ProtocolConfiguration) { check(t, b, func(c *config.Blockchain) {
c.VerifyBlocks = false c.Ledger.VerifyBlocks = false
}) })
b = e.NewUnsignedBlock(t) b = e.NewUnsignedBlock(t)
b.PrevHash = util.Uint256{} // Intentionally make block invalid. b.PrevHash = util.Uint256{} // Intentionally make block invalid.
e.SignBlock(b) e.SignBlock(b)
check(t, b, nil) check(t, b, nil)
check(t, b, func(c *config.ProtocolConfiguration) { check(t, b, func(c *config.Blockchain) {
c.VerifyBlocks = false c.Ledger.VerifyBlocks = false
}) })
tx = e.NewUnsignedTx(t, neoHash, "transfer", acc.ScriptHash(), util.Uint160{1, 2, 3}, 1, nil) // Check the good tx. tx = e.NewUnsignedTx(t, neoHash, "transfer", acc.ScriptHash(), util.Uint160{1, 2, 3}, 1, nil) // Check the good tx.
e.SignTx(t, tx, -1, acc) e.SignTx(t, tx, -1, acc)
b = e.NewUnsignedBlock(t, tx) b = e.NewUnsignedBlock(t, tx)
e.SignBlock(b) e.SignBlock(b)
check(t, b, func(c *config.ProtocolConfiguration) { check(t, b, func(c *config.Blockchain) {
c.VerifyTransactions = true c.VerifyTransactions = true
c.VerifyBlocks = true c.Ledger.VerifyBlocks = true
}) })
} }
@ -584,7 +584,7 @@ func TestBlockchain_VerifyHashAgainstScript(t *testing.T) {
} }
func TestBlockchain_IsTxStillRelevant(t *testing.T) { func TestBlockchain_IsTxStillRelevant(t *testing.T) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true c.P2PSigExtensions = true
}) })
e := neotest.NewExecutor(t, bc, acc, acc) e := neotest.NewExecutor(t, bc, acc, acc)
@ -903,10 +903,10 @@ func TestBlockchain_RemoveUntraceable(t *testing.T) {
} }
} }
t.Run("P2PStateExchangeExtensions off", func(t *testing.T) { t.Run("P2PStateExchangeExtensions off", func(t *testing.T) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
c.MaxTraceableBlocks = 2 c.MaxTraceableBlocks = 2
c.GarbageCollectionPeriod = 2 c.Ledger.GarbageCollectionPeriod = 2
c.RemoveUntraceableBlocks = true c.Ledger.RemoveUntraceableBlocks = true
}) })
e := neotest.NewExecutor(t, bc, acc, acc) e := neotest.NewExecutor(t, bc, acc, acc)
neoValidatorInvoker := e.ValidatorInvoker(e.NativeHash(t, nativenames.Neo)) neoValidatorInvoker := e.ValidatorInvoker(e.NativeHash(t, nativenames.Neo))
@ -934,10 +934,10 @@ func TestBlockchain_RemoveUntraceable(t *testing.T) {
check(t, bc, tx1Hash, b1.Hash(), sRoot.Root, true) check(t, bc, tx1Hash, b1.Hash(), sRoot.Root, true)
}) })
t.Run("P2PStateExchangeExtensions on", func(t *testing.T) { t.Run("P2PStateExchangeExtensions on", func(t *testing.T) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
c.MaxTraceableBlocks = 2 c.MaxTraceableBlocks = 2
c.GarbageCollectionPeriod = 2 c.Ledger.GarbageCollectionPeriod = 2
c.RemoveUntraceableBlocks = true c.Ledger.RemoveUntraceableBlocks = true
c.P2PStateExchangeExtensions = true c.P2PStateExchangeExtensions = true
c.StateSyncInterval = 2 c.StateSyncInterval = 2
c.StateRootInHeader = true c.StateRootInHeader = true
@ -1047,7 +1047,7 @@ func TestConfigNativeUpdateHistory(t *testing.T) {
} }
func TestBlockchain_VerifyTx(t *testing.T) { func TestBlockchain_VerifyTx(t *testing.T) {
bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true c.P2PSigExtensions = true
c.ReservedAttributes = true c.ReservedAttributes = true
}) })
@ -1467,7 +1467,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
return tx return tx
} }
t.Run("Disabled", func(t *testing.T) { t.Run("Disabled", func(t *testing.T) {
bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = false c.P2PSigExtensions = false
c.ReservedAttributes = false c.ReservedAttributes = false
}) })
@ -1509,7 +1509,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
return tx return tx
} }
t.Run("Disabled", func(t *testing.T) { t.Run("Disabled", func(t *testing.T) {
bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = false c.P2PSigExtensions = false
c.ReservedAttributes = false c.ReservedAttributes = false
}) })
@ -1553,7 +1553,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
return tx return tx
} }
t.Run("disabled", func(t *testing.T) { t.Run("disabled", func(t *testing.T) {
bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = false c.P2PSigExtensions = false
c.ReservedAttributes = false c.ReservedAttributes = false
}) })
@ -1649,7 +1649,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
return tx return tx
} }
t.Run("Disabled", func(t *testing.T) { t.Run("Disabled", func(t *testing.T) {
bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = false c.P2PSigExtensions = false
c.ReservedAttributes = false c.ReservedAttributes = false
}) })
@ -1909,7 +1909,7 @@ func TestBlockchain_Bug1728(t *testing.T) {
func TestBlockchain_ResetStateErrors(t *testing.T) { func TestBlockchain_ResetStateErrors(t *testing.T) {
chainHeight := 3 chainHeight := 3
checkResetErr := func(t *testing.T, cfg func(c *config.ProtocolConfiguration), h uint32, errText string) { checkResetErr := func(t *testing.T, cfg func(c *config.Blockchain), h uint32, errText string) {
db, path := newLevelDBForTestingWithPath(t, t.TempDir()) db, path := newLevelDBForTestingWithPath(t, t.TempDir())
bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, cfg, db, false) bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, cfg, db, false)
e := neotest.NewExecutor(t, bc, validators, committee) e := neotest.NewExecutor(t, bc, validators, committee)
@ -1937,13 +1937,13 @@ func TestBlockchain_ResetStateErrors(t *testing.T) {
checkResetErr(t, nil, uint32(chainHeight), "") checkResetErr(t, nil, uint32(chainHeight), "")
}) })
t.Run("KeepOnlyLatestState is enabled", func(t *testing.T) { t.Run("KeepOnlyLatestState is enabled", func(t *testing.T) {
checkResetErr(t, func(c *config.ProtocolConfiguration) { checkResetErr(t, func(c *config.Blockchain) {
c.KeepOnlyLatestState = true c.Ledger.KeepOnlyLatestState = true
}, uint32(chainHeight-1), "KeepOnlyLatestState is enabled") }, uint32(chainHeight-1), "KeepOnlyLatestState is enabled")
}) })
t.Run("some blocks where removed", func(t *testing.T) { t.Run("some blocks where removed", func(t *testing.T) {
checkResetErr(t, func(c *config.ProtocolConfiguration) { checkResetErr(t, func(c *config.Blockchain) {
c.RemoveUntraceableBlocks = true c.Ledger.RemoveUntraceableBlocks = true
c.MaxTraceableBlocks = 2 c.MaxTraceableBlocks = 2
}, uint32(chainHeight-3), "RemoveUntraceableBlocks is enabled, a necessary batch of traceable blocks has already been removed") }, uint32(chainHeight-3), "RemoveUntraceableBlocks is enabled, a necessary batch of traceable blocks has already been removed")
}) })
@ -1954,7 +1954,7 @@ func TestBlockchain_ResetStateErrors(t *testing.T) {
func TestBlockchain_ResetState(t *testing.T) { func TestBlockchain_ResetState(t *testing.T) {
// Create the DB. // Create the DB.
db, path := newLevelDBForTestingWithPath(t, t.TempDir()) db, path := newLevelDBForTestingWithPath(t, t.TempDir())
bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, func(cfg *config.ProtocolConfiguration) { bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, func(cfg *config.Blockchain) {
cfg.P2PSigExtensions = true cfg.P2PSigExtensions = true
}, db, false) }, db, false)
go bc.Run() go bc.Run()
@ -2025,7 +2025,7 @@ func TestBlockchain_ResetState(t *testing.T) {
// Start new chain with existing DB, but do not run it. // Start new chain with existing DB, but do not run it.
db, _ = newLevelDBForTestingWithPath(t, path) db, _ = newLevelDBForTestingWithPath(t, path)
bc, _, _ = chain.NewMultiWithCustomConfigAndStore(t, func(cfg *config.ProtocolConfiguration) { bc, _, _ = chain.NewMultiWithCustomConfigAndStore(t, func(cfg *config.Blockchain) {
cfg.P2PSigExtensions = true cfg.P2PSigExtensions = true
}, db, false) }, db, false)
defer db.Close() defer db.Close()

View file

@ -13,7 +13,7 @@ import (
type DumperRestorer interface { type DumperRestorer interface {
AddBlock(block *block.Block) error AddBlock(block *block.Block) error
GetBlock(hash util.Uint256) (*block.Block, error) GetBlock(hash util.Uint256) (*block.Block, error)
GetConfig() config.ProtocolConfiguration GetConfig() config.Blockchain
GetHeaderHash(uint32) util.Uint256 GetHeaderHash(uint32) util.Uint256
} }

View file

@ -16,30 +16,30 @@ import (
func TestBlockchain_DumpAndRestore(t *testing.T) { func TestBlockchain_DumpAndRestore(t *testing.T) {
t.Run("no state root", func(t *testing.T) { t.Run("no state root", func(t *testing.T) {
testDumpAndRestore(t, func(c *config.ProtocolConfiguration) { testDumpAndRestore(t, func(c *config.Blockchain) {
c.StateRootInHeader = false c.StateRootInHeader = false
c.P2PSigExtensions = true c.P2PSigExtensions = true
}, nil) }, nil)
}) })
t.Run("with state root", func(t *testing.T) { t.Run("with state root", func(t *testing.T) {
testDumpAndRestore(t, func(c *config.ProtocolConfiguration) { testDumpAndRestore(t, func(c *config.Blockchain) {
c.StateRootInHeader = true c.StateRootInHeader = true
c.P2PSigExtensions = true c.P2PSigExtensions = true
}, nil) }, nil)
}) })
t.Run("remove untraceable", func(t *testing.T) { t.Run("remove untraceable", func(t *testing.T) {
// Dump can only be created if all blocks and transactions are present. // Dump can only be created if all blocks and transactions are present.
testDumpAndRestore(t, func(c *config.ProtocolConfiguration) { testDumpAndRestore(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true c.P2PSigExtensions = true
}, func(c *config.ProtocolConfiguration) { }, func(c *config.Blockchain) {
c.MaxTraceableBlocks = 2 c.MaxTraceableBlocks = 2
c.RemoveUntraceableBlocks = true c.Ledger.RemoveUntraceableBlocks = true
c.P2PSigExtensions = true c.P2PSigExtensions = true
}) })
}) })
} }
func testDumpAndRestore(t *testing.T, dumpF, restoreF func(c *config.ProtocolConfiguration)) { func testDumpAndRestore(t *testing.T, dumpF, restoreF func(c *config.Blockchain)) {
if restoreF == nil { if restoreF == nil {
restoreF = dumpF restoreF = dumpF
} }

View file

@ -52,7 +52,7 @@ func initTestChainNoCheck(t testing.TB, st storage.Store, f func(*config.Config)
if _, ok := t.(*testing.B); ok { if _, ok := t.(*testing.B); ok {
log = zap.NewNop() log = zap.NewNop()
} }
return NewBlockchain(st, unitTestNetCfg.ProtocolConfiguration, log) return NewBlockchain(st, unitTestNetCfg.Blockchain(), log)
} }
func (bc *Blockchain) newBlock(txs ...*transaction.Transaction) *block.Block { func (bc *Blockchain) newBlock(txs ...*transaction.Transaction) *block.Block {
@ -69,9 +69,9 @@ func (bc *Blockchain) newBlock(txs ...*transaction.Transaction) *block.Block {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return newBlockWithState(bc.config, lastBlock.Index+1, lastBlock.Hash(), &sr.Root, txs...) return newBlockWithState(bc.config.ProtocolConfiguration, lastBlock.Index+1, lastBlock.Hash(), &sr.Root, txs...)
} }
return newBlock(bc.config, lastBlock.Index+1, lastBlock.Hash(), txs...) return newBlock(bc.config.ProtocolConfiguration, lastBlock.Index+1, lastBlock.Hash(), txs...)
} }
func newBlock(cfg config.ProtocolConfiguration, index uint32, prev util.Uint256, txs ...*transaction.Transaction) *block.Block { func newBlock(cfg config.ProtocolConfiguration, index uint32, prev util.Uint256, txs ...*transaction.Transaction) *block.Block {
@ -118,7 +118,7 @@ func (bc *Blockchain) genBlocks(n int) ([]*block.Block, error) {
lastHash := bc.topBlock.Load().(*block.Block).Hash() lastHash := bc.topBlock.Load().(*block.Block).Hash()
lastIndex := bc.topBlock.Load().(*block.Block).Index lastIndex := bc.topBlock.Load().(*block.Block).Index
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
blocks[i] = newBlock(bc.config, uint32(i)+lastIndex+1, lastHash) blocks[i] = newBlock(bc.config.ProtocolConfiguration, uint32(i)+lastIndex+1, lastHash)
if err := bc.AddBlock(blocks[i]); err != nil { if err := bc.AddBlock(blocks[i]); err != nil {
return blocks, err return blocks, err
} }

View file

@ -39,7 +39,7 @@ type Ledger interface {
BlockHeight() uint32 BlockHeight() uint32
CurrentBlockHash() util.Uint256 CurrentBlockHash() util.Uint256
GetBlock(hash util.Uint256) (*block.Block, error) GetBlock(hash util.Uint256) (*block.Block, error)
GetConfig() config.ProtocolConfiguration GetConfig() config.Blockchain
GetHeaderHash(uint32) util.Uint256 GetHeaderHash(uint32) util.Uint256
} }
@ -75,7 +75,7 @@ func NewContext(trigger trigger.Type, bc Ledger, d *dao.Simple, baseExecFee, bas
loadTokenFunc func(ic *Context, id int32) error, loadTokenFunc func(ic *Context, id int32) error,
block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context { block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context {
dao := d.GetPrivate() dao := d.GetPrivate()
cfg := bc.GetConfig() cfg := bc.GetConfig().ProtocolConfiguration
return &Context{ return &Context{
Chain: bc, Chain: bc,
Network: uint32(cfg.Magic), Network: uint32(cfg.Magic),

View file

@ -118,7 +118,7 @@ func TestCreateMultisigAccount(t *testing.T) {
} }
func TestCreateAccount_Hardfork(t *testing.T) { func TestCreateAccount_Hardfork(t *testing.T) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true // `basicchain.Init` requires Notary enabled c.P2PSigExtensions = true // `basicchain.Init` requires Notary enabled
c.Hardforks = map[string]uint32{ c.Hardforks = map[string]uint32{
config.HFAspidochelone.String(): 2, config.HFAspidochelone.String(): 2,

View file

@ -90,7 +90,7 @@ func TestNativeContract_InvokeInternal(t *testing.T) {
}) })
t.Run("fail, bad NativeUpdateHistory height", func(t *testing.T) { t.Run("fail, bad NativeUpdateHistory height", func(t *testing.T) {
bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.NativeUpdateHistories = map[string][]uint32{ c.NativeUpdateHistories = map[string][]uint32{
nativenames.Policy: {0}, nativenames.Policy: {0},
nativenames.Neo: {0}, nativenames.Neo: {0},

View file

@ -22,7 +22,7 @@ func TestManagement_GetNEP17Contracts(t *testing.T) {
}) })
t.Run("basic chain", func(t *testing.T) { t.Run("basic chain", func(t *testing.T) {
bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true // `basicchain.Init` requires Notary enabled c.P2PSigExtensions = true // `basicchain.Init` requires Notary enabled
}) })
e := neotest.NewExecutor(t, bc, validators, committee) e := neotest.NewExecutor(t, bc, validators, committee)

View file

@ -65,7 +65,7 @@ func TestGAS_RewardWithP2PSigExtensionsEnabled(t *testing.T) {
nKeys = 4 nKeys = 4
) )
bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(cfg *config.ProtocolConfiguration) { bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(cfg *config.Blockchain) {
cfg.P2PSigExtensions = true cfg.P2PSigExtensions = true
}) })
e := neotest.NewExecutor(t, bc, validator, committee) e := neotest.NewExecutor(t, bc, validator, committee)

View file

@ -20,7 +20,7 @@ import (
) )
func newLedgerClient(t *testing.T) *neotest.ContractInvoker { func newLedgerClient(t *testing.T) *neotest.ContractInvoker {
bc, acc := chain.NewSingleWithCustomConfig(t, func(cfg *config.ProtocolConfiguration) { bc, acc := chain.NewSingleWithCustomConfig(t, func(cfg *config.Blockchain) {
cfg.MaxTraceableBlocks = 10 // reduce number of traceable blocks for Ledger tests cfg.MaxTraceableBlocks = 10 // reduce number of traceable blocks for Ledger tests
}) })
e := neotest.NewExecutor(t, bc, acc, acc) e := neotest.NewExecutor(t, bc, acc, acc)

View file

@ -19,7 +19,7 @@ import (
) )
func newNotaryClient(t *testing.T) *neotest.ContractInvoker { func newNotaryClient(t *testing.T) *neotest.ContractInvoker {
bc, acc := chain.NewSingleWithCustomConfig(t, func(cfg *config.ProtocolConfiguration) { bc, acc := chain.NewSingleWithCustomConfig(t, func(cfg *config.Blockchain) {
cfg.P2PSigExtensions = true cfg.P2PSigExtensions = true
}) })
e := neotest.NewExecutor(t, bc, acc, acc) e := neotest.NewExecutor(t, bc, acc, acc)

View file

@ -55,12 +55,12 @@ type (
) )
// NewModule returns new instance of stateroot module. // NewModule returns new instance of stateroot module.
func NewModule(cfg config.ProtocolConfiguration, verif VerifierFunc, log *zap.Logger, s *storage.MemCachedStore) *Module { func NewModule(cfg config.Blockchain, verif VerifierFunc, log *zap.Logger, s *storage.MemCachedStore) *Module {
var mode mpt.TrieMode var mode mpt.TrieMode
if cfg.KeepOnlyLatestState { if cfg.Ledger.KeepOnlyLatestState {
mode |= mpt.ModeLatest mode |= mpt.ModeLatest
} }
if cfg.RemoveUntraceableBlocks { if cfg.Ledger.RemoveUntraceableBlocks {
mode |= mpt.ModeGC mode |= mpt.ModeGC
} }
return &Module{ return &Module{

View file

@ -64,7 +64,7 @@ const (
type Ledger interface { type Ledger interface {
AddHeaders(...*block.Header) error AddHeaders(...*block.Header) error
BlockHeight() uint32 BlockHeight() uint32
GetConfig() config.ProtocolConfiguration GetConfig() config.Blockchain
GetHeader(hash util.Uint256) (*block.Header, error) GetHeader(hash util.Uint256) (*block.Header, error)
GetHeaderHash(uint32) util.Uint256 GetHeaderHash(uint32) util.Uint256
HeaderHeight() uint32 HeaderHeight() uint32
@ -97,7 +97,7 @@ type Module struct {
// NewModule returns new instance of statesync module. // NewModule returns new instance of statesync module.
func NewModule(bc Ledger, stateMod *stateroot.Module, log *zap.Logger, s *dao.Simple, jumpCallback func(p uint32) error) *Module { func NewModule(bc Ledger, stateMod *stateroot.Module, log *zap.Logger, s *dao.Simple, jumpCallback func(p uint32) error) *Module {
if !(bc.GetConfig().P2PStateExchangeExtensions && bc.GetConfig().RemoveUntraceableBlocks) { if !(bc.GetConfig().P2PStateExchangeExtensions && bc.GetConfig().Ledger.RemoveUntraceableBlocks) {
return &Module{ return &Module{
dao: s, dao: s,
bc: bc, bc: bc,
@ -220,7 +220,7 @@ func (s *Module) defineSyncStage() error {
} }
var mode mpt.TrieMode var mode mpt.TrieMode
// No need to enable GC here, it only has latest things. // No need to enable GC here, it only has latest things.
if s.bc.GetConfig().KeepOnlyLatestState || s.bc.GetConfig().RemoveUntraceableBlocks { if s.bc.GetConfig().Ledger.KeepOnlyLatestState || s.bc.GetConfig().Ledger.RemoveUntraceableBlocks {
mode |= mpt.ModeLatest mode |= mpt.ModeLatest
} }
s.billet = mpt.NewBillet(header.PrevStateRoot, mode, s.billet = mpt.NewBillet(header.PrevStateRoot, mode,
@ -323,7 +323,7 @@ func (s *Module) AddBlock(block *block.Block) error {
if s.bc.GetConfig().StateRootInHeader != block.StateRootEnabled { if s.bc.GetConfig().StateRootInHeader != block.StateRootEnabled {
return fmt.Errorf("stateroot setting mismatch: %v != %v", s.bc.GetConfig().StateRootInHeader, block.StateRootEnabled) return fmt.Errorf("stateroot setting mismatch: %v != %v", s.bc.GetConfig().StateRootInHeader, block.StateRootEnabled)
} }
if s.bc.GetConfig().VerifyBlocks { if s.bc.GetConfig().Ledger.VerifyBlocks {
merkle := block.ComputeMerkleRoot() merkle := block.ComputeMerkleRoot()
if !block.MerkleRoot.Equals(merkle) { if !block.MerkleRoot.Equals(merkle) {
return errors.New("invalid block: MerkleRoot mismatch") return errors.New("invalid block: MerkleRoot mismatch")
@ -492,7 +492,7 @@ func (s *Module) Traverse(root util.Uint256, process func(node mpt.Node, nodeByt
var mode mpt.TrieMode var mode mpt.TrieMode
// GC must be turned off here to allow access to the archived nodes. // GC must be turned off here to allow access to the archived nodes.
if s.bc.GetConfig().KeepOnlyLatestState || s.bc.GetConfig().RemoveUntraceableBlocks { if s.bc.GetConfig().Ledger.KeepOnlyLatestState || s.bc.GetConfig().Ledger.RemoveUntraceableBlocks {
mode |= mpt.ModeLatest mode |= mpt.ModeLatest
} }
b := mpt.NewBillet(root, mode, 0, storage.NewMemCachedStore(s.dao.Store)) b := mpt.NewBillet(root, mode, 0, storage.NewMemCachedStore(s.dao.Store))

View file

@ -20,7 +20,7 @@ func TestStateSyncModule_Init(t *testing.T) {
stateSyncInterval = 2 stateSyncInterval = 2
maxTraceable = 3 maxTraceable = 3
) )
spoutCfg := func(c *config.ProtocolConfiguration) { spoutCfg := func(c *config.Blockchain) {
c.StateRootInHeader = true c.StateRootInHeader = true
c.P2PStateExchangeExtensions = true c.P2PStateExchangeExtensions = true
c.StateSyncInterval = stateSyncInterval c.StateSyncInterval = stateSyncInterval
@ -32,15 +32,15 @@ func TestStateSyncModule_Init(t *testing.T) {
e.AddNewBlock(t) e.AddNewBlock(t)
} }
boltCfg := func(c *config.ProtocolConfiguration) { boltCfg := func(c *config.Blockchain) {
spoutCfg(c) spoutCfg(c)
c.KeepOnlyLatestState = true c.Ledger.KeepOnlyLatestState = true
c.RemoveUntraceableBlocks = true c.Ledger.RemoveUntraceableBlocks = true
} }
t.Run("error: module disabled by config", func(t *testing.T) { t.Run("error: module disabled by config", func(t *testing.T) {
bcBolt, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bcBolt, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
boltCfg(c) boltCfg(c)
c.RemoveUntraceableBlocks = false c.Ledger.RemoveUntraceableBlocks = false
}) })
module := bcBolt.GetStateSyncModule() module := bcBolt.GetStateSyncModule()
require.Error(t, module.Init(bcSpout.BlockHeight())) // module inactive (non-archival node) require.Error(t, module.Init(bcSpout.BlockHeight())) // module inactive (non-archival node)
@ -288,9 +288,9 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
maxTraceable = 6 maxTraceable = 6
stateSyncPoint = 24 stateSyncPoint = 24
) )
spoutCfg := func(c *config.ProtocolConfiguration) { spoutCfg := func(c *config.Blockchain) {
c.KeepOnlyLatestState = spoutEnableGC c.Ledger.KeepOnlyLatestState = spoutEnableGC
c.RemoveUntraceableBlocks = spoutEnableGC c.Ledger.RemoveUntraceableBlocks = spoutEnableGC
c.StateRootInHeader = true c.StateRootInHeader = true
c.P2PStateExchangeExtensions = true c.P2PStateExchangeExtensions = true
c.StateSyncInterval = stateSyncInterval c.StateSyncInterval = stateSyncInterval
@ -309,10 +309,10 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
e.AddNewBlock(t) e.AddNewBlock(t)
require.Equal(t, stateSyncPoint+2, int(bcSpout.BlockHeight())) require.Equal(t, stateSyncPoint+2, int(bcSpout.BlockHeight()))
boltCfg := func(c *config.ProtocolConfiguration) { boltCfg := func(c *config.Blockchain) {
spoutCfg(c) spoutCfg(c)
c.KeepOnlyLatestState = true c.Ledger.KeepOnlyLatestState = true
c.RemoveUntraceableBlocks = true c.Ledger.RemoveUntraceableBlocks = true
} }
bcBoltStore := storage.NewMemoryStore() bcBoltStore := storage.NewMemoryStore()
bcBolt, _, _ := chain.NewMultiWithCustomConfigAndStore(t, boltCfg, bcBoltStore, false) bcBolt, _, _ := chain.NewMultiWithCustomConfigAndStore(t, boltCfg, bcBoltStore, false)

View file

@ -128,7 +128,7 @@ func NewSingle(t testing.TB) (*core.Blockchain, neotest.Signer) {
// NewSingleWithCustomConfig is similar to NewSingle, but allows to override the // NewSingleWithCustomConfig is similar to NewSingle, but allows to override the
// default configuration. // default configuration.
func NewSingleWithCustomConfig(t testing.TB, f func(*config.ProtocolConfiguration)) (*core.Blockchain, neotest.Signer) { func NewSingleWithCustomConfig(t testing.TB, f func(*config.Blockchain)) (*core.Blockchain, neotest.Signer) {
return NewSingleWithCustomConfigAndStore(t, f, nil, true) return NewSingleWithCustomConfigAndStore(t, f, nil, true)
} }
@ -137,24 +137,29 @@ func NewSingleWithCustomConfig(t testing.TB, f func(*config.ProtocolConfiguratio
// Run method is called on the Blockchain instance. If not, it is its caller's // Run method is called on the Blockchain instance. If not, it is its caller's
// responsibility to do that before using the chain and // responsibility to do that before using the chain and
// to properly Close the chain when done. // to properly Close the chain when done.
func NewSingleWithCustomConfigAndStore(t testing.TB, f func(cfg *config.ProtocolConfiguration), st storage.Store, run bool) (*core.Blockchain, neotest.Signer) { func NewSingleWithCustomConfigAndStore(t testing.TB, f func(cfg *config.Blockchain), st storage.Store, run bool) (*core.Blockchain, neotest.Signer) {
protoCfg := config.ProtocolConfiguration{ var cfg = config.Blockchain{
Magic: netmode.UnitTestNet, ProtocolConfiguration: config.ProtocolConfiguration{
MaxTraceableBlocks: MaxTraceableBlocks, Magic: netmode.UnitTestNet,
TimePerBlock: TimePerBlock, MaxTraceableBlocks: MaxTraceableBlocks,
StandbyCommittee: []string{hex.EncodeToString(committeeAcc.PublicKey().Bytes())}, TimePerBlock: TimePerBlock,
ValidatorsCount: 1, StandbyCommittee: []string{hex.EncodeToString(committeeAcc.PublicKey().Bytes())},
VerifyBlocks: true, ValidatorsCount: 1,
VerifyTransactions: true, VerifyTransactions: true,
},
Ledger: config.Ledger{
VerifyBlocks: true,
},
} }
if f != nil { if f != nil {
f(&protoCfg) f(&cfg)
} }
if st == nil { if st == nil {
st = storage.NewMemoryStore() st = storage.NewMemoryStore()
} }
log := zaptest.NewLogger(t) log := zaptest.NewLogger(t)
bc, err := core.NewBlockchain(st, protoCfg, log) bc, err := core.NewBlockchain(st, cfg, log)
require.NoError(t, err) require.NoError(t, err)
if run { if run {
go bc.Run() go bc.Run()
@ -172,7 +177,7 @@ func NewMulti(t testing.TB) (*core.Blockchain, neotest.Signer, neotest.Signer) {
// NewMultiWithCustomConfig is similar to NewMulti, except it allows to override the // NewMultiWithCustomConfig is similar to NewMulti, except it allows to override the
// default configuration. // default configuration.
func NewMultiWithCustomConfig(t testing.TB, f func(*config.ProtocolConfiguration)) (*core.Blockchain, neotest.Signer, neotest.Signer) { func NewMultiWithCustomConfig(t testing.TB, f func(*config.Blockchain)) (*core.Blockchain, neotest.Signer, neotest.Signer) {
return NewMultiWithCustomConfigAndStore(t, f, nil, true) return NewMultiWithCustomConfigAndStore(t, f, nil, true)
} }
@ -181,7 +186,7 @@ func NewMultiWithCustomConfig(t testing.TB, f func(*config.ProtocolConfiguration
// Run method is called on the Blockchain instance. If not, it is its caller's // Run method is called on the Blockchain instance. If not, it is its caller's
// responsibility to do that before using the chain and // responsibility to do that before using the chain and
// to properly Close the chain when done. // to properly Close the chain when done.
func NewMultiWithCustomConfigAndStore(t testing.TB, f func(*config.ProtocolConfiguration), st storage.Store, run bool) (*core.Blockchain, neotest.Signer, neotest.Signer) { func NewMultiWithCustomConfigAndStore(t testing.TB, f func(*config.Blockchain), st storage.Store, run bool) (*core.Blockchain, neotest.Signer, neotest.Signer) {
bc, validator, committee, err := NewMultiWithCustomConfigAndStoreNoCheck(t, f, st) bc, validator, committee, err := NewMultiWithCustomConfigAndStoreNoCheck(t, f, st)
require.NoError(t, err) require.NoError(t, err)
if run { if run {
@ -193,24 +198,28 @@ func NewMultiWithCustomConfigAndStore(t testing.TB, f func(*config.ProtocolConfi
// NewMultiWithCustomConfigAndStoreNoCheck is similar to NewMultiWithCustomConfig, // NewMultiWithCustomConfigAndStoreNoCheck is similar to NewMultiWithCustomConfig,
// but do not perform Blockchain run and do not check Blockchain constructor error. // but do not perform Blockchain run and do not check Blockchain constructor error.
func NewMultiWithCustomConfigAndStoreNoCheck(t testing.TB, f func(*config.ProtocolConfiguration), st storage.Store) (*core.Blockchain, neotest.Signer, neotest.Signer, error) { func NewMultiWithCustomConfigAndStoreNoCheck(t testing.TB, f func(*config.Blockchain), st storage.Store) (*core.Blockchain, neotest.Signer, neotest.Signer, error) {
protoCfg := config.ProtocolConfiguration{ var cfg = config.Blockchain{
Magic: netmode.UnitTestNet, ProtocolConfiguration: config.ProtocolConfiguration{
MaxTraceableBlocks: MaxTraceableBlocks, Magic: netmode.UnitTestNet,
TimePerBlock: TimePerBlock, MaxTraceableBlocks: MaxTraceableBlocks,
StandbyCommittee: standByCommittee, TimePerBlock: TimePerBlock,
ValidatorsCount: 4, StandbyCommittee: standByCommittee,
VerifyBlocks: true, ValidatorsCount: 4,
VerifyTransactions: true, VerifyTransactions: true,
},
Ledger: config.Ledger{
VerifyBlocks: true,
},
} }
if f != nil { if f != nil {
f(&protoCfg) f(&cfg)
} }
if st == nil { if st == nil {
st = storage.NewMemoryStore() st = storage.NewMemoryStore()
} }
log := zaptest.NewLogger(t) log := zaptest.NewLogger(t)
bc, err := core.NewBlockchain(st, protoCfg, log) bc, err := core.NewBlockchain(st, cfg, log)
return bc, neotest.NewMultiSigner(multiValidatorAcc...), neotest.NewMultiSigner(multiCommitteeAcc...), err return bc, neotest.NewMultiSigner(multiValidatorAcc...), neotest.NewMultiSigner(multiCommitteeAcc...), err
} }

View file

@ -207,7 +207,7 @@ func newTestServer(t *testing.T, serverConfig ServerConfig) *Server {
return newTestServerWithCustomCfg(t, serverConfig, nil) return newTestServerWithCustomCfg(t, serverConfig, nil)
} }
func newTestServerWithCustomCfg(t *testing.T, serverConfig ServerConfig, protocolCfg func(*config.ProtocolConfiguration)) *Server { func newTestServerWithCustomCfg(t *testing.T, serverConfig ServerConfig, protocolCfg func(*config.Blockchain)) *Server {
if len(serverConfig.Addresses) == 0 { if len(serverConfig.Addresses) == 0 {
// Normally it will be done by ApplicationConfiguration.GetAddresses(). // Normally it will be done by ApplicationConfiguration.GetAddresses().
serverConfig.Addresses = []config.AnnounceableAddress{{Address: ":0"}} serverConfig.Addresses = []config.AnnounceableAddress{{Address: ":0"}}

View file

@ -59,7 +59,7 @@ type (
mempool.Feer mempool.Feer
Blockqueuer Blockqueuer
GetBlock(hash util.Uint256) (*block.Block, error) GetBlock(hash util.Uint256) (*block.Block, error)
GetConfig() config.ProtocolConfiguration GetConfig() config.Blockchain
GetHeader(hash util.Uint256) (*block.Header, error) GetHeader(hash util.Uint256) (*block.Header, error)
GetHeaderHash(uint32) util.Uint256 GetHeaderHash(uint32) util.Uint256
GetMaxVerificationGAS() int64 GetMaxVerificationGAS() int64
@ -177,7 +177,7 @@ func newServerFromConstructors(config ServerConfig, chain Ledger, stSync StateSy
ServerConfig: config, ServerConfig: config,
chain: chain, chain: chain,
id: randomID(), id: randomID(),
config: chain.GetConfig(), config: chain.GetConfig().ProtocolConfiguration,
quit: make(chan struct{}), quit: make(chan struct{}),
relayFin: make(chan struct{}), relayFin: make(chan struct{}),
register: make(chan Peer), register: make(chan Peer),

View file

@ -56,10 +56,11 @@ func (f *fakeConsensus) OnTransaction(tx *transaction.Transaction) {
func (f *fakeConsensus) GetPayload(h util.Uint256) *payload.Extensible { panic("implement me") } func (f *fakeConsensus) GetPayload(h util.Uint256) *payload.Extensible { panic("implement me") }
func TestNewServer(t *testing.T) { func TestNewServer(t *testing.T) {
bc := &fakechain.FakeChain{ProtocolConfiguration: config.ProtocolConfiguration{ bc := &fakechain.FakeChain{Blockchain: config.Blockchain{
P2PStateExchangeExtensions: true, ProtocolConfiguration: config.ProtocolConfiguration{
StateRootInHeader: true, P2PStateExchangeExtensions: true,
}} StateRootInHeader: true,
}}}
s, err := newServerFromConstructors(ServerConfig{}, bc, new(fakechain.FakeStateSync), nil, newFakeTransp, newTestDiscovery) s, err := newServerFromConstructors(ServerConfig{}, bc, new(fakechain.FakeStateSync), nil, newFakeTransp, newTestDiscovery)
require.Error(t, err) require.Error(t, err)
@ -387,7 +388,7 @@ func (s *Server) testHandleMessage(t *testing.T, p Peer, cmd CommandType, pl pay
return s return s
} }
func startTestServer(t *testing.T, protocolCfg ...func(*config.ProtocolConfiguration)) *Server { func startTestServer(t *testing.T, protocolCfg ...func(*config.Blockchain)) *Server {
var s *Server var s *Server
srvCfg := ServerConfig{UserAgent: "/test/"} srvCfg := ServerConfig{UserAgent: "/test/"}
if protocolCfg != nil { if protocolCfg != nil {
@ -820,15 +821,15 @@ func TestHandleGetMPTData(t *testing.T) {
require.Eventually(t, recvResponse.Load, time.Second, time.Millisecond) require.Eventually(t, recvResponse.Load, time.Second, time.Millisecond)
} }
t.Run("KeepOnlyLatestState on", func(t *testing.T) { t.Run("KeepOnlyLatestState on", func(t *testing.T) {
s := startTestServer(t, func(c *config.ProtocolConfiguration) { s := startTestServer(t, func(c *config.Blockchain) {
c.P2PStateExchangeExtensions = true c.P2PStateExchangeExtensions = true
c.KeepOnlyLatestState = true c.Ledger.KeepOnlyLatestState = true
}) })
check(t, s) check(t, s)
}) })
t.Run("good", func(t *testing.T) { t.Run("good", func(t *testing.T) {
s := startTestServer(t, func(c *config.ProtocolConfiguration) { s := startTestServer(t, func(c *config.Blockchain) {
c.P2PStateExchangeExtensions = true c.P2PStateExchangeExtensions = true
}) })
check(t, s) check(t, s)

View file

@ -70,7 +70,7 @@ func dupNotaryRequest(t *testing.T, p *payload.P2PNotaryRequest) *payload.P2PNot
} }
func TestNotary(t *testing.T) { func TestNotary(t *testing.T) {
bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true c.P2PSigExtensions = true
}) })
e := neotest.NewExecutor(t, bc, validators, committee) e := neotest.NewExecutor(t, bc, validators, committee)

View file

@ -27,7 +27,7 @@ type (
BlockHeight() uint32 BlockHeight() uint32
FeePerByte() int64 FeePerByte() int64
GetBaseExecFee() int64 GetBaseExecFee() int64
GetConfig() config.ProtocolConfiguration GetConfig() config.Blockchain
GetMaxVerificationGAS() int64 GetMaxVerificationGAS() int64
GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) (*interop.Context, error) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *block.Block) (*interop.Context, error)
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error) GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)

View file

@ -72,7 +72,7 @@ type (
GetBaseExecFee() int64 GetBaseExecFee() int64
GetBlock(hash util.Uint256) (*block.Block, error) GetBlock(hash util.Uint256) (*block.Block, error)
GetCommittee() (keys.PublicKeys, error) GetCommittee() (keys.PublicKeys, error)
GetConfig() config.ProtocolConfiguration GetConfig() config.Blockchain
GetContractScriptHash(id int32) (util.Uint160, error) GetContractScriptHash(id int32) (util.Uint160, error)
GetContractState(hash util.Uint160) *state.Contract GetContractState(hash util.Uint160) *state.Contract
GetEnrollments() ([]state.Validator, error) GetEnrollments() ([]state.Validator, error)
@ -274,7 +274,7 @@ func New(chain Ledger, conf config.RPC, coreServer *network.Server,
} }
} }
protoCfg := chain.GetConfig() protoCfg := chain.GetConfig().ProtocolConfiguration
if conf.SessionEnabled { if conf.SessionEnabled {
if conf.SessionExpirationTime <= 0 { if conf.SessionExpirationTime <= 0 {
conf.SessionExpirationTime = int(protoCfg.TimePerBlock / time.Second) conf.SessionExpirationTime = int(protoCfg.TimePerBlock / time.Second)
@ -935,7 +935,7 @@ contract_loop:
lub, ok := lastUpdated[cs.ID] lub, ok := lastUpdated[cs.ID]
if !ok { if !ok {
cfg := s.chain.GetConfig() cfg := s.chain.GetConfig()
if !cfg.P2PStateExchangeExtensions && cfg.RemoveUntraceableBlocks { if !cfg.P2PStateExchangeExtensions && cfg.Ledger.RemoveUntraceableBlocks {
return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get LastUpdatedBlock for balance of %s token: internal database inconsistency", cs.Hash.StringLE())) return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get LastUpdatedBlock for balance of %s token: internal database inconsistency", cs.Hash.StringLE()))
} }
lub = stateSyncPoint lub = stateSyncPoint
@ -1057,7 +1057,7 @@ func (s *Server) getNEP17Balances(ps params.Params) (interface{}, *neorpc.Error)
lub, ok := lastUpdated[cs.ID] lub, ok := lastUpdated[cs.ID]
if !ok { if !ok {
cfg := s.chain.GetConfig() cfg := s.chain.GetConfig()
if !cfg.P2PStateExchangeExtensions && cfg.RemoveUntraceableBlocks { if !cfg.P2PStateExchangeExtensions && cfg.Ledger.RemoveUntraceableBlocks {
return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get LastUpdatedBlock for balance of %s token: internal database inconsistency", cs.Hash.StringLE())) return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get LastUpdatedBlock for balance of %s token: internal database inconsistency", cs.Hash.StringLE()))
} }
lub = stateSyncPoint lub = stateSyncPoint
@ -1396,7 +1396,7 @@ func makeStorageKey(id int32, key []byte) []byte {
var errKeepOnlyLatestState = errors.New("'KeepOnlyLatestState' setting is enabled") var errKeepOnlyLatestState = errors.New("'KeepOnlyLatestState' setting is enabled")
func (s *Server) getProof(ps params.Params) (interface{}, *neorpc.Error) { func (s *Server) getProof(ps params.Params) (interface{}, *neorpc.Error) {
if s.chain.GetConfig().KeepOnlyLatestState { if s.chain.GetConfig().Ledger.KeepOnlyLatestState {
return nil, neorpc.NewInvalidRequestError(fmt.Sprintf("'getproof' is not supported: %s", errKeepOnlyLatestState)) return nil, neorpc.NewInvalidRequestError(fmt.Sprintf("'getproof' is not supported: %s", errKeepOnlyLatestState))
} }
root, err := ps.Value(0).GetUint256() root, err := ps.Value(0).GetUint256()
@ -1427,7 +1427,7 @@ func (s *Server) getProof(ps params.Params) (interface{}, *neorpc.Error) {
} }
func (s *Server) verifyProof(ps params.Params) (interface{}, *neorpc.Error) { func (s *Server) verifyProof(ps params.Params) (interface{}, *neorpc.Error) {
if s.chain.GetConfig().KeepOnlyLatestState { if s.chain.GetConfig().Ledger.KeepOnlyLatestState {
return nil, neorpc.NewInvalidRequestError(fmt.Sprintf("'verifyproof' is not supported: %s", errKeepOnlyLatestState)) return nil, neorpc.NewInvalidRequestError(fmt.Sprintf("'verifyproof' is not supported: %s", errKeepOnlyLatestState))
} }
root, err := ps.Value(0).GetUint256() root, err := ps.Value(0).GetUint256()
@ -1455,7 +1455,7 @@ func (s *Server) getState(ps params.Params) (interface{}, *neorpc.Error) {
if err != nil { if err != nil {
return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, "invalid stateroot") return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, "invalid stateroot")
} }
if s.chain.GetConfig().KeepOnlyLatestState { if s.chain.GetConfig().Ledger.KeepOnlyLatestState {
curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight()) curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight())
if err != nil { if err != nil {
return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get current stateroot: %s", err)) return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get current stateroot: %s", err))
@ -1489,7 +1489,7 @@ func (s *Server) findStates(ps params.Params) (interface{}, *neorpc.Error) {
if err != nil { if err != nil {
return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, "invalid stateroot") return nil, neorpc.WrapErrorWithData(neorpc.ErrInvalidParams, "invalid stateroot")
} }
if s.chain.GetConfig().KeepOnlyLatestState { if s.chain.GetConfig().Ledger.KeepOnlyLatestState {
curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight()) curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight())
if err != nil { if err != nil {
return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get current stateroot: %s", err)) return nil, neorpc.NewInternalServerError(fmt.Sprintf("failed to get current stateroot: %s", err))
@ -2041,7 +2041,7 @@ func (s *Server) getInvokeContractVerifyParams(reqParams params.Params) (util.Ui
// specified stateroot is stored at the specified height for further request // specified stateroot is stored at the specified height for further request
// handling consistency. // handling consistency.
func (s *Server) getHistoricParams(reqParams params.Params) (uint32, *neorpc.Error) { func (s *Server) getHistoricParams(reqParams params.Params) (uint32, *neorpc.Error) {
if s.chain.GetConfig().KeepOnlyLatestState { if s.chain.GetConfig().Ledger.KeepOnlyLatestState {
return 0, neorpc.NewInvalidRequestError(fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState)) return 0, neorpc.NewInvalidRequestError(fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState))
} }
if len(reqParams) < 1 { if len(reqParams) < 1 {

View file

@ -67,7 +67,7 @@ func getUnitTestChainWithCustomConfig(t testing.TB, enableOracle bool, enableNot
memoryStore := storage.NewMemoryStore() memoryStore := storage.NewMemoryStore()
logger := zaptest.NewLogger(t) logger := zaptest.NewLogger(t)
chain, err := core.NewBlockchain(memoryStore, cfg.ProtocolConfiguration, logger) chain, err := core.NewBlockchain(memoryStore, cfg.Blockchain(), logger)
require.NoError(t, err, "could not create chain") require.NoError(t, err, "could not create chain")
var orc *oracle.Oracle var orc *oracle.Oracle

View file

@ -21,7 +21,7 @@ import (
type ( type (
// Ledger is an interface to Blockchain sufficient for Service. // Ledger is an interface to Blockchain sufficient for Service.
Ledger interface { Ledger interface {
GetConfig() config.ProtocolConfiguration GetConfig() config.Blockchain
HeaderHeight() uint32 HeaderHeight() uint32
SubscribeForBlocks(ch chan *block.Block) SubscribeForBlocks(ch chan *block.Block)
UnsubscribeFromBlocks(ch chan *block.Block) UnsubscribeFromBlocks(ch chan *block.Block)

View file

@ -298,7 +298,7 @@ func checkVoteBroadcasted(t *testing.T, bc *core.Blockchain, p *payload.Extensib
} }
func TestStateroot_GetLatestStateHeight(t *testing.T) { func TestStateroot_GetLatestStateHeight(t *testing.T) {
bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) { bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true c.P2PSigExtensions = true
}) })
e := neotest.NewExecutor(t, bc, validators, committee) e := neotest.NewExecutor(t, bc, validators, committee)

View file

@ -132,14 +132,14 @@ func newChain() (*core.Blockchain, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
unitTestNetCfg.ProtocolConfiguration.VerifyBlocks = false unitTestNetCfg.ApplicationConfiguration.VerifyBlocks = false
zapCfg := zap.NewDevelopmentConfig() zapCfg := zap.NewDevelopmentConfig()
zapCfg.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel) zapCfg.Level = zap.NewAtomicLevelAt(zapcore.InfoLevel)
log, err := zapCfg.Build() log, err := zapCfg.Build()
if err != nil { if err != nil {
return nil, err return nil, err
} }
chain, err := core.NewBlockchain(storage.NewMemoryStore(), unitTestNetCfg.ProtocolConfiguration, log) chain, err := core.NewBlockchain(storage.NewMemoryStore(), unitTestNetCfg.Blockchain(), log)
if err != nil { if err != nil {
return nil, err return nil, err
} }