forked from TrueCloudLab/neoneo-go
config: add TimePerBlock to replace SecondsPerBlock
It's more generic and convenient than MillisecondsPerBlock. This setting is made in backwards-compatible fashion, but it'll override SecondsPerBlock if both are used. Configurations are specifically not changed here, it's important to check compatibility. Fixes #2675.
This commit is contained in:
parent
f6a9969fa8
commit
c2adbf768b
13 changed files with 70 additions and 28 deletions
10
ROADMAP.md
10
ROADMAP.md
|
@ -92,3 +92,13 @@ used instead (that also have a counter).
|
|||
|
||||
It's not a frequently used thing and it's easy to replace it, so removal of
|
||||
old counters is scheduled for January-February 2023 (~0.100.X release).
|
||||
|
||||
## SecondsPerBlock protocol configuration
|
||||
|
||||
With 0.100.0 version SecondsPerBlock protocol configuration setting was
|
||||
deprecated and replaced by a bit more generic and precise TimePerBlock
|
||||
(allowing for subsecond time). An informational message is printed on node
|
||||
startup to inform about this, it's very easy to deal with this configuration
|
||||
change, just replace one line.
|
||||
|
||||
Removal of SecondsPerBlock is scheduled for May-June 2023 (~0.103.0 release).
|
||||
|
|
|
@ -197,7 +197,7 @@ where:
|
|||
enable `SessionBackedByMPT`, see `SessionBackedByMPT` documentation for more
|
||||
details.
|
||||
- `SessionExpirationTime` is a lifetime of iterator session in seconds. It is set
|
||||
to `SecondsPerBlock` seconds by default and is relevant only if `SessionEnabled`
|
||||
to `TimePerBlock` seconds by default and is relevant only if `SessionEnabled`
|
||||
is set to `true`.
|
||||
- `SessionBackedByMPT` is a flag forcing JSON-RPC server into using MPT-backed
|
||||
storage for delayed iterator traversal. If `true`, then iterator resources got
|
||||
|
@ -275,11 +275,12 @@ protocol-related settings described in the table below.
|
|||
| 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`). |
|
||||
| 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. |
|
||||
| SecondsPerBlock | `int` | `15` | Minimal time that should pass before next block is accepted. |
|
||||
| SecondsPerBlock | `int` | `15` | Minimal time that should pass before next block is accepted. Deprecated: please use TimePerBlock setting (which overrides anything set here), SecondsPerBlock will be removed in future versions. |
|
||||
| SeedList | `[]string` | [] | List of initial nodes addresses used to establish connectivity. |
|
||||
| StandbyCommittee | `[]string` | [] | List of public keys of standby committee validators are chosen from. |
|
||||
| StateRootInHeader | `bool` | `false` | Enables storing state root in block header. | Experimental protocol extension! |
|
||||
| StateSyncInterval | `int` | `40000` | The number of blocks between state heights available for MPT state data synchronization. | `P2PStateExchangeExtensions` should be enabled to use this setting. |
|
||||
| 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. |
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
|
@ -59,6 +60,9 @@ type (
|
|||
ReservedAttributes bool `yaml:"ReservedAttributes"`
|
||||
// SaveStorageBatch enables storage batch saving before every persist.
|
||||
SaveStorageBatch bool `yaml:"SaveStorageBatch"`
|
||||
// SecondsPerBlock is the time interval (in seconds) between blocks that consensus nodes work with.
|
||||
//
|
||||
// Deprecated: replaced by TimePerBlock, to be removed in future versions.
|
||||
SecondsPerBlock int `yaml:"SecondsPerBlock"`
|
||||
SeedList []string `yaml:"SeedList"`
|
||||
StandbyCommittee []string `yaml:"StandbyCommittee"`
|
||||
|
@ -67,6 +71,9 @@ type (
|
|||
// StateSyncInterval is the number of blocks between state heights available for MPT state data synchronization.
|
||||
// It is valid only if P2PStateExchangeExtensions are enabled.
|
||||
StateSyncInterval int `yaml:"StateSyncInterval"`
|
||||
// TimePerBlock is the time interval between blocks that consensus nodes work with.
|
||||
// It must be an integer number of milliseconds.
|
||||
TimePerBlock time.Duration `yaml:"TimePerBlock"`
|
||||
ValidatorsCount int `yaml:"ValidatorsCount"`
|
||||
// Validators stores history of changes to consensus node number (height: number).
|
||||
ValidatorsHistory map[uint32]int `yaml:"ValidatorsHistory"`
|
||||
|
@ -92,6 +99,9 @@ func (p *ProtocolConfiguration) Validate() error {
|
|||
if p.P2PStateExchangeExtensions && p.KeepOnlyLatestState && !p.RemoveUntraceableBlocks {
|
||||
return fmt.Errorf("P2PStateExchangeExtensions can be enabled either on MPT-complete node (KeepOnlyLatestState=false) or on light GC-enabled node (RemoveUntraceableBlocks=true)")
|
||||
}
|
||||
if p.TimePerBlock%time.Millisecond != 0 {
|
||||
return errors.New("TimePerBlock must be an integer number of milliseconds")
|
||||
}
|
||||
for name := range p.NativeUpdateHistories {
|
||||
if !nativenames.IsValid(name) {
|
||||
return fmt.Errorf("NativeActivations configuration section contains unexpected native contract name: %s", name)
|
||||
|
@ -219,6 +229,7 @@ func (p *ProtocolConfiguration) Equals(o *ProtocolConfiguration) bool {
|
|||
p.SecondsPerBlock != o.SecondsPerBlock ||
|
||||
p.StateRootInHeader != o.StateRootInHeader ||
|
||||
p.StateSyncInterval != o.StateSyncInterval ||
|
||||
p.TimePerBlock != o.TimePerBlock ||
|
||||
p.ValidatorsCount != o.ValidatorsCount ||
|
||||
p.VerifyBlocks != o.VerifyBlocks ||
|
||||
p.VerifyTransactions != o.VerifyTransactions ||
|
||||
|
|
|
@ -3,6 +3,7 @@ package config
|
|||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -17,6 +18,14 @@ func TestProtocolConfigurationValidation(t *testing.T) {
|
|||
P2PStateExchangeExtensions: true,
|
||||
}
|
||||
require.Error(t, p.Validate())
|
||||
p = &ProtocolConfiguration{
|
||||
StandbyCommittee: []string{
|
||||
"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2",
|
||||
},
|
||||
ValidatorsCount: 1,
|
||||
TimePerBlock: time.Microsecond,
|
||||
}
|
||||
require.Error(t, p.Validate())
|
||||
p = &ProtocolConfiguration{
|
||||
ValidatorsCount: 1,
|
||||
}
|
||||
|
|
|
@ -480,7 +480,7 @@ func newTestServiceWithChain(t *testing.T, bc *core.Blockchain) *service {
|
|||
ProtocolConfiguration: bc.GetConfig(),
|
||||
RequestTx: func(...util.Uint256) {},
|
||||
StopTxFlow: func() {},
|
||||
TimePerBlock: time.Duration(bc.GetConfig().SecondsPerBlock) * time.Second,
|
||||
TimePerBlock: bc.GetConfig().TimePerBlock,
|
||||
Wallet: &config.Wallet{
|
||||
Path: "./testdata/wallet1.json",
|
||||
Password: "one",
|
||||
|
|
|
@ -55,7 +55,7 @@ const (
|
|||
defaultMaxBlockSystemFee = 900000000000
|
||||
defaultMaxTraceableBlocks = 2102400 // 1 year of 15s blocks
|
||||
defaultMaxTransactionsPerBlock = 512
|
||||
defaultSecondsPerBlock = 15
|
||||
defaultTimePerBlock = 15 * time.Second
|
||||
// HeaderVerificationGasLimit is the maximum amount of GAS for block header verification.
|
||||
HeaderVerificationGasLimit = 3_00000000 // 3 GAS
|
||||
defaultStateSyncInterval = 40000
|
||||
|
@ -252,15 +252,21 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
|
|||
log.Info("MaxTransactionsPerBlock is not set or wrong, using default value",
|
||||
zap.Uint16("MaxTransactionsPerBlock", cfg.MaxTransactionsPerBlock))
|
||||
}
|
||||
if cfg.SecondsPerBlock == 0 {
|
||||
cfg.SecondsPerBlock = defaultSecondsPerBlock
|
||||
log.Info("SecondsPerBlock is not set or wrong, using default value",
|
||||
zap.Int("SecondsPerBlock", cfg.SecondsPerBlock))
|
||||
if cfg.TimePerBlock <= 0 {
|
||||
if cfg.SecondsPerBlock > 0 { //nolint:staticcheck // SA1019: cfg.SecondsPerBlock is deprecated
|
||||
cfg.TimePerBlock = time.Duration(cfg.SecondsPerBlock) * time.Second //nolint:staticcheck // SA1019: cfg.SecondsPerBlock is deprecated
|
||||
log.Info("TimePerBlock is not set, using deprecated SecondsPerBlock setting, consider updating your config",
|
||||
zap.Duration("TimePerBlock", cfg.TimePerBlock))
|
||||
} else {
|
||||
cfg.TimePerBlock = defaultTimePerBlock
|
||||
log.Info("TimePerBlock is not set or wrong, using default value",
|
||||
zap.Duration("TimePerBlock", cfg.TimePerBlock))
|
||||
}
|
||||
}
|
||||
if cfg.MaxValidUntilBlockIncrement == 0 {
|
||||
const secondsPerDay = int(24 * time.Hour / time.Second)
|
||||
const timePerDay = 24 * time.Hour
|
||||
|
||||
cfg.MaxValidUntilBlockIncrement = uint32(secondsPerDay / cfg.SecondsPerBlock)
|
||||
cfg.MaxValidUntilBlockIncrement = uint32(timePerDay / cfg.TimePerBlock)
|
||||
log.Info("MaxValidUntilBlockIncrement is not set or wrong, using default value",
|
||||
zap.Uint32("MaxValidUntilBlockIncrement", cfg.MaxValidUntilBlockIncrement))
|
||||
}
|
||||
|
@ -2650,7 +2656,7 @@ func (bc *Blockchain) getFakeNextBlock(nextBlockHeight uint32) (*block.Block, er
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.Timestamp = hdr.Timestamp + uint64(bc.config.SecondsPerBlock*int(time.Second/time.Millisecond))
|
||||
b.Timestamp = hdr.Timestamp + uint64(bc.config.TimePerBlock/time.Millisecond)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/hex"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
|
@ -22,9 +23,9 @@ const (
|
|||
// We don't need a lot of traceable blocks for tests.
|
||||
MaxTraceableBlocks = 1000
|
||||
|
||||
// SecondsPerBlock is the default SecondsPerBlock setting used for test chains.
|
||||
// TimePerBlock is the default TimePerBlock setting used for test chains (1s).
|
||||
// Usually blocks are created by tests bypassing this setting.
|
||||
SecondsPerBlock = 1
|
||||
TimePerBlock = time.Second
|
||||
)
|
||||
|
||||
const singleValidatorWIF = "KxyjQ8eUa4FHt3Gvioyt1Wz29cTUrE4eTqX3yFSk1YFCsPL8uNsY"
|
||||
|
@ -117,7 +118,7 @@ func init() {
|
|||
|
||||
// NewSingle creates a new blockchain instance with a single validator and
|
||||
// setups cleanup functions. The configuration used is with netmode.UnitTestNet
|
||||
// magic and SecondsPerBlock/MaxTraceableBlocks options defined by constants in
|
||||
// magic and TimePerBlock/MaxTraceableBlocks options defined by constants in
|
||||
// this package. MemoryStore is used as the backend storage, so all of the chain
|
||||
// contents is always in RAM. The Signer returned is the validator (and the committee at
|
||||
// the same time).
|
||||
|
@ -140,7 +141,7 @@ func NewSingleWithCustomConfigAndStore(t testing.TB, f func(cfg *config.Protocol
|
|||
protoCfg := config.ProtocolConfiguration{
|
||||
Magic: netmode.UnitTestNet,
|
||||
MaxTraceableBlocks: MaxTraceableBlocks,
|
||||
SecondsPerBlock: SecondsPerBlock,
|
||||
TimePerBlock: TimePerBlock,
|
||||
StandbyCommittee: []string{hex.EncodeToString(committeeAcc.PublicKey().Bytes())},
|
||||
ValidatorsCount: 1,
|
||||
VerifyBlocks: true,
|
||||
|
@ -196,7 +197,7 @@ func NewMultiWithCustomConfigAndStoreNoCheck(t testing.TB, f func(*config.Protoc
|
|||
protoCfg := config.ProtocolConfiguration{
|
||||
Magic: netmode.UnitTestNet,
|
||||
MaxTraceableBlocks: MaxTraceableBlocks,
|
||||
SecondsPerBlock: SecondsPerBlock,
|
||||
TimePerBlock: TimePerBlock,
|
||||
StandbyCommittee: standByCommittee,
|
||||
ValidatorsCount: 4,
|
||||
VerifyBlocks: true,
|
||||
|
|
|
@ -89,6 +89,10 @@ type (
|
|||
func NewServerConfig(cfg config.Config) ServerConfig {
|
||||
appConfig := cfg.ApplicationConfiguration
|
||||
protoConfig := cfg.ProtocolConfiguration
|
||||
timePerBlock := protoConfig.TimePerBlock
|
||||
if timePerBlock == 0 && protoConfig.SecondsPerBlock > 0 { //nolint:staticcheck // SA1019: protoConfig.SecondsPerBlock is deprecated
|
||||
timePerBlock = time.Duration(protoConfig.SecondsPerBlock) * time.Second //nolint:staticcheck // SA1019: protoConfig.SecondsPerBlock is deprecated
|
||||
}
|
||||
|
||||
return ServerConfig{
|
||||
UserAgent: cfg.GenerateUserAgent(),
|
||||
|
@ -105,7 +109,7 @@ func NewServerConfig(cfg config.Config) ServerConfig {
|
|||
MaxPeers: appConfig.MaxPeers,
|
||||
AttemptConnPeers: appConfig.AttemptConnPeers,
|
||||
MinPeers: appConfig.MinPeers,
|
||||
TimePerBlock: time.Duration(protoConfig.SecondsPerBlock) * time.Second,
|
||||
TimePerBlock: timePerBlock,
|
||||
OracleCfg: appConfig.Oracle,
|
||||
P2PNotaryCfg: appConfig.P2PNotary,
|
||||
StateRootCfg: appConfig.StateRoot,
|
||||
|
|
|
@ -205,7 +205,7 @@ func (p *TCPPeer) handleQueues() {
|
|||
var p2pSkipCounter uint32
|
||||
const p2pSkipDivisor = 4
|
||||
|
||||
var writeTimeout = time.Duration(p.server.config.SecondsPerBlock) * time.Second
|
||||
var writeTimeout = p.server.TimePerBlock
|
||||
for {
|
||||
var msg []byte
|
||||
|
||||
|
|
|
@ -1994,7 +1994,7 @@ func TestClient_Wait(t *testing.T) {
|
|||
select {
|
||||
case <-rcvr:
|
||||
break waitloop
|
||||
case <-time.NewTimer(time.Duration(chain.GetConfig().SecondsPerBlock) * time.Second).C:
|
||||
case <-time.NewTimer(chain.GetConfig().TimePerBlock).C:
|
||||
t.Fatal("transaction failed to be awaited")
|
||||
}
|
||||
}
|
||||
|
@ -2070,7 +2070,7 @@ func TestWSClient_Wait(t *testing.T) {
|
|||
require.Equal(t, vmstate.Halt, aer.VMState)
|
||||
}
|
||||
break waitloop
|
||||
case <-time.NewTimer(time.Duration(chain.GetConfig().SecondsPerBlock) * time.Second).C:
|
||||
case <-time.NewTimer(chain.GetConfig().TimePerBlock).C:
|
||||
t.Fatalf("transaction from block %d failed to be awaited: deadline exceeded", b.Index)
|
||||
}
|
||||
}
|
||||
|
@ -2232,7 +2232,7 @@ waitloop:
|
|||
require.Equal(t, trigger.Application, aer.Trigger)
|
||||
require.Equal(t, vmstate.Halt, aer.VMState)
|
||||
break waitloop
|
||||
case <-time.NewTimer(time.Duration(chain.GetConfig().SecondsPerBlock) * time.Second).C:
|
||||
case <-time.NewTimer(chain.GetConfig().TimePerBlock).C:
|
||||
t.Fatal("transaction failed to be awaited")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -268,8 +268,8 @@ func New(chain Ledger, conf config.RPC, coreServer *network.Server,
|
|||
protoCfg := chain.GetConfig()
|
||||
if conf.SessionEnabled {
|
||||
if conf.SessionExpirationTime <= 0 {
|
||||
conf.SessionExpirationTime = protoCfg.SecondsPerBlock
|
||||
log.Info("SessionExpirationTime is not set or wrong, setting default value", zap.Int("SessionExpirationTime", protoCfg.SecondsPerBlock))
|
||||
conf.SessionExpirationTime = int(protoCfg.TimePerBlock / time.Second)
|
||||
log.Info("SessionExpirationTime is not set or wrong, setting default value", zap.Int("SessionExpirationTime", conf.SessionExpirationTime))
|
||||
}
|
||||
if conf.SessionPoolSize <= 0 {
|
||||
conf.SessionPoolSize = defaultSessionPoolSize
|
||||
|
@ -706,7 +706,7 @@ func (s *Server) getVersion(_ params.Params) (interface{}, *neorpc.Error) {
|
|||
Protocol: result.Protocol{
|
||||
AddressVersion: address.NEO3Prefix,
|
||||
Network: cfg.Magic,
|
||||
MillisecondsPerBlock: cfg.SecondsPerBlock * 1000,
|
||||
MillisecondsPerBlock: int(cfg.TimePerBlock / time.Millisecond),
|
||||
MaxTraceableBlocks: cfg.MaxTraceableBlocks,
|
||||
MaxValidUntilBlockIncrement: cfg.MaxValidUntilBlockIncrement,
|
||||
MaxTransactionsPerBlock: cfg.MaxTransactionsPerBlock,
|
||||
|
|
|
@ -872,7 +872,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
cfg := e.chain.GetConfig()
|
||||
require.EqualValues(t, address.NEO3Prefix, resp.Protocol.AddressVersion)
|
||||
require.EqualValues(t, cfg.Magic, resp.Protocol.Network)
|
||||
require.EqualValues(t, cfg.SecondsPerBlock*1000, resp.Protocol.MillisecondsPerBlock)
|
||||
require.EqualValues(t, cfg.TimePerBlock/time.Millisecond, resp.Protocol.MillisecondsPerBlock)
|
||||
require.EqualValues(t, cfg.MaxTraceableBlocks, resp.Protocol.MaxTraceableBlocks)
|
||||
require.EqualValues(t, cfg.MaxValidUntilBlockIncrement, resp.Protocol.MaxValidUntilBlockIncrement)
|
||||
require.EqualValues(t, cfg.MaxTransactionsPerBlock, resp.Protocol.MaxTransactionsPerBlock)
|
||||
|
|
|
@ -87,7 +87,7 @@ func New(cfg config.StateRoot, sm *stateroot.Module, log *zap.Logger, bc Ledger,
|
|||
blockCh: make(chan *block.Block),
|
||||
stopCh: make(chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
timePerBlock: time.Duration(bcConf.SecondsPerBlock) * time.Second,
|
||||
timePerBlock: bcConf.TimePerBlock,
|
||||
maxRetries: voteValidEndInc,
|
||||
relayExtensible: cb,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue