Skip to content

Commit f711fc8

Browse files
committed
dbft: Implement block verification callback. Close #65
1 parent 7b56bf7 commit f711fc8

File tree

4 files changed

+94
-0
lines changed

4 files changed

+94
-0
lines changed

consensus/dbft/block.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,14 @@ func (b *Block) Verify(pub crypto.PublicKey, sign []byte) error {
119119
func (b *Block) Hash() util.Uint256 {
120120
return WorkerSealHash(b.header).Uint256()
121121
}
122+
123+
// Convert dbft.Blcok to types.Block
124+
func (b *Block) ToEthBlock() *types.Block {
125+
res := types.NewBlockWithHeader(b.header)
126+
// Uncles are always nil in dBFT-like consensus.
127+
res = res.WithBody(b.transactions, nil)
128+
if b.withdrawals != nil {
129+
res = res.WithWithdrawals(b.withdrawals)
130+
}
131+
return res
132+
}

consensus/dbft/chainreader.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/ethereum/go-ethereum/common"
55
"github.com/ethereum/go-ethereum/consensus"
66
"github.com/ethereum/go-ethereum/core"
7+
"github.com/ethereum/go-ethereum/core/state"
78
"github.com/ethereum/go-ethereum/core/types"
89
"github.com/ethereum/go-ethereum/event"
910
)
@@ -15,6 +16,7 @@ type ChainHeaderReader interface {
1516
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
1617
HasBlock(hash common.Hash, number uint64) bool
1718
GetBlockByNumber(uint64) *types.Block
19+
VerifyBlock(block *types.Block) (*state.StateDB, types.Receipts, error)
1820
}
1921

2022
// ChainHeaderWriter is a Blockchain API abstraction needed for proper blockQueue

consensus/dbft/dbft.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,30 @@ func New(config *params.DBFTConfig, _ ethdb.Database) (*DBFT, error) {
550550

551551
return nil
552552
}),
553+
dbft.WithVerifyBlock(func(b block.Block) bool {
554+
dbftBlock := b.(*Block)
555+
parent := c.chain.CurrentBlock()
556+
if parent.Number.Cmp(dbftBlock.header.Number) >= 0 {
557+
log.Warn("proposed block has already outdated",
558+
"current block number", parent.Number.Uint64(),
559+
"proposed block number", dbftBlock.header.Number)
560+
return false
561+
}
562+
if c.lastTimestamp > dbftBlock.header.Time {
563+
log.Warn("proposed block has small timestamp",
564+
"ts", dbftBlock.header.Time,
565+
"last", c.lastTimestamp)
566+
return false
567+
}
568+
ethBlock := dbftBlock.ToEthBlock()
569+
_, _, err := c.chain.VerifyBlock(ethBlock)
570+
if err != nil {
571+
log.Warn("proposed block verification failed",
572+
"err", err.Error())
573+
return false
574+
}
575+
return true
576+
}),
553577
dbft.WithBroadcast(func(p payload.ConsensusPayload) {
554578
if err := p.(*Payload).Sign(c.dbft.Priv.(*Signer)); err != nil {
555579
log.Warn("can't sign consensus payload", "error", err)

core/blockchain.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2451,3 +2451,60 @@ func (bc *BlockChain) SetTrieFlushInterval(interval time.Duration) {
24512451
func (bc *BlockChain) GetTrieFlushInterval() time.Duration {
24522452
return time.Duration(bc.flushInterval.Load())
24532453
}
2454+
2455+
// ProcessState processes the state changes according to the Ethereum rules by running
2456+
// the transaction messages using the statedb and applying any rewards to both
2457+
// the processor (coinbase) and any included uncles. It doesn't persist any data.
2458+
func (bc *BlockChain) ProcessState(block *types.Block) (*state.StateDB, types.Receipts, []*types.Log, uint64, error) {
2459+
parent := bc.GetBlockByHash(block.ParentHash())
2460+
if parent == nil {
2461+
err := fmt.Errorf("failed to retrieve parent by hash to process block, %s: %v, %s: %s", "parent number", block.NumberU64()-1,
2462+
"parent hash", block.ParentHash().String())
2463+
log.Error(err.Error())
2464+
parent = bc.GetBlockByNumber(block.NumberU64() - 1)
2465+
if parent == nil {
2466+
err = fmt.Errorf("failed to retrieve canonical parent by number to process block, %s: %v, %s: %s", "parent number", block.NumberU64()-1,
2467+
"parent hash", block.ParentHash().String())
2468+
log.Error(err.Error())
2469+
return nil, nil, nil, 0, err
2470+
}
2471+
}
2472+
statedb, err := bc.StateAt(parent.Root())
2473+
if err != nil {
2474+
err = fmt.Errorf("failed to retrieve state at %s: %w", parent.Root(), err)
2475+
log.Error(err.Error())
2476+
return nil, nil, nil, 0, err
2477+
}
2478+
2479+
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
2480+
if err != nil {
2481+
err = fmt.Errorf("failed to process block: %w", err)
2482+
log.Error(err.Error())
2483+
return nil, nil, nil, 0, err
2484+
}
2485+
return statedb, receipts, logs, usedGas, nil
2486+
}
2487+
2488+
// VerifyBlock checks block state
2489+
func (bc *BlockChain) VerifyBlock(block *types.Block) (*state.StateDB, types.Receipts, error) {
2490+
err := bc.validator.ValidateBody(block)
2491+
if err != nil {
2492+
err = fmt.Errorf("failed to validate body: %w", err)
2493+
log.Error(err.Error())
2494+
return nil, nil, err
2495+
}
2496+
2497+
statedb, receipts, _, usedGas, err := bc.ProcessState(block)
2498+
if err != nil {
2499+
err = fmt.Errorf("failed to process block state: %w", err)
2500+
log.Error(err.Error())
2501+
return nil, nil, err
2502+
}
2503+
2504+
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
2505+
err = fmt.Errorf("failed to verify state: %w", err)
2506+
log.Error(err.Error())
2507+
return nil, nil, err
2508+
}
2509+
return statedb, receipts, nil
2510+
}

0 commit comments

Comments
 (0)