mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-16 01:40:44 +00:00
stop reorg at committed blocks (#276)
This PR makes committed blocks non-reorg-able inside `Blockchain` struct. This ensures V2 consensus safety property in the aspect of blockchain head: committed blocks' state will not be reorg and users will always see committed blocks (or their child blocks) as current head of the blockchain. * stop reorg at committed blocks * fix tests * fix tests
This commit is contained in:
parent
2df16bbd37
commit
d578e092cd
2 changed files with 79 additions and 0 deletions
54
consensus/tests/engine_v2_tests/commit_test.go
Normal file
54
consensus/tests/engine_v2_tests/commit_test.go
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
package engine_v2_tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNormalReorgWhenNotInvolveCommittedBlock(t *testing.T) {
|
||||||
|
// create 3 forking blockss, so the committed block is not in the forking numbers
|
||||||
|
var numOfForks = new(int)
|
||||||
|
*numOfForks = 3
|
||||||
|
blockchain, _, currentBlock, signer, signFn, forkedBlock := PrepareXDCTestBlockChainForV2Engine(t, 906, params.TestXDPoSMockChainConfig, &ForkedBlockOptions{numOfForkedBlocks: numOfForks})
|
||||||
|
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||||
|
|
||||||
|
var extraField types.ExtraFields_v2
|
||||||
|
err := utils.DecodeBytesExtraFields(currentBlock.Extra(), &extraField)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Fail to decode extra data", err)
|
||||||
|
}
|
||||||
|
engineV2.ProcessQCFaker(blockchain, extraField.QuorumCert)
|
||||||
|
assert.Equal(t, uint64(903), engineV2.GetLatestCommittedBlockInfo().Number.Uint64())
|
||||||
|
blockCoinBase := "0x111000000000000000000000000000000123"
|
||||||
|
newBlock := CreateBlock(blockchain, params.TestXDPoSMockChainConfig, forkedBlock, int(forkedBlock.NumberU64())+1, int64(extraField.Round)+10, blockCoinBase, signer, signFn, nil, nil, forkedBlock.Header().Root.Hex())
|
||||||
|
err = blockchain.InsertBlock(newBlock)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldNotReorgCommittedBlock(t *testing.T) {
|
||||||
|
// create 4 forking blocks, so the committed block is in the forking numbers
|
||||||
|
var numOfForks = new(int)
|
||||||
|
*numOfForks = 4
|
||||||
|
blockchain, _, currentBlock, signer, signFn, forkedBlock := PrepareXDCTestBlockChainForV2Engine(t, 906, params.TestXDPoSMockChainConfig, &ForkedBlockOptions{numOfForkedBlocks: numOfForks})
|
||||||
|
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||||
|
|
||||||
|
var extraField types.ExtraFields_v2
|
||||||
|
err := utils.DecodeBytesExtraFields(currentBlock.Extra(), &extraField)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Fail to decode extra data", err)
|
||||||
|
}
|
||||||
|
engineV2.ProcessQCFaker(blockchain, extraField.QuorumCert)
|
||||||
|
assert.Equal(t, uint64(903), engineV2.GetLatestCommittedBlockInfo().Number.Uint64())
|
||||||
|
blockCoinBase := "0x111000000000000000000000000000000123"
|
||||||
|
newBlock := CreateBlock(blockchain, params.TestXDPoSMockChainConfig, forkedBlock, int(forkedBlock.NumberU64())+1, int64(extraField.Round)+10, blockCoinBase, signer, signFn, nil, nil, forkedBlock.Header().Root.Hex())
|
||||||
|
err = blockchain.InsertBlock(newBlock)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.True(t, strings.Contains(err.Error(), "reorg"))
|
||||||
|
assert.True(t, strings.Contains(err.Error(), "attack"))
|
||||||
|
}
|
||||||
|
|
@ -2200,6 +2200,31 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||||
return fmt.Errorf("Invalid new chain")
|
return fmt.Errorf("Invalid new chain")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Ensure XDPoS engine committed block will be not reverted
|
||||||
|
if xdpos, ok := bc.Engine().(*XDPoS.XDPoS); ok {
|
||||||
|
latestCommittedBlock := xdpos.EngineV2.GetLatestCommittedBlockInfo()
|
||||||
|
if latestCommittedBlock != nil {
|
||||||
|
currentBlock := bc.CurrentBlock()
|
||||||
|
currentBlock.Number().Cmp(latestCommittedBlock.Number)
|
||||||
|
cmp := commonBlock.Number().Cmp(latestCommittedBlock.Number)
|
||||||
|
if cmp < 0 {
|
||||||
|
for _, oldBlock := range oldChain {
|
||||||
|
if oldBlock.Number().Cmp(latestCommittedBlock.Number) == 0 {
|
||||||
|
if oldBlock.Hash() != latestCommittedBlock.Hash {
|
||||||
|
log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "committed hash", latestCommittedBlock.Hash)
|
||||||
|
} else {
|
||||||
|
log.Warn("Stop reorg, blockchain is under forking attack", "old committed num", oldBlock.Number(), "old committed hash", oldBlock.Hash())
|
||||||
|
return fmt.Errorf("stop reorg, blockchain is under forking attack. old committed num %d, hash %x", oldBlock.Number(), oldBlock.Hash())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if cmp == 0 {
|
||||||
|
if commonBlock.Hash() != latestCommittedBlock.Hash {
|
||||||
|
log.Error("Impossible reorg, please file an issue", "oldnum", commonBlock.Number(), "oldhash", commonBlock.Hash(), "committed hash", latestCommittedBlock.Hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Ensure the user sees large reorgs
|
// Ensure the user sees large reorgs
|
||||||
if len(oldChain) > 0 && len(newChain) > 0 {
|
if len(oldChain) > 0 && len(newChain) > 0 {
|
||||||
logFn := log.Warn
|
logFn := log.Warn
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue