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
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")
if dumpDir != "" {
cfg.ProtocolConfiguration.SaveStorageBatch = true
cfg.ApplicationConfiguration.SaveStorageBatch = true
}
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
@ -384,7 +384,7 @@ func mkConsensus(config config.Consensus, tpb time.Duration, chain *core.Blockch
Logger: log,
Broadcast: serv.BroadcastExtensible,
Chain: chain,
ProtocolConfiguration: chain.GetConfig(),
ProtocolConfiguration: chain.GetConfig().ProtocolConfiguration,
RequestTx: serv.RequestTx,
StopTxFlow: serv.StopTxFlow,
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)
}
chain, err := core.NewBlockchain(store, cfg.ProtocolConfiguration, log)
chain, err := core.NewBlockchain(store, cfg.Blockchain(), log)
if err != nil {
errText := "could not initialize blockchain: %w"
errArgs := []interface{}{err}

View file

@ -468,7 +468,7 @@ func NewWithConfig(printLogotype bool, onExit func(int), c *readline.Config, cfg
onExit(i)
}
chain, err := core.NewBlockchain(store, cfg.ProtocolConfiguration, fLog)
chain, err := core.NewBlockchain(store, cfg.Blockchain(), fLog)
if err != nil {
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)
require.NoError(t, err)
customConfig := func(c *config.ProtocolConfiguration) {
customConfig := func(c *config.Blockchain) {
c.StateRootInHeader = true // Need for P2PStateExchangeExtensions check.
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. |
| ExtensiblePoolSize | `int` | `20` | Maximum amount of the extensible payloads from a single sender stored in a local pool. Warning: this field is deprecated and moved to `P2P` section. |
| LogLevel | `string` | "info" | Minimal logged messages level (can be "debug", "info", "warn", "error", "dpanic", "panic" or "fatal"). |
| GarbageCollectionPeriod | `uint32` | 10000 | Controls MPT garbage collection interval (in blocks) for configurations with `RemoveUntraceableBlocks` enabled and `KeepOnlyLatestState` disabled. In this mode the node stores a number of MPT trees (corresponding to `MaxTraceableBlocks` and `StateSyncInterval`), but the DB needs to be clean from old entries from time to time. Doing it too often will cause too much processing overhead, doing it too rarely will leave more useless data in the DB. |
| KeepOnlyLatestState | `bool` | `false` | Specifies if MPT should only store the latest state (or a set of latest states, see `P2PStateExchangeExtensions` section in the ProtocolConfiguration for details). If true, DB size will be smaller, but older roots won't be accessible. This value should remain the same for the same database. | |
| LogPath | `string` | "", so only console logging | File path where to store node logs. |
| MaxPeers | `int` | `100` | Maximum numbers of peers that can be connected to the server. Warning: this field is deprecated and moved to `P2P` section. |
| MinPeers | `int` | `5` | Minimum number of peers for normal operation; when the node has less than this number of peers it tries to connect with some new ones. Warning: this field is deprecated and moved to `P2P` section. |
@ -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. |
| Relay | `bool` | `true` | Determines whether the server is forwarding its inventory. |
| Consensus | [Consensus Configuration](#Consensus-Configuration) | | Describes consensus (dBFT) configuration. See the [Consensus Configuration](#Consensus-Configuration) for details. |
| RemoveUntraceableBlocks | `bool`| `false` | Denotes whether old blocks should be removed from cache and database. If enabled, then only the last `MaxTraceableBlocks` are stored and accessible to smart contracts. Old MPT data is also deleted in accordance with `GarbageCollectionPeriod` setting. If enabled along with `P2PStateExchangeExtensions` protocol extension, then old blocks and MPT states will be removed up to the second latest state synchronisation point (see `StateSyncInterval`). |
| 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. |
| 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
@ -335,9 +340,9 @@ protocol-related settings described in the table below.
| 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. |
| 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. |
| 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. |
| MaxBlockSize | `uint32` | `262144` | Maximum block size in bytes. |
| 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. |
| 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`). |
| 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. |
| 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. |
| SeedList | `[]string` | [] | List of initial nodes addresses used to establish connectivity. |
| 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. |
| 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. |
| 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. |

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.
// Set `saveState` flag to true and run the test to rewrite NEF and manifest files.
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
})
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.
type FakeChain struct {
config.ProtocolConfiguration
config.Blockchain
*mempool.Pool
blocksCh []chan *block.Block
Blockheight uint32
@ -56,19 +56,19 @@ func NewFakeChain() *FakeChain {
}
// NewFakeChainWithCustomCfg returns a new FakeChain structure with the specified protocol configuration.
func NewFakeChainWithCustomCfg(protocolCfg func(c *config.ProtocolConfiguration)) *FakeChain {
cfg := config.ProtocolConfiguration{Magic: netmode.UnitTestNet, P2PNotaryRequestPayloadPoolSize: 10}
func NewFakeChainWithCustomCfg(protocolCfg func(c *config.Blockchain)) *FakeChain {
cfg := config.Blockchain{ProtocolConfiguration: config.ProtocolConfiguration{Magic: netmode.UnitTestNet, P2PNotaryRequestPayloadPoolSize: 10}}
if protocolCfg != nil {
protocolCfg(&cfg)
}
return &FakeChain{
Pool: mempool.New(10, 0, false),
PoolTxF: func(*transaction.Transaction) error { return nil },
poolTxWithData: func(*transaction.Transaction, interface{}, *mempool.Pool) error { return nil },
blocks: make(map[util.Uint256]*block.Block),
hdrHashes: make(map[uint32]util.Uint256),
txs: make(map[util.Uint256]*transaction.Transaction),
ProtocolConfiguration: cfg,
Pool: mempool.New(10, 0, false),
PoolTxF: func(*transaction.Transaction) error { return nil },
poolTxWithData: func(*transaction.Transaction, interface{}, *mempool.Pool) error { return nil },
blocks: make(map[util.Uint256]*block.Block),
hdrHashes: make(map[uint32]util.Uint256),
txs: make(map[util.Uint256]*transaction.Transaction),
Blockchain: cfg,
}
}
@ -159,8 +159,8 @@ func (chain *FakeChain) RegisterPostBlock(f func(func(*transaction.Transaction,
}
// GetConfig implements the Blockchainer interface.
func (chain *FakeChain) GetConfig() config.ProtocolConfiguration {
return chain.ProtocolConfiguration
func (chain *FakeChain) GetConfig() config.Blockchain {
return chain.Blockchain
}
// 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()
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")
if run {
@ -155,7 +155,7 @@ func NewTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockch
Logger: zap.NewNop(),
Broadcast: netSrv.BroadcastExtensible,
Chain: chain,
ProtocolConfiguration: chain.GetConfig(),
ProtocolConfiguration: cfg.ProtocolConfiguration,
RequestTx: netSrv.RequestTx,
StopTxFlow: netSrv.StopTxFlow,
Wallet: cfg.ApplicationConfiguration.Consensus.UnlockWallet,

View file

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

View file

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

View file

@ -44,7 +44,7 @@ const nsInMs = 1000000
type Ledger interface {
AddBlock(block *coreb.Block) error
ApplyPolicyToTxSet([]*transaction.Transaction) []*transaction.Transaction
GetConfig() config.ProtocolConfiguration
GetConfig() config.Blockchain
GetMemPool() *mempool.Pool
GetNextBlockValidators() ([]*keys.PublicKey, 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 err error
cfg := s.Chain.GetConfig()
cfg := s.Chain.GetConfig().ProtocolConfiguration
if cfg.ShouldUpdateCommitteeAt(ctx.BlockIndex) {
validators, err = s.Chain.GetValidators()
} else {

View file

@ -50,7 +50,7 @@ func TestNewWatchingService(t *testing.T) {
Logger: zaptest.NewLogger(t),
Broadcast: func(*npayload.Extensible) {},
Chain: bc,
ProtocolConfiguration: bc.GetConfig(),
ProtocolConfiguration: bc.GetConfig().ProtocolConfiguration,
RequestTx: func(...util.Uint256) {},
StopTxFlow: func() {},
TimePerBlock: bc.GetConfig().TimePerBlock,
@ -495,7 +495,7 @@ func newTestServiceWithChain(t *testing.T, bc *core.Blockchain) *service {
Logger: zaptest.NewLogger(t),
Broadcast: func(*npayload.Extensible) {},
Chain: bc,
ProtocolConfiguration: bc.GetConfig(),
ProtocolConfiguration: bc.GetConfig().ProtocolConfiguration,
RequestTx: func(...util.Uint256) {},
StopTxFlow: func() {},
TimePerBlock: bc.GetConfig().TimePerBlock,
@ -519,7 +519,7 @@ func newSingleTestChain(t *testing.T) *core.Blockchain {
cfg, err := config.LoadFile(configPath)
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")
go chain.Run()
@ -532,7 +532,7 @@ func newTestChain(t *testing.T, stateRootInHeader bool) *core.Blockchain {
require.NoError(t, err)
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)
go chain.Run()

View file

@ -37,7 +37,7 @@ var (
func TestCreateBasicChain(t *testing.T) {
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
})
e := neotest.NewExecutor(t, bc, validators, committee)

View file

@ -116,7 +116,7 @@ var (
type Blockchain struct {
HeaderHashes
config config.ProtocolConfiguration
config config.Blockchain
// 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
@ -218,11 +218,12 @@ type transferData struct {
// NewBlockchain returns a new blockchain object the will use the
// given Store as its underlying storage. For it to work correctly you need
// 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 {
return nil, errors.New("empty logger")
}
// Protocol configuration fixups/checks.
if cfg.InitialGASSupply <= 0 {
cfg.InitialGASSupply = fixedn.Fixed8(defaultInitialGAS)
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))
}
}
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 {
cfg.NativeUpdateHistories = map[string][]uint32{}
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{}
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{
config: cfg,
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),
subCh: 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
if err := bc.init(); err != nil {
@ -370,13 +381,13 @@ func (bc *Blockchain) init() error {
StateRootInHeader: bc.config.StateRootInHeader,
P2PSigExtensions: bc.config.P2PSigExtensions,
P2PStateExchangeExtensions: bc.config.P2PStateExchangeExtensions,
KeepOnlyLatestState: bc.config.KeepOnlyLatestState,
KeepOnlyLatestState: bc.config.Ledger.KeepOnlyLatestState,
Value: version,
}
bc.dao.PutVersion(ver)
bc.dao.Version = ver
bc.persistent.Version = ver
genesisBlock, err := CreateGenesisBlock(bc.config)
genesisBlock, err := CreateGenesisBlock(bc.config.ProtocolConfiguration)
if err != nil {
return err
}
@ -401,9 +412,9 @@ func (bc *Blockchain) init() error {
return fmt.Errorf("P2PStateExchangeExtensions setting mismatch (old=%t, new=%t)",
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)",
ver.KeepOnlyLatestState, bc.config.KeepOnlyLatestState)
ver.KeepOnlyLatestState, bc.config.Ledger.KeepOnlyLatestState)
}
bc.dao.Version = ver
bc.persistent.Version = ver
@ -432,7 +443,7 @@ func (bc *Blockchain) init() error {
if (stateChStage[0] & stateResetBit) != 0 {
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. " +
"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))
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)
}
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")
}
}
@ -727,7 +738,7 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
pStorageStart := p
var mode = mpt.ModeAll
if bc.config.RemoveUntraceableBlocks {
if bc.config.Ledger.RemoveUntraceableBlocks {
mode |= mpt.ModeGCFlag
}
trieStore := mpt.NewTrieStore(sr.Root, mode, cache.Store)
@ -919,14 +930,14 @@ func (bc *Blockchain) Run() {
var oldPersisted uint32
var gcDur time.Duration
if bc.config.RemoveUntraceableBlocks {
if bc.config.Ledger.RemoveUntraceableBlocks {
oldPersisted = atomic.LoadUint32(&bc.persistedHeight)
}
dur, err := bc.persist(nextSync)
if err != nil {
bc.log.Warn("failed to persist blockchain", zap.Error(err))
}
if bc.config.RemoveUntraceableBlocks {
if bc.config.Ledger.RemoveUntraceableBlocks {
gcDur = bc.tryRunGC(oldPersisted)
}
nextSync = dur > persistInterval*2
@ -955,14 +966,14 @@ func (bc *Blockchain) tryRunGC(oldHeight uint32) time.Duration {
}
}
// Always round to the GCP.
tgtBlock /= int64(bc.config.GarbageCollectionPeriod)
tgtBlock *= int64(bc.config.GarbageCollectionPeriod)
tgtBlock /= int64(bc.config.Ledger.GarbageCollectionPeriod)
tgtBlock *= int64(bc.config.Ledger.GarbageCollectionPeriod)
// Count periods.
oldHeight /= bc.config.GarbageCollectionPeriod
newHeight /= bc.config.GarbageCollectionPeriod
if tgtBlock > int64(bc.config.GarbageCollectionPeriod) && newHeight != oldHeight {
tgtBlock /= int64(bc.config.GarbageCollectionPeriod)
tgtBlock *= int64(bc.config.GarbageCollectionPeriod)
oldHeight /= bc.config.Ledger.GarbageCollectionPeriod
newHeight /= bc.config.Ledger.GarbageCollectionPeriod
if tgtBlock > int64(bc.config.Ledger.GarbageCollectionPeriod) && newHeight != oldHeight {
tgtBlock /= int64(bc.config.Ledger.GarbageCollectionPeriod)
tgtBlock *= int64(bc.config.Ledger.GarbageCollectionPeriod)
dur = bc.stateRoot.GC(uint32(tgtBlock), bc.store)
dur += bc.removeOldTransfers(uint32(tgtBlock))
}
@ -1298,12 +1309,12 @@ func (bc *Blockchain) AddBlock(block *block.Block) error {
}
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 {
return err
}
}
if bc.config.VerifyBlocks {
if bc.config.Ledger.VerifyBlocks {
merkle := block.ComputeMerkleRoot()
if !block.MerkleRoot.Equals(merkle) {
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
// HeaderHashList. It expects headers to be sorted by index.
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
@ -1415,7 +1426,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
transCache = make(map[util.Uint160]transferData)
)
kvcache.StoreAsCurrentBlock(block)
if bc.config.RemoveUntraceableBlocks {
if bc.config.Ledger.RemoveUntraceableBlocks {
var start, stop uint32
if bc.config.P2PStateExchangeExtensions {
// 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()
}
// 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 {
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 {
nBalance, lub := bc.contracts.NEO.BalanceOf(bc.dao, acc)
if nBalance.Sign() != 0 {
@ -2121,7 +2132,7 @@ func (bc *Blockchain) GetNatives() []state.NativeContract {
}
// GetConfig returns the config stored in the blockchain.
func (bc *Blockchain) GetConfig() config.ProtocolConfiguration {
func (bc *Blockchain) GetConfig() config.Blockchain {
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.
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")
}
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)
}
var mode = mpt.ModeAll
if bc.config.RemoveUntraceableBlocks {
if bc.config.Ledger.RemoveUntraceableBlocks {
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)
}

View file

@ -32,21 +32,21 @@ func TestVerifyHeader(t *testing.T) {
t.Run("Hash", func(t *testing.T) {
h := prev.Hash()
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))
})
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))
})
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
require.True(t, errors.Is(bc.verifyHeader(&hdr, &prev), ErrHdrInvalidTimestamp))
})
})
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))
})
}
@ -144,12 +144,12 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
maxTraceable uint32 = 6
)
spountCfg := func(c *config.Config) {
c.ProtocolConfiguration.RemoveUntraceableBlocks = true
c.ApplicationConfiguration.RemoveUntraceableBlocks = true
c.ProtocolConfiguration.StateRootInHeader = true
c.ProtocolConfiguration.P2PStateExchangeExtensions = true
c.ProtocolConfiguration.StateSyncInterval = stateSyncInterval
c.ProtocolConfiguration.MaxTraceableBlocks = maxTraceable
c.ProtocolConfiguration.KeepOnlyLatestState = true
c.ApplicationConfiguration.KeepOnlyLatestState = true
}
bcSpout := newTestChainWithCustomCfg(t, spountCfg)
@ -190,7 +190,7 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
require.NoError(t, err)
cfg(&unitTestNetCfg)
log := zaptest.NewLogger(t)
_, err = NewBlockchain(store, unitTestNetCfg.ProtocolConfiguration, log)
_, err = NewBlockchain(store, unitTestNetCfg.Blockchain(), log)
if len(errText) != 0 {
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), errText))
@ -200,7 +200,7 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
}
boltCfg := func(c *config.Config) {
spountCfg(c)
c.ProtocolConfiguration.KeepOnlyLatestState = true
c.ApplicationConfiguration.KeepOnlyLatestState = true
}
// manually store statejump stage to check statejump recover process
bPrefix[0] = byte(storage.SYSStateChangeStage)
@ -219,7 +219,7 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
bcSpout.dao.Store.Put([]byte{byte(storage.SYSStateSyncPoint)}, point)
checkNewBlockchainErr(t, func(c *config.Config) {
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")
})
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) {
ps, path := newLevelDBForTestingWithPath(t, "")
customConfig := func(c *config.ProtocolConfiguration) {
customConfig := func(c *config.Blockchain) {
c.StateRootInHeader = true // Need for P2PStateExchangeExtensions check.
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) {
ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.ProtocolConfiguration) {
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c)
c.StateRootInHeader = false
}, ps)
@ -115,7 +115,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
})
t.Run("mismatch P2PSigExtensions", func(t *testing.T) {
ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.ProtocolConfiguration) {
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c)
c.P2PSigExtensions = false
}, ps)
@ -124,7 +124,7 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
})
t.Run("mismatch P2PStateExchangeExtensions", func(t *testing.T) {
ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.ProtocolConfiguration) {
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c)
c.StateRootInHeader = true
c.P2PStateExchangeExtensions = true
@ -134,9 +134,9 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
})
t.Run("mismatch KeepOnlyLatestState", func(t *testing.T) {
ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.ProtocolConfiguration) {
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c)
c.KeepOnlyLatestState = true
c.Ledger.KeepOnlyLatestState = true
}, ps)
require.Error(t, 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) {
ps = newPS(t)
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.ProtocolConfiguration) {
_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
customConfig(c)
c.NativeUpdateHistories = map[string][]uint32{
nativenames.Policy: {0},
@ -291,7 +291,7 @@ func TestBlockchain_StartFromExistingDB(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
})
e := neotest.NewExecutor(t, bc, acc, acc)
@ -342,7 +342,7 @@ func TestBlockchain_AddHeaders(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
})
e := neotest.NewExecutor(t, bc, acc, acc)
@ -371,7 +371,7 @@ func TestBlockchain_AddBlockStateRoot(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
})
e := neotest.NewExecutor(t, bc, acc, acc)
@ -401,7 +401,7 @@ func TestBlockchain_AddHeadersStateRoot(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)
err := bc.AddBlock(b)
if cfg == nil {
@ -420,25 +420,25 @@ func TestBlockchain_AddBadBlock(t *testing.T) {
b := e.NewUnsignedBlock(t, tx)
e.SignBlock(b)
check(t, b, nil)
check(t, b, func(c *config.ProtocolConfiguration) {
c.VerifyBlocks = false
check(t, b, func(c *config.Blockchain) {
c.Ledger.VerifyBlocks = false
})
b = e.NewUnsignedBlock(t)
b.PrevHash = util.Uint256{} // Intentionally make block invalid.
e.SignBlock(b)
check(t, b, nil)
check(t, b, func(c *config.ProtocolConfiguration) {
c.VerifyBlocks = false
check(t, b, func(c *config.Blockchain) {
c.Ledger.VerifyBlocks = false
})
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)
b = e.NewUnsignedBlock(t, tx)
e.SignBlock(b)
check(t, b, func(c *config.ProtocolConfiguration) {
check(t, b, func(c *config.Blockchain) {
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) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.ProtocolConfiguration) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true
})
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) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.ProtocolConfiguration) {
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
c.MaxTraceableBlocks = 2
c.GarbageCollectionPeriod = 2
c.RemoveUntraceableBlocks = true
c.Ledger.GarbageCollectionPeriod = 2
c.Ledger.RemoveUntraceableBlocks = true
})
e := neotest.NewExecutor(t, bc, acc, acc)
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)
})
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.GarbageCollectionPeriod = 2
c.RemoveUntraceableBlocks = true
c.Ledger.GarbageCollectionPeriod = 2
c.Ledger.RemoveUntraceableBlocks = true
c.P2PStateExchangeExtensions = true
c.StateSyncInterval = 2
c.StateRootInHeader = true
@ -1047,7 +1047,7 @@ func TestConfigNativeUpdateHistory(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.ReservedAttributes = true
})
@ -1467,7 +1467,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
return tx
}
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.ReservedAttributes = false
})
@ -1509,7 +1509,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
return tx
}
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.ReservedAttributes = false
})
@ -1553,7 +1553,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
return tx
}
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.ReservedAttributes = false
})
@ -1649,7 +1649,7 @@ func TestBlockchain_VerifyTx(t *testing.T) {
return tx
}
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.ReservedAttributes = false
})
@ -1909,7 +1909,7 @@ func TestBlockchain_Bug1728(t *testing.T) {
func TestBlockchain_ResetStateErrors(t *testing.T) {
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())
bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, cfg, db, false)
e := neotest.NewExecutor(t, bc, validators, committee)
@ -1937,13 +1937,13 @@ func TestBlockchain_ResetStateErrors(t *testing.T) {
checkResetErr(t, nil, uint32(chainHeight), "")
})
t.Run("KeepOnlyLatestState is enabled", func(t *testing.T) {
checkResetErr(t, func(c *config.ProtocolConfiguration) {
c.KeepOnlyLatestState = true
checkResetErr(t, func(c *config.Blockchain) {
c.Ledger.KeepOnlyLatestState = true
}, uint32(chainHeight-1), "KeepOnlyLatestState is enabled")
})
t.Run("some blocks where removed", func(t *testing.T) {
checkResetErr(t, func(c *config.ProtocolConfiguration) {
c.RemoveUntraceableBlocks = true
checkResetErr(t, func(c *config.Blockchain) {
c.Ledger.RemoveUntraceableBlocks = true
c.MaxTraceableBlocks = 2
}, 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) {
// Create the DB.
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
}, db, false)
go bc.Run()
@ -2025,7 +2025,7 @@ func TestBlockchain_ResetState(t *testing.T) {
// Start new chain with existing DB, but do not run it.
db, _ = newLevelDBForTestingWithPath(t, path)
bc, _, _ = chain.NewMultiWithCustomConfigAndStore(t, func(cfg *config.ProtocolConfiguration) {
bc, _, _ = chain.NewMultiWithCustomConfigAndStore(t, func(cfg *config.Blockchain) {
cfg.P2PSigExtensions = true
}, db, false)
defer db.Close()

View file

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

View file

@ -16,30 +16,30 @@ import (
func TestBlockchain_DumpAndRestore(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.P2PSigExtensions = true
}, nil)
})
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.P2PSigExtensions = true
}, nil)
})
t.Run("remove untraceable", func(t *testing.T) {
// 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
}, func(c *config.ProtocolConfiguration) {
}, func(c *config.Blockchain) {
c.MaxTraceableBlocks = 2
c.RemoveUntraceableBlocks = true
c.Ledger.RemoveUntraceableBlocks = 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 {
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 {
log = zap.NewNop()
}
return NewBlockchain(st, unitTestNetCfg.ProtocolConfiguration, log)
return NewBlockchain(st, unitTestNetCfg.Blockchain(), log)
}
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 {
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 {
@ -118,7 +118,7 @@ func (bc *Blockchain) genBlocks(n int) ([]*block.Block, error) {
lastHash := bc.topBlock.Load().(*block.Block).Hash()
lastIndex := bc.topBlock.Load().(*block.Block).Index
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 {
return blocks, err
}

View file

@ -39,7 +39,7 @@ type Ledger interface {
BlockHeight() uint32
CurrentBlockHash() util.Uint256
GetBlock(hash util.Uint256) (*block.Block, error)
GetConfig() config.ProtocolConfiguration
GetConfig() config.Blockchain
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,
block *block.Block, tx *transaction.Transaction, log *zap.Logger) *Context {
dao := d.GetPrivate()
cfg := bc.GetConfig()
cfg := bc.GetConfig().ProtocolConfiguration
return &Context{
Chain: bc,
Network: uint32(cfg.Magic),

View file

@ -118,7 +118,7 @@ func TestCreateMultisigAccount(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.Hardforks = map[string]uint32{
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) {
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{
nativenames.Policy: {0},
nativenames.Neo: {0},

View file

@ -22,7 +22,7 @@ func TestManagement_GetNEP17Contracts(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
})
e := neotest.NewExecutor(t, bc, validators, committee)

View file

@ -65,7 +65,7 @@ func TestGAS_RewardWithP2PSigExtensionsEnabled(t *testing.T) {
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
})
e := neotest.NewExecutor(t, bc, validator, committee)

View file

@ -20,7 +20,7 @@ import (
)
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
})
e := neotest.NewExecutor(t, bc, acc, acc)

View file

@ -19,7 +19,7 @@ import (
)
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
})
e := neotest.NewExecutor(t, bc, acc, acc)

View file

@ -55,12 +55,12 @@ type (
)
// 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
if cfg.KeepOnlyLatestState {
if cfg.Ledger.KeepOnlyLatestState {
mode |= mpt.ModeLatest
}
if cfg.RemoveUntraceableBlocks {
if cfg.Ledger.RemoveUntraceableBlocks {
mode |= mpt.ModeGC
}
return &Module{

View file

@ -64,7 +64,7 @@ const (
type Ledger interface {
AddHeaders(...*block.Header) error
BlockHeight() uint32
GetConfig() config.ProtocolConfiguration
GetConfig() config.Blockchain
GetHeader(hash util.Uint256) (*block.Header, error)
GetHeaderHash(uint32) util.Uint256
HeaderHeight() uint32
@ -97,7 +97,7 @@ type Module struct {
// NewModule returns new instance of statesync module.
func NewModule(bc Ledger, stateMod *stateroot.Module, log *zap.Logger, s *dao.Simple, jumpCallback func(p uint32) error) *Module {
if !(bc.GetConfig().P2PStateExchangeExtensions && bc.GetConfig().RemoveUntraceableBlocks) {
if !(bc.GetConfig().P2PStateExchangeExtensions && bc.GetConfig().Ledger.RemoveUntraceableBlocks) {
return &Module{
dao: s,
bc: bc,
@ -220,7 +220,7 @@ func (s *Module) defineSyncStage() error {
}
var mode mpt.TrieMode
// 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
}
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 {
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()
if !block.MerkleRoot.Equals(merkle) {
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
// 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
}
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
maxTraceable = 3
)
spoutCfg := func(c *config.ProtocolConfiguration) {
spoutCfg := func(c *config.Blockchain) {
c.StateRootInHeader = true
c.P2PStateExchangeExtensions = true
c.StateSyncInterval = stateSyncInterval
@ -32,15 +32,15 @@ func TestStateSyncModule_Init(t *testing.T) {
e.AddNewBlock(t)
}
boltCfg := func(c *config.ProtocolConfiguration) {
boltCfg := func(c *config.Blockchain) {
spoutCfg(c)
c.KeepOnlyLatestState = true
c.RemoveUntraceableBlocks = true
c.Ledger.KeepOnlyLatestState = true
c.Ledger.RemoveUntraceableBlocks = true
}
t.Run("error: module disabled by config", func(t *testing.T) {
bcBolt, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) {
bcBolt, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
boltCfg(c)
c.RemoveUntraceableBlocks = false
c.Ledger.RemoveUntraceableBlocks = false
})
module := bcBolt.GetStateSyncModule()
require.Error(t, module.Init(bcSpout.BlockHeight())) // module inactive (non-archival node)
@ -288,9 +288,9 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
maxTraceable = 6
stateSyncPoint = 24
)
spoutCfg := func(c *config.ProtocolConfiguration) {
c.KeepOnlyLatestState = spoutEnableGC
c.RemoveUntraceableBlocks = spoutEnableGC
spoutCfg := func(c *config.Blockchain) {
c.Ledger.KeepOnlyLatestState = spoutEnableGC
c.Ledger.RemoveUntraceableBlocks = spoutEnableGC
c.StateRootInHeader = true
c.P2PStateExchangeExtensions = true
c.StateSyncInterval = stateSyncInterval
@ -309,10 +309,10 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
e.AddNewBlock(t)
require.Equal(t, stateSyncPoint+2, int(bcSpout.BlockHeight()))
boltCfg := func(c *config.ProtocolConfiguration) {
boltCfg := func(c *config.Blockchain) {
spoutCfg(c)
c.KeepOnlyLatestState = true
c.RemoveUntraceableBlocks = true
c.Ledger.KeepOnlyLatestState = true
c.Ledger.RemoveUntraceableBlocks = true
}
bcBoltStore := storage.NewMemoryStore()
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
// 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)
}
@ -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
// responsibility to do that before using the chain and
// 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) {
protoCfg := config.ProtocolConfiguration{
Magic: netmode.UnitTestNet,
MaxTraceableBlocks: MaxTraceableBlocks,
TimePerBlock: TimePerBlock,
StandbyCommittee: []string{hex.EncodeToString(committeeAcc.PublicKey().Bytes())},
ValidatorsCount: 1,
VerifyBlocks: true,
VerifyTransactions: true,
func NewSingleWithCustomConfigAndStore(t testing.TB, f func(cfg *config.Blockchain), st storage.Store, run bool) (*core.Blockchain, neotest.Signer) {
var cfg = config.Blockchain{
ProtocolConfiguration: config.ProtocolConfiguration{
Magic: netmode.UnitTestNet,
MaxTraceableBlocks: MaxTraceableBlocks,
TimePerBlock: TimePerBlock,
StandbyCommittee: []string{hex.EncodeToString(committeeAcc.PublicKey().Bytes())},
ValidatorsCount: 1,
VerifyTransactions: true,
},
Ledger: config.Ledger{
VerifyBlocks: true,
},
}
if f != nil {
f(&protoCfg)
f(&cfg)
}
if st == nil {
st = storage.NewMemoryStore()
}
log := zaptest.NewLogger(t)
bc, err := core.NewBlockchain(st, protoCfg, log)
bc, err := core.NewBlockchain(st, cfg, log)
require.NoError(t, err)
if 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
// 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)
}
@ -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
// responsibility to do that before using the chain and
// 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)
require.NoError(t, err)
if run {
@ -193,24 +198,28 @@ func NewMultiWithCustomConfigAndStore(t testing.TB, f func(*config.ProtocolConfi
// NewMultiWithCustomConfigAndStoreNoCheck is similar to NewMultiWithCustomConfig,
// 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) {
protoCfg := config.ProtocolConfiguration{
Magic: netmode.UnitTestNet,
MaxTraceableBlocks: MaxTraceableBlocks,
TimePerBlock: TimePerBlock,
StandbyCommittee: standByCommittee,
ValidatorsCount: 4,
VerifyBlocks: true,
VerifyTransactions: true,
func NewMultiWithCustomConfigAndStoreNoCheck(t testing.TB, f func(*config.Blockchain), st storage.Store) (*core.Blockchain, neotest.Signer, neotest.Signer, error) {
var cfg = config.Blockchain{
ProtocolConfiguration: config.ProtocolConfiguration{
Magic: netmode.UnitTestNet,
MaxTraceableBlocks: MaxTraceableBlocks,
TimePerBlock: TimePerBlock,
StandbyCommittee: standByCommittee,
ValidatorsCount: 4,
VerifyTransactions: true,
},
Ledger: config.Ledger{
VerifyBlocks: true,
},
}
if f != nil {
f(&protoCfg)
f(&cfg)
}
if st == nil {
st = storage.NewMemoryStore()
}
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
}

View file

@ -207,7 +207,7 @@ func newTestServer(t *testing.T, serverConfig ServerConfig) *Server {
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 {
// Normally it will be done by ApplicationConfiguration.GetAddresses().
serverConfig.Addresses = []config.AnnounceableAddress{{Address: ":0"}}

View file

@ -59,7 +59,7 @@ type (
mempool.Feer
Blockqueuer
GetBlock(hash util.Uint256) (*block.Block, error)
GetConfig() config.ProtocolConfiguration
GetConfig() config.Blockchain
GetHeader(hash util.Uint256) (*block.Header, error)
GetHeaderHash(uint32) util.Uint256
GetMaxVerificationGAS() int64
@ -177,7 +177,7 @@ func newServerFromConstructors(config ServerConfig, chain Ledger, stSync StateSy
ServerConfig: config,
chain: chain,
id: randomID(),
config: chain.GetConfig(),
config: chain.GetConfig().ProtocolConfiguration,
quit: make(chan struct{}),
relayFin: make(chan struct{}),
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 TestNewServer(t *testing.T) {
bc := &fakechain.FakeChain{ProtocolConfiguration: config.ProtocolConfiguration{
P2PStateExchangeExtensions: true,
StateRootInHeader: true,
}}
bc := &fakechain.FakeChain{Blockchain: config.Blockchain{
ProtocolConfiguration: config.ProtocolConfiguration{
P2PStateExchangeExtensions: true,
StateRootInHeader: true,
}}}
s, err := newServerFromConstructors(ServerConfig{}, bc, new(fakechain.FakeStateSync), nil, newFakeTransp, newTestDiscovery)
require.Error(t, err)
@ -387,7 +388,7 @@ func (s *Server) testHandleMessage(t *testing.T, p Peer, cmd CommandType, pl pay
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
srvCfg := ServerConfig{UserAgent: "/test/"}
if protocolCfg != nil {
@ -820,15 +821,15 @@ func TestHandleGetMPTData(t *testing.T) {
require.Eventually(t, recvResponse.Load, time.Second, time.Millisecond)
}
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.KeepOnlyLatestState = true
c.Ledger.KeepOnlyLatestState = true
})
check(t, s)
})
t.Run("good", func(t *testing.T) {
s := startTestServer(t, func(c *config.ProtocolConfiguration) {
s := startTestServer(t, func(c *config.Blockchain) {
c.P2PStateExchangeExtensions = true
})
check(t, s)

View file

@ -70,7 +70,7 @@ func dupNotaryRequest(t *testing.T, p *payload.P2PNotaryRequest) *payload.P2PNot
}
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
})
e := neotest.NewExecutor(t, bc, validators, committee)

View file

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

View file

@ -72,7 +72,7 @@ type (
GetBaseExecFee() int64
GetBlock(hash util.Uint256) (*block.Block, error)
GetCommittee() (keys.PublicKeys, error)
GetConfig() config.ProtocolConfiguration
GetConfig() config.Blockchain
GetContractScriptHash(id int32) (util.Uint160, error)
GetContractState(hash util.Uint160) *state.Contract
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.SessionExpirationTime <= 0 {
conf.SessionExpirationTime = int(protoCfg.TimePerBlock / time.Second)
@ -935,7 +935,7 @@ contract_loop:
lub, ok := lastUpdated[cs.ID]
if !ok {
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()))
}
lub = stateSyncPoint
@ -1057,7 +1057,7 @@ func (s *Server) getNEP17Balances(ps params.Params) (interface{}, *neorpc.Error)
lub, ok := lastUpdated[cs.ID]
if !ok {
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()))
}
lub = stateSyncPoint
@ -1396,7 +1396,7 @@ func makeStorageKey(id int32, key []byte) []byte {
var errKeepOnlyLatestState = errors.New("'KeepOnlyLatestState' setting is enabled")
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))
}
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) {
if s.chain.GetConfig().KeepOnlyLatestState {
if s.chain.GetConfig().Ledger.KeepOnlyLatestState {
return nil, neorpc.NewInvalidRequestError(fmt.Sprintf("'verifyproof' is not supported: %s", errKeepOnlyLatestState))
}
root, err := ps.Value(0).GetUint256()
@ -1455,7 +1455,7 @@ func (s *Server) getState(ps params.Params) (interface{}, *neorpc.Error) {
if err != nil {
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())
if err != nil {
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 {
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())
if err != nil {
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
// handling consistency.
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))
}
if len(reqParams) < 1 {

View file

@ -67,7 +67,7 @@ func getUnitTestChainWithCustomConfig(t testing.TB, enableOracle bool, enableNot
memoryStore := storage.NewMemoryStore()
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")
var orc *oracle.Oracle

View file

@ -21,7 +21,7 @@ import (
type (
// Ledger is an interface to Blockchain sufficient for Service.
Ledger interface {
GetConfig() config.ProtocolConfiguration
GetConfig() config.Blockchain
HeaderHeight() uint32
SubscribeForBlocks(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) {
bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.ProtocolConfiguration) {
bc, validators, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
c.P2PSigExtensions = true
})
e := neotest.NewExecutor(t, bc, validators, committee)

View file

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