diff --git a/cmd/geth/main.go b/cmd/geth/main.go index a539719a49..5e606251b4 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -149,6 +149,7 @@ var ( utils.PluginSkipVerifyFlag, utils.PluginLocalVerifyFlag, utils.PluginPublicKeyFlag, + utils.AllowedFutureBlockTimeFlag, // End-Quorum } diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index c0e0d00e66..024adc919b 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -145,6 +145,7 @@ var AppHelpFlagGroups = []flagGroup{ utils.PluginSkipVerifyFlag, utils.PluginLocalVerifyFlag, utils.PluginPublicKeyFlag, + utils.AllowedFutureBlockTimeFlag, }, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index eecabb2270..f9c9c0601d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -619,6 +619,11 @@ var ( Name: "permissioned", Usage: "If enabled, the node will allow only a defined list of nodes to connect", } + AllowedFutureBlockTimeFlag = cli.Uint64Flag{ + Name: "allowedfutureblocktime", + Usage: "Max time (in seconds) from current time allowed for blocks, before they're considered future blocks", + Value: 0, + } // Plugins settings PluginSettingsFlag = cli.StringFlag{ Name: "plugins", @@ -1270,6 +1275,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { setEthash(ctx, cfg) setIstanbul(ctx, cfg) + cfg.AllowedFutureBlockTime = ctx.GlobalUint64(AllowedFutureBlockTimeFlag.Name) //Quorum + if ctx.GlobalIsSet(SyncModeFlag.Name) { cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) } diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index dc2614dfa3..41ef68b659 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -278,8 +278,9 @@ func (c *Clique) verifyHeader(chain consensus.ChainReader, header *types.Header, } number := header.Number.Uint64() - // Don't waste time checking blocks from the future - if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 { + // Don't waste time checking blocks from the future (adjusting for allowed threshold) + adjustedTimeNow := time.Now().Add(time.Duration(c.config.AllowedFutureBlockTime) * time.Second).Unix() + if header.Time.Cmp(big.NewInt(adjustedTimeNow)) > 0 { return consensus.ErrFutureBlock } // Checkpoint blocks need to enforce zero beneficiary diff --git a/consensus/istanbul/backend/engine.go b/consensus/istanbul/backend/engine.go index 0c24f91cd9..264e384445 100644 --- a/consensus/istanbul/backend/engine.go +++ b/consensus/istanbul/backend/engine.go @@ -27,8 +27,8 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/istanbul" - "github.com/ethereum/go-ethereum/consensus/istanbul/validator" istanbulCore "github.com/ethereum/go-ethereum/consensus/istanbul/core" + "github.com/ethereum/go-ethereum/consensus/istanbul/validator" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/sha3" @@ -144,8 +144,9 @@ func (sb *backend) verifyHeader(chain consensus.ChainReader, header *types.Heade return errUnknownBlock } - // Don't waste time checking blocks from the future - if header.Time.Cmp(big.NewInt(now().Unix())) > 0 { + // Don't waste time checking blocks from the future (adjusting for allowed threshold) + adjustedTimeNow := now().Add(time.Duration(sb.config.AllowedFutureBlockTime) * time.Second).Unix() + if header.Time.Cmp(big.NewInt(adjustedTimeNow)) > 0 { return consensus.ErrFutureBlock } @@ -308,7 +309,7 @@ func (sb *backend) verifyCommittedSeals(chain consensus.ChainReader, header *typ return errInvalidCommittedSeals } - // The length of validSeal should be larger than number of faulty node + 1 + // The length of validSeal should be larger than number of faulty node + 1 if validSeal <= snap.ValSet.F() { return errInvalidCommittedSeals } diff --git a/consensus/istanbul/backend/engine_test.go b/consensus/istanbul/backend/engine_test.go index fa5c4a4fde..cb5f54c2aa 100644 --- a/consensus/istanbul/backend/engine_test.go +++ b/consensus/istanbul/backend/engine_test.go @@ -325,6 +325,18 @@ func TestVerifyHeader(t *testing.T) { t.Errorf("error mismatch: have %v, want %v", err, consensus.ErrFutureBlock) } + // future block which is within AllowedFutureBlockTime + block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) + header = block.Header() + header.Time = new(big.Int).Add(big.NewInt(now().Unix()), new(big.Int).SetUint64(10)) + priorValue := engine.config.AllowedFutureBlockTime + engine.config.AllowedFutureBlockTime = 10 + err = engine.VerifyHeader(chain, header, false) + engine.config.AllowedFutureBlockTime = priorValue //restore changed value + if err == consensus.ErrFutureBlock { + t.Errorf("error mismatch: have %v, want nil", err) + } + // invalid nonce block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) header = block.Header() diff --git a/consensus/istanbul/config.go b/consensus/istanbul/config.go index 2a223a1a51..dfe6c087d0 100644 --- a/consensus/istanbul/config.go +++ b/consensus/istanbul/config.go @@ -26,17 +26,19 @@ const ( ) type Config struct { - RequestTimeout uint64 `toml:",omitempty"` // The timeout for each Istanbul round in milliseconds. - BlockPeriod uint64 `toml:",omitempty"` // Default minimum difference between two consecutive block's timestamps in second - ProposerPolicy ProposerPolicy `toml:",omitempty"` // The policy for proposer selection - Epoch uint64 `toml:",omitempty"` // The number of blocks after which to checkpoint and reset the pending votes - Ceil2Nby3Block *big.Int `toml:",omitempty"` // Number of confirmations required to move from one state to next [2F + 1 to Ceil(2N/3)] + RequestTimeout uint64 `toml:",omitempty"` // The timeout for each Istanbul round in milliseconds. + BlockPeriod uint64 `toml:",omitempty"` // Default minimum difference between two consecutive block's timestamps in second + ProposerPolicy ProposerPolicy `toml:",omitempty"` // The policy for proposer selection + Epoch uint64 `toml:",omitempty"` // The number of blocks after which to checkpoint and reset the pending votes + Ceil2Nby3Block *big.Int `toml:",omitempty"` // Number of confirmations required to move from one state to next [2F + 1 to Ceil(2N/3)] + AllowedFutureBlockTime uint64 `toml:",omitempty"` // Max time (in seconds) from current time allowed for blocks, before they're considered future blocks } var DefaultConfig = &Config{ - RequestTimeout: 10000, - BlockPeriod: 1, - ProposerPolicy: RoundRobin, - Epoch: 30000, - Ceil2Nby3Block: big.NewInt(0), + RequestTimeout: 10000, + BlockPeriod: 1, + ProposerPolicy: RoundRobin, + Epoch: 30000, + Ceil2Nby3Block: big.NewInt(0), + AllowedFutureBlockTime: 0, } diff --git a/eth/backend.go b/eth/backend.go index d7af9b20fd..9906671e6b 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -250,6 +250,7 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine { // If proof-of-authority is requested, set it up if chainConfig.Clique != nil { + chainConfig.Clique.AllowedFutureBlockTime = config.AllowedFutureBlockTime //Quorum return clique.New(chainConfig.Clique, db) } // If Istanbul is requested, set it up @@ -259,6 +260,7 @@ func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainCo } config.Istanbul.ProposerPolicy = istanbul.ProposerPolicy(chainConfig.Istanbul.ProposerPolicy) config.Istanbul.Ceil2Nby3Block = chainConfig.Istanbul.Ceil2Nby3Block + config.Istanbul.AllowedFutureBlockTime = config.AllowedFutureBlockTime return istanbulBackend.New(&config.Istanbul, ctx.NodeKey(), db) } diff --git a/eth/config.go b/eth/config.go index 751a659d5d..f104cdc95f 100644 --- a/eth/config.go +++ b/eth/config.go @@ -128,7 +128,8 @@ type Config struct { Istanbul istanbul.Config // Miscellaneous options - DocRoot string `toml:"-"` + DocRoot string `toml:"-"` + AllowedFutureBlockTime uint64 //Quorum // Type of the EWASM interpreter ("" for default) EWASMInterpreter string diff --git a/eth/handler_test.go b/eth/handler_test.go index da3a779ef3..7f0ebbff49 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -82,8 +82,8 @@ func TestNodeInfo(t *testing.T) { }{ {"ethash", nil, nil, false}, {"raft", nil, nil, true}, - {"istanbul", nil, ¶ms.IstanbulConfig{1, 1, big.NewInt(0)}, false}, - {"clique", ¶ms.CliqueConfig{1, 1}, nil, false}, + {"istanbul", nil, ¶ms.IstanbulConfig{1, 1, big.NewInt(0), 0}, false}, + {"clique", ¶ms.CliqueConfig{1, 1, 0}, nil, false}, } // Make sure anything we screw up is restored @@ -285,10 +285,10 @@ func testGetBlockBodies(t *testing.T, protocol int) { available []bool // Availability of explicitly requested blocks expected int // Total number of existing blocks to expect }{ - {1, nil, nil, 1}, // A single random block should be retrievable - {10, nil, nil, 10}, // Multiple random blocks should be retrievable - {limit, nil, nil, limit}, // The maximum possible blocks should be retrievable - {limit + 1, nil, nil, limit}, // No more than the possible block count should be returned + {1, nil, nil, 1}, // A single random block should be retrievable + {10, nil, nil, 10}, // Multiple random blocks should be retrievable + {limit, nil, nil, limit}, // The maximum possible blocks should be retrievable + {limit + 1, nil, nil, limit}, // No more than the possible block count should be returned {0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1}, // The genesis block should be retrievable {0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable {0, []common.Hash{{}}, []bool{false}, 0}, // A non existent block should not be returned diff --git a/params/config.go b/params/config.go index d16afa6a55..d0e56e649a 100644 --- a/params/config.go +++ b/params/config.go @@ -195,7 +195,7 @@ type ChainConfig struct { // Quorum // // QIP714Block implements the permissions related changes - QIP714Block *big.Int `json:"qip714Block,omitempty"` + QIP714Block *big.Int `json:"qip714Block,omitempty"` MaxCodeSizeChangeBlock *big.Int `json:"maxCodeSizeChangeBlock,omitempty"` } @@ -209,8 +209,9 @@ func (c *EthashConfig) String() string { // CliqueConfig is the consensus engine configs for proof-of-authority based sealing. type CliqueConfig struct { - Period uint64 `json:"period"` // Number of seconds between blocks to enforce - Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint + Period uint64 `json:"period"` // Number of seconds between blocks to enforce + Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint + AllowedFutureBlockTime uint64 `json:"allowedFutureBlockTime"` // Max time (in seconds) from current time allowed for blocks, before they're considered future blocks } // String implements the stringer interface, returning the consensus engine details. @@ -220,9 +221,10 @@ func (c *CliqueConfig) String() string { // IstanbulConfig is the consensus engine configs for Istanbul based sealing. type IstanbulConfig struct { - Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint - ProposerPolicy uint64 `json:"policy"` // The policy for proposer selection - Ceil2Nby3Block *big.Int `json:"ceil2Nby3Block,omitempty"` // Number of confirmations required to move from one state to next [2F + 1 to Ceil(2N/3)] + Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint + ProposerPolicy uint64 `json:"policy"` // The policy for proposer selection + Ceil2Nby3Block *big.Int `json:"ceil2Nby3Block,omitempty"` // Number of confirmations required to move from one state to next [2F + 1 to Ceil(2N/3)] + AllowedFutureBlockTime uint64 `json:"allowedFutureBlockTime"` // Max time (in seconds) from current time allowed for blocks, before they're considered future blocks } // String implements the stringer interface, returning the consensus engine details. @@ -319,6 +321,7 @@ func (c *ChainConfig) IsEWASM(num *big.Int) bool { func (c *ChainConfig) IsQIP714(num *big.Int) bool { return isForked(c.QIP714Block, num) } + // Quorum // // IsMaxCodeSizeChangeBlock returns whether num represents a block number max code size