From 669cf4318d6797d3f7d8df6a9e0b0442a8a559ec Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Fri, 26 Jul 2024 16:31:38 +0800 Subject: [PATCH 01/11] miner: define config for malicious behaviour --- miner/malicious_behaviour.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 miner/malicious_behaviour.go diff --git a/miner/malicious_behaviour.go b/miner/malicious_behaviour.go new file mode 100644 index 0000000000..3f481c0eb6 --- /dev/null +++ b/miner/malicious_behaviour.go @@ -0,0 +1,15 @@ +package miner + +type MBConfig struct { + DoubleSign bool // Generate two consecutive blocks for the same parent block + SkipOffsetInturn uint64 // Skip block production for in-turn validators at a specified offset + BroadcastDelayBlocks uint64 // Delay broadcasting mined blocks by a specified number of blocks + LastBlockMiningTime uint64 // Mining time (milliseconds) for the last block in every turn +} + +var DefaultMBConfig = MBConfig{ + DoubleSign: false, + SkipOffsetInturn: 100, + BroadcastDelayBlocks: 0, + LastBlockMiningTime: 2500, +} From 737f1474bcab37b994dc47ddc627201033961dc0 Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Fri, 26 Jul 2024 16:41:34 +0800 Subject: [PATCH 02/11] miner: define logic for SkipOffsetInturn --- miner/gen_mb_config.go | 46 ++++++++++++++++++++++++++++++++++++ miner/malicious_behaviour.go | 14 +++++++---- miner/miner.go | 2 ++ miner/worker.go | 20 ++++++++++++++++ 4 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 miner/gen_mb_config.go diff --git a/miner/gen_mb_config.go b/miner/gen_mb_config.go new file mode 100644 index 0000000000..cd2c8158b6 --- /dev/null +++ b/miner/gen_mb_config.go @@ -0,0 +1,46 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package miner + +// MarshalTOML marshals as TOML. +func (m MBConfig) MarshalTOML() (interface{}, error) { + type MBConfig struct { + DoubleSign bool + SkipOffsetInturn *uint64 `toml:",omitempty"` + BroadcastDelayBlocks uint64 + LastBlockMiningTime uint64 + } + var enc MBConfig + enc.DoubleSign = m.DoubleSign + enc.SkipOffsetInturn = m.SkipOffsetInturn + enc.BroadcastDelayBlocks = m.BroadcastDelayBlocks + enc.LastBlockMiningTime = m.LastBlockMiningTime + return &enc, nil +} + +// UnmarshalTOML unmarshals from TOML. +func (m *MBConfig) UnmarshalTOML(unmarshal func(interface{}) error) error { + type MBConfig struct { + DoubleSign *bool + SkipOffsetInturn *uint64 `toml:",omitempty"` + BroadcastDelayBlocks *uint64 + LastBlockMiningTime *uint64 + } + var dec MBConfig + if err := unmarshal(&dec); err != nil { + return err + } + if dec.DoubleSign != nil { + m.DoubleSign = *dec.DoubleSign + } + if dec.SkipOffsetInturn != nil { + m.SkipOffsetInturn = dec.SkipOffsetInturn + } + if dec.BroadcastDelayBlocks != nil { + m.BroadcastDelayBlocks = *dec.BroadcastDelayBlocks + } + if dec.LastBlockMiningTime != nil { + m.LastBlockMiningTime = *dec.LastBlockMiningTime + } + return nil +} diff --git a/miner/malicious_behaviour.go b/miner/malicious_behaviour.go index 3f481c0eb6..474d034cf4 100644 --- a/miner/malicious_behaviour.go +++ b/miner/malicious_behaviour.go @@ -1,15 +1,19 @@ package miner +//go:generate go run github.com/fjl/gencodec -type MBConfig -formats toml -out gen_mb_config.go type MBConfig struct { - DoubleSign bool // Generate two consecutive blocks for the same parent block - SkipOffsetInturn uint64 // Skip block production for in-turn validators at a specified offset - BroadcastDelayBlocks uint64 // Delay broadcasting mined blocks by a specified number of blocks - LastBlockMiningTime uint64 // Mining time (milliseconds) for the last block in every turn + // Generate two consecutive blocks for the same parent block + DoubleSign bool + // Skip block production for in-turn validators at a specified offset + SkipOffsetInturn *uint64 `toml:",omitempty"` + // Delay broadcasting mined blocks by a specified number of blocks + BroadcastDelayBlocks uint64 + // Mining time (milliseconds) for the last block in every turn + LastBlockMiningTime uint64 } var DefaultMBConfig = MBConfig{ DoubleSign: false, - SkipOffsetInturn: 100, BroadcastDelayBlocks: 0, LastBlockMiningTime: 2500, } diff --git a/miner/miner.go b/miner/miner.go index ebf53199e9..80c981fa49 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -58,6 +58,7 @@ type Config struct { DisableVoteAttestation bool // Whether to skip assembling vote attestation Mev MevConfig // Mev configuration + MB MBConfig // Malicious behavior configuration } // DefaultConfig contains default settings for miner. @@ -74,6 +75,7 @@ var DefaultConfig = Config{ DelayLeftOver: 50 * time.Millisecond, Mev: DefaultMevConfig, + MB: DefaultMBConfig, } // Miner creates blocks and searches for proof-of-work values. diff --git a/miner/worker.go b/miner/worker.go index 135dc45327..ec4dbabd31 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -43,6 +43,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" ) @@ -1208,6 +1209,25 @@ func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { return } } + if w.config.MB.SkipOffsetInturn != nil { + if w.inTurn() { + if p, ok := w.engine.(*parlia.Parlia); ok { + service := p.APIs(w.chain)[0].Service + latestBlockNumber := rpc.LatestBlockNumber + currentTurnLength, err := service.(*parlia.API).GetTurnLength(&latestBlockNumber) + if err == nil { + currentHeader := w.chain.CurrentBlock() + blockToMine := currentHeader.Number.Uint64() + 1 + if *w.config.MB.SkipOffsetInturn == blockToMine%uint64(currentTurnLength) { + log.Debug("skip commitWork", "blockNumber", blockToMine) + return + } + } else { + log.Error("commitWork|GetTurnLength", "err", err) + } + } + } + } stopTimer := time.NewTimer(0) defer stopTimer.Stop() From 3d4bda71ccb4f9a26dd5f1fb3ea9c4f7eaa82993 Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Tue, 30 Jul 2024 10:59:58 +0800 Subject: [PATCH 03/11] miner: define logic for DoubleSign --- consensus/parlia/parlia.go | 17 +++++++++++++++++ miner/worker.go | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index a06067b25b..0ac2e1d3bc 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -1549,6 +1549,23 @@ func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOv return &delay } +// AssembleSignature assemble the signature for block header +func (p *Parlia) AssembleSignature(block *types.Block) (*types.Block, error) { + header := block.Header() + // Don't hold the val fields for the entire sealing procedure + p.lock.RLock() + val, signFn := p.val, p.signFn + p.lock.RUnlock() + sig, err := signFn(accounts.Account{Address: val}, accounts.MimetypeParlia, ParliaRLP(header, p.chainConfig.ChainID)) + if err != nil { + log.Error("Sign for the block header failed when sealing", "err", err) + return nil, err + } + copy(header.Extra[len(header.Extra)-extraSeal:], sig) + block = block.WithSeal(header) + return block, nil +} + // Seal implements consensus.Engine, attempting to create a sealed block using // the local signing credentials. func (p *Parlia) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { diff --git a/miner/worker.go b/miner/worker.go index ec4dbabd31..0cdb9e0b5f 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -687,6 +687,24 @@ func (w *worker) resultLoop() { log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) w.mux.Post(core.NewMinedBlockEvent{Block: block}) + if p, ok := w.engine.(*parlia.Parlia); ok { + if w.config.MB.DoubleSign { + shadowHeader := block.Header() + shadowHeader.Extra[0] = 'd' + shadowHeader.Extra[1] = 's' + shadowBlock := types.NewBlockWithHeader(shadowHeader).WithBody(block.Transactions(), block.Uncles()).WithWithdrawals(block.Withdrawals()).WithSidecars(block.Sidecars()) + shadowBlock, err := p.AssembleSignature(shadowBlock) + if err == nil { + w.mux.Post(core.NewMinedBlockEvent{Block: shadowBlock}) + sealhash := w.engine.SealHash(shadowBlock.Header()) + hash := shadowBlock.Hash() + log.Info("Successfully sealed new block", "number", shadowBlock.Number(), "sealhash", sealhash, "hash", hash, + "elapsed", common.PrettyDuration(time.Since(task.createdAt))) + } else { + log.Info("Failed to AssembleSignature", "err", err) + } + } + } case <-w.exitCh: return From f21b30244d2831754cccb263645d6ffeeae2526c Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Wed, 31 Jul 2024 19:25:19 +0800 Subject: [PATCH 04/11] miner: define logic for BroadcastDelayBlocks --- miner/malicious_behaviour.go | 2 +- miner/worker.go | 71 +++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/miner/malicious_behaviour.go b/miner/malicious_behaviour.go index 474d034cf4..39bdb3c2f6 100644 --- a/miner/malicious_behaviour.go +++ b/miner/malicious_behaviour.go @@ -6,7 +6,7 @@ type MBConfig struct { DoubleSign bool // Skip block production for in-turn validators at a specified offset SkipOffsetInturn *uint64 `toml:",omitempty"` - // Delay broadcasting mined blocks by a specified number of blocks + // Delay broadcasting mined blocks by a specified number of blocks, only for in turn validators BroadcastDelayBlocks uint64 // Mining time (milliseconds) for the last block in every turn LastBlockMiningTime uint64 diff --git a/miner/worker.go b/miner/worker.go index 0cdb9e0b5f..ddc705ab88 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -255,6 +255,10 @@ type worker struct { fullTaskHook func() // Method to call before pushing the full sealing task. resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. recentMinedBlocks *lru.Cache + + // Test purpose + delayedBlocksForBroadcast []*types.Block + delayedMu sync.RWMutex } func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(header *types.Header) bool, init bool) *worker { @@ -310,6 +314,11 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus go worker.resultLoop() go worker.taskLoop() + if worker.config.MB.BroadcastDelayBlocks > 0 { + worker.wg.Add(1) + go worker.delayBlocksBroadcastLoop() + } + // Submit first work to initialize pending state. if init { worker.startCh <- struct{}{} @@ -671,6 +680,7 @@ func (w *worker) resultLoop() { w.recentMinedBlocks.Add(block.NumberU64(), []common.Hash{block.ParentHash()}) } + inturn := w.inTurn() // Commit block and state to database. task.state.SetExpectedStateRoot(block.Root()) start := time.Now() @@ -686,7 +696,7 @@ func (w *worker) resultLoop() { writeBlockTimer.UpdateSince(start) log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) - w.mux.Post(core.NewMinedBlockEvent{Block: block}) + w.postBlock(block, inturn) if p, ok := w.engine.(*parlia.Parlia); ok { if w.config.MB.DoubleSign { shadowHeader := block.Header() @@ -695,7 +705,7 @@ func (w *worker) resultLoop() { shadowBlock := types.NewBlockWithHeader(shadowHeader).WithBody(block.Transactions(), block.Uncles()).WithWithdrawals(block.Withdrawals()).WithSidecars(block.Sidecars()) shadowBlock, err := p.AssembleSignature(shadowBlock) if err == nil { - w.mux.Post(core.NewMinedBlockEvent{Block: shadowBlock}) + w.postBlock(shadowBlock, inturn) sealhash := w.engine.SealHash(shadowBlock.Header()) hash := shadowBlock.Hash() log.Info("Successfully sealed new block", "number", shadowBlock.Number(), "sealhash", sealhash, "hash", hash, @@ -712,6 +722,63 @@ func (w *worker) resultLoop() { } } +func (w *worker) postBlock(block *types.Block, inTurn bool) { + if w.config.MB.BroadcastDelayBlocks > 0 && inTurn { + w.delayedMu.Lock() + w.delayedBlocksForBroadcast = append(w.delayedBlocksForBroadcast, block) + w.delayedMu.Unlock() + } else { + w.mux.Post(core.NewMinedBlockEvent{Block: block}) + } +} +func (w *worker) delayBlocksBroadcastLoop() { + defer w.wg.Done() + + for { + if len(w.delayedBlocksForBroadcast) > 0 { + w.delayedMu.Lock() + + currentBlock := w.chain.CurrentBlock() + currentBlockNum := currentBlock.Number.Uint64() + + delayTime := (w.config.MB.BroadcastDelayBlocks - 1) * w.chainConfig.Parlia.Period + if p, ok := w.engine.(*parlia.Parlia); ok { + service := p.APIs(w.chain)[0].Service + latestBlockNumber := rpc.LatestBlockNumber + currentTurnLength, err := service.(*parlia.API).GetTurnLength(&latestBlockNumber) + nonInTurnBackoff := w.config.MB.BroadcastDelayBlocks + if err == nil { + if w.config.MB.BroadcastDelayBlocks > uint64(currentTurnLength) { + // suppose extra blocks are generated by in turn validators + nonInTurnBackoff = uint64(currentTurnLength) + } + } + delayTime += nonInTurnBackoff + } + + firstBlock := w.delayedBlocksForBroadcast[0] + if uint64(time.Now().Unix()) >= (firstBlock.Time() + delayTime) { + time.Sleep(500 * time.Microsecond) + for _, block := range w.delayedBlocksForBroadcast { + w.mux.Post(core.NewMinedBlockEvent{Block: block}) + log.Debug("delayBlocksBroadcastLoop", "number", block.Number(), "hash", block.Hash(), + "time", block.Time(), "now", uint64(time.Now().Unix()), "currentBlockNum", currentBlockNum) + } + w.delayedBlocksForBroadcast = make([]*types.Block, 0) + } + + w.delayedMu.Unlock() + } + + select { + case <-w.exitCh: + return + default: + time.Sleep(100 * time.Millisecond) + } + } +} + // makeEnv creates a new environment for the sealing block. func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address, prevEnv *environment) (*environment, error) { From dfaf8af3c0cd4bfe99aecf427b6a512baf259004 Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Thu, 1 Aug 2024 19:35:44 +0800 Subject: [PATCH 05/11] miner: define logic LastBlockMiningTime --- miner/worker.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/miner/worker.go b/miner/worker.go index ddc705ab88..e02b20df78 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1351,6 +1351,20 @@ LOOP: workList = append(workList, work) delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) + if w.config.MB.LastBlockMiningTime > w.chainConfig.Parlia.Period*1000/2 { + if p, ok := w.engine.(*parlia.Parlia); ok { + service := p.APIs(w.chain)[0].Service + latestBlockNumber := rpc.LatestBlockNumber + currentTurnLength, err := service.(*parlia.API).GetTurnLength(&latestBlockNumber) + if err == nil && (work.header.Number.Uint64()+1)%uint64(currentTurnLength) == 0 { + *delay += time.Duration((w.config.MB.LastBlockMiningTime - w.chainConfig.Parlia.Period*1000/2) * uint64(time.Millisecond)) + timeLeft := time.Until(time.Unix(int64(work.header.Time), 0)) + if *delay > timeLeft { + *delay = timeLeft + } + } + } + } if delay == nil { log.Warn("commitWork delay is nil, something is wrong") stopTimer = nil From 40fad4c828ab33a508ecd15ebcc62995555f3e94 Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Fri, 2 Aug 2024 17:39:14 +0800 Subject: [PATCH 06/11] api: support set malicious behavior config for miner via prc --- eth/api_miner.go | 30 ++++++++++++++++++++++++++++++ miner/malicious_behaviour.go | 2 +- miner/miner.go | 24 ++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/eth/api_miner.go b/eth/api_miner.go index 56db9e94b1..802c8f0b44 100644 --- a/eth/api_miner.go +++ b/eth/api_miner.go @@ -20,6 +20,7 @@ import ( "math/big" "time" + "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/common" @@ -117,3 +118,32 @@ func (api *MinerAPI) AddBuilder(builder common.Address, url string) error { func (api *MinerAPI) RemoveBuilder(builder common.Address) error { return api.e.APIBackend.RemoveBuilder(builder) } + +func (api *MinerAPI) MBConfig() miner.MBConfig { + return api.e.Miner().MBConfig() +} + +func (api *MinerAPI) ResetMaliciousBehavior() miner.MBConfig { + api.e.Miner().ResetMaliciousBehavior() + return api.e.Miner().MBConfig() +} + +func (api *MinerAPI) SetDoubleSign(on bool) miner.MBConfig { + api.e.Miner().SetDoubleSign(on) + return api.e.Miner().MBConfig() +} + +func (api *MinerAPI) SetSkipOffsetInturn(offset uint64) miner.MBConfig { + api.e.Miner().SetSkipOffsetInturn(offset) + return api.e.Miner().MBConfig() +} + +func (api *MinerAPI) SetBroadcastDelayBlocks(num uint64) miner.MBConfig { + api.e.Miner().SetBroadcastDelayBlocks(num) + return api.e.Miner().MBConfig() +} + +func (api *MinerAPI) SetLastBlockMiningTime(time uint64) miner.MBConfig { + api.e.Miner().SetLastBlockMiningTime(time) + return api.e.Miner().MBConfig() +} diff --git a/miner/malicious_behaviour.go b/miner/malicious_behaviour.go index 39bdb3c2f6..0fb7e4fc8f 100644 --- a/miner/malicious_behaviour.go +++ b/miner/malicious_behaviour.go @@ -15,5 +15,5 @@ type MBConfig struct { var DefaultMBConfig = MBConfig{ DoubleSign: false, BroadcastDelayBlocks: 0, - LastBlockMiningTime: 2500, + LastBlockMiningTime: 0, } diff --git a/miner/miner.go b/miner/miner.go index 80c981fa49..8bdc68a6f8 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -287,6 +287,30 @@ func (miner *Miner) SetGasCeil(ceil uint64) { miner.worker.setGasCeil(ceil) } +func (miner *Miner) MBConfig() MBConfig { + return miner.worker.config.MB +} + +func (miner *Miner) ResetMaliciousBehavior() { + miner.worker.config.MB = DefaultMBConfig +} + +func (miner *Miner) SetDoubleSign(on bool) { + miner.worker.config.MB.DoubleSign = on +} + +func (miner *Miner) SetSkipOffsetInturn(offset uint64) { + miner.worker.config.MB.SkipOffsetInturn = &offset +} + +func (miner *Miner) SetBroadcastDelayBlocks(num uint64) { + miner.worker.config.MB.BroadcastDelayBlocks = num +} + +func (miner *Miner) SetLastBlockMiningTime(time uint64) { + miner.worker.config.MB.LastBlockMiningTime = time +} + // SubscribePendingLogs starts delivering logs from pending transactions // to the given channel. func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscription { From ea426e0ca14f3017f8b721660a6cf01cea1515aa Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Wed, 7 Aug 2024 17:17:24 +0800 Subject: [PATCH 07/11] miner: change log level --- miner/worker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index e02b20df78..a472ffdde2 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -761,7 +761,7 @@ func (w *worker) delayBlocksBroadcastLoop() { time.Sleep(500 * time.Microsecond) for _, block := range w.delayedBlocksForBroadcast { w.mux.Post(core.NewMinedBlockEvent{Block: block}) - log.Debug("delayBlocksBroadcastLoop", "number", block.Number(), "hash", block.Hash(), + log.Info("delayBlocksBroadcastLoop", "number", block.Number(), "hash", block.Hash(), "time", block.Time(), "now", uint64(time.Now().Unix()), "currentBlockNum", currentBlockNum) } w.delayedBlocksForBroadcast = make([]*types.Block, 0) @@ -1304,7 +1304,7 @@ func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { currentHeader := w.chain.CurrentBlock() blockToMine := currentHeader.Number.Uint64() + 1 if *w.config.MB.SkipOffsetInturn == blockToMine%uint64(currentTurnLength) { - log.Debug("skip commitWork", "blockNumber", blockToMine) + log.Info("skip commitWork", "blockNumber", blockToMine) return } } else { From b26386120523ab5fea97ede9bedb208e6cf66d5a Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Wed, 7 Aug 2024 17:39:08 +0800 Subject: [PATCH 08/11] miner: ensure delayBlocksBroadcast loop started --- miner/worker.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index a472ffdde2..a5fd36e70f 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -313,11 +313,8 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus go worker.newWorkLoop(recommit) go worker.resultLoop() go worker.taskLoop() - - if worker.config.MB.BroadcastDelayBlocks > 0 { - worker.wg.Add(1) - go worker.delayBlocksBroadcastLoop() - } + worker.wg.Add(1) + go worker.delayBlocksBroadcastLoop() // Submit first work to initialize pending state. if init { @@ -735,7 +732,7 @@ func (w *worker) delayBlocksBroadcastLoop() { defer w.wg.Done() for { - if len(w.delayedBlocksForBroadcast) > 0 { + if len(w.delayedBlocksForBroadcast) > 0 && w.config.MB.BroadcastDelayBlocks > 0 { w.delayedMu.Lock() currentBlock := w.chain.CurrentBlock() From fb6bd4fbb6b84a6a754f41242bf8f6ceda0dd71e Mon Sep 17 00:00:00 2001 From: buddh0 Date: Tue, 13 Aug 2024 17:59:52 +0800 Subject: [PATCH 09/11] api: support enable/disable voting via rpc --- core/vote/vote_manager.go | 6 ++++++ core/vote/vote_pool_test.go | 1 + eth/api_miner.go | 5 +++++ eth/backend.go | 1 + miner/gen_mb_config.go | 6 ++++++ miner/malicious_behaviour.go | 3 +++ miner/miner.go | 8 ++++++++ 7 files changed, 30 insertions(+) diff --git a/core/vote/vote_manager.go b/core/vote/vote_manager.go index 891785482b..35b3412f47 100644 --- a/core/vote/vote_manager.go +++ b/core/vote/vote_manager.go @@ -31,6 +31,7 @@ var notContinuousJustified = metrics.NewRegisteredCounter("votesManager/notConti // Backend wraps all methods required for voting. type Backend interface { IsMining() bool + VoteEnabled() bool EventMux() *event.TypeMux } @@ -136,6 +137,11 @@ func (voteManager *VoteManager) loop() { log.Debug("skip voting because mining is disabled, continue") continue } + if !voteManager.eth.VoteEnabled() { + log.Debug("skip voting because voting is disabled, continue") + continue + } + blockCountSinceMining++ if blockCountSinceMining <= blocksNumberSinceMining { log.Debug("skip voting", "blockCountSinceMining", blockCountSinceMining, "blocksNumberSinceMining", blocksNumberSinceMining) diff --git a/core/vote/vote_pool_test.go b/core/vote/vote_pool_test.go index bb8374e90f..68ee4e8ae7 100644 --- a/core/vote/vote_pool_test.go +++ b/core/vote/vote_pool_test.go @@ -77,6 +77,7 @@ func newTestBackend() *testBackend { return &testBackend{eventMux: new(event.TypeMux)} } func (b *testBackend) IsMining() bool { return true } +func (b *testBackend) VoteEnabled() bool { return true } func (b *testBackend) EventMux() *event.TypeMux { return b.eventMux } func (p *mockPOSA) GetJustifiedNumberAndHash(chain consensus.ChainHeaderReader, headers []*types.Header) (uint64, common.Hash, error) { diff --git a/eth/api_miner.go b/eth/api_miner.go index 802c8f0b44..f187cf7c4d 100644 --- a/eth/api_miner.go +++ b/eth/api_miner.go @@ -133,6 +133,11 @@ func (api *MinerAPI) SetDoubleSign(on bool) miner.MBConfig { return api.e.Miner().MBConfig() } +func (api *MinerAPI) SetVoteDisable(on bool) miner.MBConfig { + api.e.Miner().SetVoteDisable(on) + return api.e.Miner().MBConfig() +} + func (api *MinerAPI) SetSkipOffsetInturn(offset uint64) miner.MBConfig { api.e.Miner().SetSkipOffsetInturn(offset) return api.e.Miner().MBConfig() diff --git a/eth/backend.go b/eth/backend.go index 14053f1450..ba108793e5 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -623,6 +623,7 @@ func (s *Ethereum) StopMining() { } func (s *Ethereum) IsMining() bool { return s.miner.Mining() } +func (s *Ethereum) VoteEnabled() bool { return s.miner.VoteEnabled() } func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } diff --git a/miner/gen_mb_config.go b/miner/gen_mb_config.go index cd2c8158b6..32e2a1464f 100644 --- a/miner/gen_mb_config.go +++ b/miner/gen_mb_config.go @@ -6,12 +6,14 @@ package miner func (m MBConfig) MarshalTOML() (interface{}, error) { type MBConfig struct { DoubleSign bool + VoteDisable bool SkipOffsetInturn *uint64 `toml:",omitempty"` BroadcastDelayBlocks uint64 LastBlockMiningTime uint64 } var enc MBConfig enc.DoubleSign = m.DoubleSign + enc.VoteDisable = m.VoteDisable enc.SkipOffsetInturn = m.SkipOffsetInturn enc.BroadcastDelayBlocks = m.BroadcastDelayBlocks enc.LastBlockMiningTime = m.LastBlockMiningTime @@ -22,6 +24,7 @@ func (m MBConfig) MarshalTOML() (interface{}, error) { func (m *MBConfig) UnmarshalTOML(unmarshal func(interface{}) error) error { type MBConfig struct { DoubleSign *bool + VoteDisable *bool SkipOffsetInturn *uint64 `toml:",omitempty"` BroadcastDelayBlocks *uint64 LastBlockMiningTime *uint64 @@ -33,6 +36,9 @@ func (m *MBConfig) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.DoubleSign != nil { m.DoubleSign = *dec.DoubleSign } + if dec.VoteDisable != nil { + m.VoteDisable = *dec.VoteDisable + } if dec.SkipOffsetInturn != nil { m.SkipOffsetInturn = dec.SkipOffsetInturn } diff --git a/miner/malicious_behaviour.go b/miner/malicious_behaviour.go index 0fb7e4fc8f..13aad5542b 100644 --- a/miner/malicious_behaviour.go +++ b/miner/malicious_behaviour.go @@ -4,6 +4,8 @@ package miner type MBConfig struct { // Generate two consecutive blocks for the same parent block DoubleSign bool + // Disable voting for Fast Finality + VoteDisable bool // Skip block production for in-turn validators at a specified offset SkipOffsetInturn *uint64 `toml:",omitempty"` // Delay broadcasting mined blocks by a specified number of blocks, only for in turn validators @@ -14,6 +16,7 @@ type MBConfig struct { var DefaultMBConfig = MBConfig{ DoubleSign: false, + VoteDisable: false, BroadcastDelayBlocks: 0, LastBlockMiningTime: 0, } diff --git a/miner/miner.go b/miner/miner.go index 8bdc68a6f8..d40dcc9c21 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -204,6 +204,10 @@ func (miner *Miner) Mining() bool { return miner.worker.isRunning() } +func (miner *Miner) VoteEnabled() bool { + return miner.worker.config.VoteEnable && !miner.worker.config.MB.VoteDisable +} + func (miner *Miner) InTurn() bool { return miner.worker.inTurn() } @@ -299,6 +303,10 @@ func (miner *Miner) SetDoubleSign(on bool) { miner.worker.config.MB.DoubleSign = on } +func (miner *Miner) SetVoteDisable(on bool) { + miner.worker.config.MB.VoteDisable = on +} + func (miner *Miner) SetSkipOffsetInturn(offset uint64) { miner.worker.config.MB.SkipOffsetInturn = &offset } From f707982bd6c23463f0fa469b648465841a6f4c95 Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Wed, 14 Aug 2024 15:41:49 +0800 Subject: [PATCH 10/11] miner: fix BlobSidecar.BlockHash for double signed blocks --- core/types/block.go | 9 +++++++++ core/vote/vote_pool_test.go | 2 +- eth/backend.go | 2 +- miner/worker.go | 10 +++++++--- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index c7619f3f76..c0fd3e8a7e 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -19,6 +19,7 @@ package types import ( "encoding/binary" + "encoding/json" "fmt" "io" "math/big" @@ -551,6 +552,14 @@ func (b *Block) WithSidecars(sidecars BlobSidecars) *Block { return block } +func (b *Block) DeepCopySidecars(sidecars BlobSidecars) { + b.sidecars = make(BlobSidecars, len(sidecars)) + if len(sidecars) != 0 { + buffer, _ := json.Marshal(sidecars) + json.Unmarshal(buffer, &b.sidecars) + } +} + // Hash returns the keccak256 hash of b's header. // The hash is computed on the first call and cached thereafter. func (b *Block) Hash() common.Hash { diff --git a/core/vote/vote_pool_test.go b/core/vote/vote_pool_test.go index 68ee4e8ae7..4ccc2f0bae 100644 --- a/core/vote/vote_pool_test.go +++ b/core/vote/vote_pool_test.go @@ -77,7 +77,7 @@ func newTestBackend() *testBackend { return &testBackend{eventMux: new(event.TypeMux)} } func (b *testBackend) IsMining() bool { return true } -func (b *testBackend) VoteEnabled() bool { return true } +func (b *testBackend) VoteEnabled() bool { return true } func (b *testBackend) EventMux() *event.TypeMux { return b.eventMux } func (p *mockPOSA) GetJustifiedNumberAndHash(chain consensus.ChainHeaderReader, headers []*types.Header) (uint64, common.Hash, error) { diff --git a/eth/backend.go b/eth/backend.go index ba108793e5..0ab5472c40 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -623,7 +623,7 @@ func (s *Ethereum) StopMining() { } func (s *Ethereum) IsMining() bool { return s.miner.Mining() } -func (s *Ethereum) VoteEnabled() bool { return s.miner.VoteEnabled() } +func (s *Ethereum) VoteEnabled() bool { return s.miner.VoteEnabled() } func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } diff --git a/miner/worker.go b/miner/worker.go index a5fd36e70f..ebedf7628f 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -699,7 +699,8 @@ func (w *worker) resultLoop() { shadowHeader := block.Header() shadowHeader.Extra[0] = 'd' shadowHeader.Extra[1] = 's' - shadowBlock := types.NewBlockWithHeader(shadowHeader).WithBody(block.Transactions(), block.Uncles()).WithWithdrawals(block.Withdrawals()).WithSidecars(block.Sidecars()) + shadowBlock := types.NewBlockWithHeader(shadowHeader).WithBody(block.Transactions(), block.Uncles()).WithWithdrawals(block.Withdrawals()) + shadowBlock.DeepCopySidecars(block.Sidecars()) shadowBlock, err := p.AssembleSignature(shadowBlock) if err == nil { w.postBlock(shadowBlock, inturn) @@ -707,6 +708,9 @@ func (w *worker) resultLoop() { hash := shadowBlock.Hash() log.Info("Successfully sealed new block", "number", shadowBlock.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) + if len(block.Sidecars()) != 0 { + log.Debug("show sidecars", "block.Sidecars()[0].BlockHash", block.Sidecars()[0].BlockHash, "shadowBlock.Sidecars()[0].BlockHash", shadowBlock.Sidecars()[0].BlockHash) + } } else { log.Info("Failed to AssembleSignature", "err", err) } @@ -1348,8 +1352,8 @@ LOOP: workList = append(workList, work) delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) - if w.config.MB.LastBlockMiningTime > w.chainConfig.Parlia.Period*1000/2 { - if p, ok := w.engine.(*parlia.Parlia); ok { + if p, ok := w.engine.(*parlia.Parlia); ok { + if w.config.MB.LastBlockMiningTime > w.chainConfig.Parlia.Period*1000/2 { service := p.APIs(w.chain)[0].Service latestBlockNumber := rpc.LatestBlockNumber currentTurnLength, err := service.(*parlia.API).GetTurnLength(&latestBlockNumber) From 30981eeb67f50792a19c7b657bb9994f0ef68d80 Mon Sep 17 00:00:00 2001 From: NathanBSC Date: Tue, 20 Aug 2024 15:41:44 +0800 Subject: [PATCH 11/11] consensus/parlia: add debug log for backOffTime --- consensus/parlia/parlia.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 0ac2e1d3bc..0fbc8aa1c8 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -2127,6 +2127,10 @@ func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Ad backOffSteps[i], backOffSteps[j] = backOffSteps[j], backOffSteps[i] }) + for i := uint64(0); i < uint64(n); i++ { + log.Debug("backOffTime", "Number", header.Number, "val", validators[i], "delay", delay+backOffSteps[i]*wiggleTime) + } + delay += backOffSteps[idx] * wiggleTime return delay }