Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

consensus/parlia: reduce block interval to 1 second #143

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cmd/geth/chaincmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ var (
utils.OverridePassedForkTime,
utils.OverridePascal,
utils.OverridePrague,
utils.OverrideLorentz,
utils.OverrideVerkle,
utils.MultiDataBaseFlag,
}, utils.DatabaseFlags),
Expand Down Expand Up @@ -268,6 +269,10 @@ func initGenesis(ctx *cli.Context) error {
v := ctx.Uint64(utils.OverridePrague.Name)
overrides.OverridePrague = &v
}
if ctx.IsSet(utils.OverrideLorentz.Name) {
v := ctx.Uint64(utils.OverrideLorentz.Name)
overrides.OverrideLorentz = &v
}
if ctx.IsSet(utils.OverrideVerkle.Name) {
v := ctx.Uint64(utils.OverrideVerkle.Name)
overrides.OverrideVerkle = &v
Expand Down
4 changes: 4 additions & 0 deletions cmd/geth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
v := ctx.Uint64(utils.OverridePrague.Name)
cfg.Eth.OverridePrague = &v
}
if ctx.IsSet(utils.OverrideLorentz.Name) {
v := ctx.Uint64(utils.OverrideLorentz.Name)
cfg.Eth.OverrideLorentz = &v
}
if ctx.IsSet(utils.OverrideVerkle.Name) {
v := ctx.Uint64(utils.OverrideVerkle.Name)
cfg.Eth.OverrideVerkle = &v
Expand Down
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ var (
utils.OverridePassedForkTime,
utils.OverridePascal,
utils.OverridePrague,
utils.OverrideLorentz,
utils.OverrideVerkle,
utils.OverrideFullImmutabilityThreshold,
utils.OverrideMinBlocksForBlobRequests,
Expand Down
5 changes: 5 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ var (
Usage: "Manually specify the Prague fork timestamp, overriding the bundled setting",
Category: flags.EthCategory,
}
OverrideLorentz = &cli.Uint64Flag{
Name: "override.lorentz",
Usage: "Manually specify the Lorentz fork timestamp, overriding the bundled setting",
Category: flags.EthCategory,
}
OverrideVerkle = &cli.Uint64Flag{
Name: "override.verkle",
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
Expand Down
4 changes: 4 additions & 0 deletions consensus/beacon/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,10 @@ func (beacon *Beacon) Delay(_ consensus.ChainReader, _ *types.Header, _ *time.Du
return nil
}

func (beacon *Beacon) BlockInterval(chain consensus.ChainHeaderReader, header *types.Header) (uint64, error) {
panic("not supported")
}

// Finalize implements consensus.Engine, setting the final state on the header
func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state vm.StateDB, txs *[]*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal, _ *[]*types.Receipt, _ *[]*types.Transaction, _ *uint64, tracer *tracing.Hooks) error {
// Finalize is different with Prepare, it can be used in both block verification.
Expand Down
4 changes: 4 additions & 0 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,10 @@ func (c *Clique) Delay(chain consensus.ChainReader, header *types.Header, leftOv
return nil
}

func (c *Clique) BlockInterval(chain consensus.ChainHeaderReader, header *types.Header) (uint64, error) {
return c.config.Period, nil
}

// Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials.
func (c *Clique) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
Expand Down
4 changes: 3 additions & 1 deletion consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ type Engine interface {
// Delay returns the max duration the miner can commit txs
Delay(chain ChainReader, header *types.Header, leftOver *time.Duration) *time.Duration

// BlockInterval returns the block interval after given header applied
BlockInterval(chain ChainHeaderReader, header *types.Header) (uint64, error)

// Close terminates any background threads maintained by the consensus engine.
Close() error
}
Expand All @@ -162,6 +165,5 @@ type PoSA interface {
GetFinalizedHeader(chain ChainHeaderReader, header *types.Header) *types.Header
VerifyVote(chain ChainHeaderReader, vote *types.VoteEnvelope) error
IsActiveValidatorAt(chain ChainHeaderReader, header *types.Header, checkVoteKeyFn func(bLSPublicKey *types.BLSPublicKey) bool) bool
BlockInterval() uint64
NextProposalBlock(chain ChainHeaderReader, header *types.Header, proposer common.Address) (uint64, uint64, error)
}
4 changes: 4 additions & 0 deletions consensus/ethash/ethash.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,7 @@ func (ethash *Ethash) APIs(chain consensus.ChainHeaderReader) []rpc.API {
func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
panic("ethash (pow) sealing not supported any more")
}

func (ethash *Ethash) BlockInterval(chain consensus.ChainHeaderReader, header *types.Header) (uint64, error) {
panic("not supported")
}
3 changes: 1 addition & 2 deletions consensus/misc/eip1559/eip1559_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ func config() *params.ChainConfig {
config := copyConfig(params.TestChainConfig)
config.Ethash = nil
config.Parlia = &params.ParliaConfig{
Period: 3,
Epoch: 200,
Epoch: 200,
}
config.LondonBlock = big.NewInt(5)
return config
Expand Down
40 changes: 22 additions & 18 deletions consensus/parlia/parlia.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ const (
inMemorySignatures = 4096 // Number of recent block signatures to keep in memory
inMemoryHeaders = 86400 // Number of recent headers to keep in memory for double sign detection,

checkpointInterval = 1024 // Number of blocks after which to save the snapshot to the database
defaultEpochLength = uint64(200) // Default number of blocks of checkpoint to update validatorSet from contract
defaultTurnLength = uint8(1) // Default consecutive number of blocks a validator receives priority for block production
checkpointInterval = 1024 // Number of blocks after which to save the snapshot to the database
defaultEpochLength = uint64(200) // Default number of blocks of checkpoint to update validatorSet from contract
defaultBlockInterval = uint8(3) // Default block interval
lorentzBlockInterval = uint8(1) // Block interval starting from the Lorentz hard fork
defaultTurnLength = uint8(1) // Default consecutive number of blocks a validator receives priority for block production

extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
Expand Down Expand Up @@ -316,10 +318,6 @@ func New(
return c
}

func (p *Parlia) Period() uint64 {
return p.config.Period
}

func (p *Parlia) IsSystemTransaction(tx *types.Transaction, header *types.Header) (bool, error) {
// deploy a contract
if tx.To() == nil {
Expand Down Expand Up @@ -779,6 +777,10 @@ func (p *Parlia) snapshot(chain consensus.ChainHeaderReader, number uint64, hash
// new snapshot
snap = newSnapshot(p.config, p.signatures, number, blockHash, validators, voteAddrs, p.ethAPI)

if p.chainConfig.IsLorentz(checkpoint.Number, checkpoint.Time) {
snap.BlockInterval = lorentzBlockInterval
}

// get turnLength from headers and use that for new turnLength
turnLength, err := parseTurnLength(checkpoint, p.chainConfig, p.config)
if err != nil {
Expand Down Expand Up @@ -1539,9 +1541,9 @@ func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOv
}
delay := p.delayForRamanujanFork(snap, header)

if *leftOver >= time.Duration(p.config.Period)*time.Second {
if *leftOver >= time.Duration(snap.BlockInterval)*time.Second {
// ignore invalid leftOver
log.Error("Delay invalid argument", "leftOver", leftOver.String(), "Period", p.config.Period)
log.Error("Delay invalid argument", "leftOver", leftOver.String(), "Period", snap.BlockInterval)
} else if *leftOver >= delay {
delay = time.Duration(0)
return &delay
Expand All @@ -1550,9 +1552,9 @@ func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOv
}

// The blocking time should be no more than half of period when snap.TurnLength == 1
timeForMining := time.Duration(p.config.Period) * time.Second / 2
timeForMining := time.Duration(snap.BlockInterval) * time.Second / 2
if !snap.lastBlockInOneTurn(header.Number.Uint64()) {
timeForMining = time.Duration(p.config.Period) * time.Second * 2 / 3
timeForMining = time.Duration(snap.BlockInterval) * time.Second * 2 / 3
}
if delay > timeForMining {
delay = timeForMining
Expand All @@ -1570,11 +1572,6 @@ func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, res
if number == 0 {
return errUnknownBlock
}
// For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing)
if p.config.Period == 0 && len(block.Transactions()) == 0 {
log.Info("Sealing paused, waiting for transactions")
return nil
}
// Don't hold the val fields for the entire sealing procedure
p.lock.RLock()
val, signFn := p.val, p.signFn
Expand Down Expand Up @@ -2159,8 +2156,15 @@ func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Ad
}
}

func (p *Parlia) BlockInterval() uint64 {
return p.config.Period
func (p *Parlia) BlockInterval(chain consensus.ChainHeaderReader, header *types.Header) (uint64, error) {
if header == nil {
return uint64(defaultBlockInterval), errUnknownBlock
}
snap, err := p.snapshot(chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil {
return uint64(defaultBlockInterval), err
}
return uint64(snap.BlockInterval), nil
}

func (p *Parlia) NextProposalBlock(chain consensus.ChainHeaderReader, header *types.Header, proposer common.Address) (uint64, uint64, error) {
Expand Down
4 changes: 2 additions & 2 deletions consensus/parlia/ramanujanfork.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (p *Parlia) delayForRamanujanFork(snap *Snapshot, header *types.Header) tim
}

func (p *Parlia) blockTimeForRamanujanFork(snap *Snapshot, header, parent *types.Header) uint64 {
blockTime := parent.Time + p.config.Period
blockTime := parent.Time + uint64(snap.BlockInterval)
if p.chainConfig.IsRamanujan(header.Number) {
blockTime = blockTime + p.backOffTime(snap, header, p.val)
}
Expand All @@ -36,7 +36,7 @@ func (p *Parlia) blockTimeForRamanujanFork(snap *Snapshot, header, parent *types

func (p *Parlia) blockTimeVerifyForRamanujanFork(snap *Snapshot, header, parent *types.Header) error {
if p.chainConfig.IsRamanujan(header.Number) {
if header.Time < parent.Time+p.config.Period+p.backOffTime(snap, header, header.Coinbase) {
if header.Time < parent.Time+uint64(snap.BlockInterval)+p.backOffTime(snap, header, header.Coinbase) {
return consensus.ErrFutureBlock
}
}
Expand Down
10 changes: 10 additions & 0 deletions consensus/parlia/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Snapshot struct {

Number uint64 `json:"number"` // Block number where the snapshot was created
Hash common.Hash `json:"hash"` // Block hash where the snapshot was created
BlockInterval uint8 `json:"block_interval"` // Block Interval
TurnLength uint8 `json:"turn_length"` // Length of `turn`, meaning the consecutive number of blocks a validator receives priority for block production
Validators map[common.Address]*ValidatorInfo `json:"validators"` // Set of authorized validators at this moment
Recents map[uint64]common.Address `json:"recents"` // Set of recent validators for spam protections
Expand Down Expand Up @@ -74,6 +75,7 @@ func newSnapshot(
sigCache: sigCache,
Number: number,
Hash: hash,
BlockInterval: defaultBlockInterval,
TurnLength: defaultTurnLength,
Recents: make(map[uint64]common.Address),
RecentForkHashes: make(map[uint64]string),
Expand Down Expand Up @@ -117,6 +119,9 @@ func loadSnapshot(config *params.ParliaConfig, sigCache *lru.ARCCache, db ethdb.
if err := json.Unmarshal(blob, snap); err != nil {
return nil, err
}
if snap.BlockInterval == 0 { // no BlockInterval field in old snapshots
snap.BlockInterval = defaultBlockInterval
}
if snap.TurnLength == 0 { // no TurnLength field in old snapshots
snap.TurnLength = defaultTurnLength
}
Expand Down Expand Up @@ -145,6 +150,7 @@ func (s *Snapshot) copy() *Snapshot {
sigCache: s.sigCache,
Number: s.Number,
Hash: s.Hash,
BlockInterval: s.BlockInterval,
TurnLength: s.TurnLength,
Validators: make(map[common.Address]*ValidatorInfo),
Recents: make(map[uint64]common.Address),
Expand Down Expand Up @@ -308,6 +314,10 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
}
}
}
// It's better to set it based on IsOnLorentz, but in practice, the effect is the same as using IsLorentz.
if chainConfig.IsLorentz(header.Number, header.Time) {
snap.BlockInterval = lorentzBlockInterval
}
snap.Recents[number] = validator
snap.RecentForkHashes[number] = hex.EncodeToString(header.Extra[extraVanity-nextForkHashSize : extraVanity])
snap.updateAttestation(header, chainConfig, s.config)
Expand Down
4 changes: 4 additions & 0 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ type ChainOverrides struct {
OverridePassedForkTime *uint64
OverridePascal *uint64
OverridePrague *uint64
OverrideLorentz *uint64
OverrideVerkle *uint64
}

Expand All @@ -290,6 +291,9 @@ func (o *ChainOverrides) apply(cfg *params.ChainConfig) error {
if o.OverridePrague != nil {
cfg.PragueTime = o.OverridePrague
}
if o.OverrideLorentz != nil {
cfg.LorentzTime = o.OverrideLorentz
}
if o.OverrideVerkle != nil {
cfg.VerkleTime = o.OverrideVerkle
}
Expand Down
15 changes: 7 additions & 8 deletions core/vote/vote_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/parlia"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader"
Expand Down Expand Up @@ -147,13 +146,13 @@ func (voteManager *VoteManager) loop() {
}

curHead := cHead.Header
if p, ok := voteManager.engine.(*parlia.Parlia); ok {
nextBlockMinedTime := time.Unix(int64((curHead.Time + p.Period())), 0)
timeForBroadcast := 50 * time.Millisecond // enough to broadcast a vote
if time.Now().Add(timeForBroadcast).After(nextBlockMinedTime) {
log.Warn("too late to vote", "Head.Time(Second)", curHead.Time, "Now(Millisecond)", time.Now().UnixMilli())
continue
}
parentHeader := voteManager.chain.GetHeaderByHash(curHead.ParentHash)
blockInterval, _ := voteManager.engine.BlockInterval(voteManager.chain, parentHeader)
nextBlockMinedTime := time.Unix(int64((curHead.Time + blockInterval)), 0)
timeForBroadcast := 50 * time.Millisecond // enough to broadcast a vote
if time.Now().Add(timeForBroadcast).After(nextBlockMinedTime) {
log.Warn("too late to vote", "Head.Time(Second)", curHead.Time, "Now(Millisecond)", time.Now().UnixMilli())
continue
}

// Check if cur validator is within the validatorSet at curHead
Expand Down
4 changes: 4 additions & 0 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
chainConfig.PragueTime = config.OverridePrague
overrides.OverridePrague = config.OverridePrague
}
if config.OverrideLorentz != nil {
chainConfig.LorentzTime = config.OverrideLorentz
overrides.OverrideLorentz = config.OverrideLorentz
}
if config.OverrideVerkle != nil {
chainConfig.VerkleTime = config.OverrideVerkle
overrides.OverrideVerkle = config.OverrideVerkle
Expand Down
3 changes: 3 additions & 0 deletions eth/ethconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ type Config struct {
// OverridePrague (TODO: remove after the fork)
OverridePrague *uint64 `toml:",omitempty"`

// OverrideLorentz (TODO: remove after the fork)
OverrideLorentz *uint64 `toml:",omitempty"`

// OverrideVerkle (TODO: remove after the fork)
OverrideVerkle *uint64 `toml:",omitempty"`

Expand Down
6 changes: 6 additions & 0 deletions eth/ethconfig/gen_config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion miner/bid_simulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,8 @@ func (b *bidSimulator) newBidLoop() {

func (b *bidSimulator) bidBetterBefore(parentHash common.Hash) time.Time {
parentHeader := b.chain.GetHeaderByHash(parentHash)
return bidutil.BidBetterBefore(parentHeader, b.chainConfig.Parlia.Period, b.delayLeftOver, b.config.BidSimulationLeftOver)
blockInterval, _ := b.engine.BlockInterval(b.chain, parentHeader)
return bidutil.BidBetterBefore(parentHeader, blockInterval, b.delayLeftOver, b.config.BidSimulationLeftOver)
}

func (b *bidSimulator) clearLoop() {
Expand Down
7 changes: 4 additions & 3 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) {
// If sealing is running resubmit a new work cycle periodically to pull in
// higher priced transactions. Disable this overhead for pending blocks.
if w.isRunning() && ((w.chainConfig.Clique != nil &&
w.chainConfig.Clique.Period > 0) || (w.chainConfig.Parlia != nil && w.chainConfig.Parlia.Period > 0)) {
w.chainConfig.Clique.Period > 0) || (w.chainConfig.Parlia != nil)) {
// Short circuit if no new transaction arrives.
commit(commitInterruptResubmit)
}
Expand Down Expand Up @@ -1538,13 +1538,14 @@ func (w *worker) tryWaitProposalDoneWhenStopping() {
log.Warn("next proposal end block has passed, ignore")
return
}
if startBlock > currentBlock && (startBlock-currentBlock)*posa.BlockInterval() > w.config.MaxWaitProposalInSecs {
blockInterval, _ := w.engine.BlockInterval(w.chain, currentHeader)
if startBlock > currentBlock && (startBlock-currentBlock)*blockInterval > w.config.MaxWaitProposalInSecs {
log.Warn("the next proposal start block is too far, just skip waiting")
return
}

// wait one more block for safety
waitSecs := (endBlock - currentBlock + 1) * posa.BlockInterval()
waitSecs := (endBlock - currentBlock + 1) * blockInterval
log.Info("The miner will propose in later, waiting for the proposal to be done",
"currentBlock", currentBlock, "nextProposalStart", startBlock, "nextProposalEnd", endBlock, "waitTime", waitSecs)
time.Sleep(time.Duration(waitSecs) * time.Second)
Expand Down
Loading
Loading