Unverified Commit b818e73e authored by Martin Holst Swende's avatar Martin Holst Swende Committed by GitHub

tests: update tests (#26314)

This PR builds on #26299, but also updates the tests to the most recent version, which includes tests regarding TheMerge.

This change adds checks to the beacon consensus engine, making it more strict in validating the pre- and post-headers, and not relying on the caller to have already correctly sanitized the headers/blocks. 
parent 79a478bb
This diff is collapsed.
...@@ -230,7 +230,7 @@ func TestT8n(t *testing.T) { ...@@ -230,7 +230,7 @@ func TestT8n(t *testing.T) {
{ // Test post-merge transition { // Test post-merge transition
base: "./testdata/24", base: "./testdata/24",
input: t8nInput{ input: t8nInput{
"alloc.json", "txs.json", "env.json", "Merged", "", "alloc.json", "txs.json", "env.json", "Merge", "",
}, },
output: t8nOutput{alloc: true, result: true}, output: t8nOutput{alloc: true, result: true},
expOut: "exp.json", expOut: "exp.json",
...@@ -238,7 +238,7 @@ func TestT8n(t *testing.T) { ...@@ -238,7 +238,7 @@ func TestT8n(t *testing.T) {
{ // Test post-merge transition where input is missing random { // Test post-merge transition where input is missing random
base: "./testdata/24", base: "./testdata/24",
input: t8nInput{ input: t8nInput{
"alloc.json", "txs.json", "env-missingrandom.json", "Merged", "", "alloc.json", "txs.json", "env-missingrandom.json", "Merge", "",
}, },
output: t8nOutput{alloc: false, result: false}, output: t8nOutput{alloc: false, result: false},
expExitCode: 3, expExitCode: 3,
...@@ -246,7 +246,7 @@ func TestT8n(t *testing.T) { ...@@ -246,7 +246,7 @@ func TestT8n(t *testing.T) {
{ // Test base fee calculation { // Test base fee calculation
base: "./testdata/25", base: "./testdata/25",
input: t8nInput{ input: t8nInput{
"alloc.json", "txs.json", "env.json", "Merged", "", "alloc.json", "txs.json", "env.json", "Merge", "",
}, },
output: t8nOutput{alloc: true, result: true}, output: t8nOutput{alloc: true, result: true},
expOut: "exp.json", expOut: "exp.json",
......
This diff is collapsed.
...@@ -95,44 +95,71 @@ func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *ty ...@@ -95,44 +95,71 @@ func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *ty
return beacon.verifyHeader(chain, header, parent) return beacon.verifyHeader(chain, header, parent)
} }
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers // errOut constructs an error channel with prefilled errors inside.
// concurrently. The method returns a quit channel to abort the operations and func errOut(n int, err error) chan error {
// a results channel to retrieve the async verifications. errs := make(chan error, n)
// VerifyHeaders expect the headers to be ordered and continuous. for i := 0; i < n; i++ {
func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { errs <- err
if !beacon.IsPoSHeader(headers[len(headers)-1]) { }
return beacon.ethone.VerifyHeaders(chain, headers, seals) return errs
}
// splitHeaders splits the provided header batch into two parts according to
// the configured ttd. It requires the parent of header batch along with its
// td are stored correctly in chain. If ttd is not configured yet, all headers
// will be treated legacy PoW headers.
// Note, this function will not verify the header validity but just split them.
func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) ([]*types.Header, []*types.Header, error) {
// TTD is not defined yet, all headers should be in legacy format.
ttd := chain.Config().TerminalTotalDifficulty
if ttd == nil {
return headers, nil, nil
}
ptd := chain.GetTd(headers[0].ParentHash, headers[0].Number.Uint64()-1)
if ptd == nil {
return nil, nil, consensus.ErrUnknownAncestor
}
// The entire header batch already crosses the transition.
if ptd.Cmp(ttd) >= 0 {
return nil, headers, nil
} }
var ( var (
preHeaders []*types.Header preHeaders = headers
postHeaders []*types.Header postHeaders []*types.Header
preSeals []bool td = new(big.Int).Set(ptd)
tdPassed bool
) )
for index, header := range headers { for i, header := range headers {
if beacon.IsPoSHeader(header) { if tdPassed {
preHeaders = headers[:index] preHeaders = headers[:i]
postHeaders = headers[index:] postHeaders = headers[i:]
preSeals = seals[:index]
break break
} }
td = td.Add(td, header.Difficulty)
if td.Cmp(ttd) >= 0 {
// This is the last PoW header, it still belongs to
// the preHeaders, so we cannot split+break yet.
tdPassed = true
} }
if len(preHeaders) == 0 {
// All the headers are pos headers. Verify that the parent block reached total terminal difficulty.
if reached, err := IsTTDReached(chain, headers[0].ParentHash, headers[0].Number.Uint64()-1); !reached {
// TTD not reached for the first block, mark subsequent with invalid terminal block
if err == nil {
err = consensus.ErrInvalidTerminalBlock
} }
results := make(chan error, len(headers)) return preHeaders, postHeaders, nil
for i := 0; i < len(headers); i++ { }
results <- err
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
// concurrently. The method returns a quit channel to abort the operations and
// a results channel to retrieve the async verifications.
// VerifyHeaders expect the headers to be ordered and continuous.
func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
preHeaders, postHeaders, err := beacon.splitHeaders(chain, headers)
if err != nil {
return make(chan struct{}), errOut(len(headers), err)
} }
return make(chan struct{}), results if len(postHeaders) == 0 {
return beacon.ethone.VerifyHeaders(chain, headers, seals)
} }
if len(preHeaders) == 0 {
return beacon.verifyHeaders(chain, headers, nil) return beacon.verifyHeaders(chain, headers, nil)
} }
// The transition point exists in the middle, separate the headers // The transition point exists in the middle, separate the headers
// into two batches and apply different verification rules for them. // into two batches and apply different verification rules for them.
var ( var (
...@@ -144,16 +171,9 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ ...@@ -144,16 +171,9 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [
old, new, out = 0, len(preHeaders), 0 old, new, out = 0, len(preHeaders), 0
errors = make([]error, len(headers)) errors = make([]error, len(headers))
done = make([]bool, len(headers)) done = make([]bool, len(headers))
oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders, preSeals) oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders, seals[:len(preHeaders)])
newDone, newResult = beacon.verifyHeaders(chain, postHeaders, preHeaders[len(preHeaders)-1]) newDone, newResult = beacon.verifyHeaders(chain, postHeaders, preHeaders[len(preHeaders)-1])
) )
// Verify that pre-merge headers don't overflow the TTD
if index, err := verifyTerminalPoWBlock(chain, preHeaders); err != nil {
// Mark all subsequent pow headers with the error.
for i := index; i < len(preHeaders); i++ {
errors[i], done[i] = err, true
}
}
// Collect the results // Collect the results
for { for {
for ; done[out]; out++ { for ; done[out]; out++ {
...@@ -181,33 +201,6 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ ...@@ -181,33 +201,6 @@ func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers [
return abort, results return abort, results
} }
// verifyTerminalPoWBlock verifies that the preHeaders conform to the specification
// wrt. their total difficulty.
// It expects:
// - preHeaders to be at least 1 element
// - the parent of the header element to be stored in the chain correctly
// - the preHeaders to have a set difficulty
// - the last element to be the terminal block
func verifyTerminalPoWBlock(chain consensus.ChainHeaderReader, preHeaders []*types.Header) (int, error) {
td := chain.GetTd(preHeaders[0].ParentHash, preHeaders[0].Number.Uint64()-1)
if td == nil {
return 0, consensus.ErrUnknownAncestor
}
td = new(big.Int).Set(td)
// Check that all blocks before the last one are below the TTD
for i, head := range preHeaders {
if td.Cmp(chain.Config().TerminalTotalDifficulty) >= 0 {
return i, consensus.ErrInvalidTerminalBlock
}
td.Add(td, head.Difficulty)
}
// Check that the last block is the terminal block
if td.Cmp(chain.Config().TerminalTotalDifficulty) < 0 {
return len(preHeaders) - 1, consensus.ErrInvalidTerminalBlock
}
return 0, nil
}
// VerifyUncles verifies that the given block's uncles conform to the consensus // VerifyUncles verifies that the given block's uncles conform to the consensus
// rules of the Ethereum consensus engine. // rules of the Ethereum consensus engine.
func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
...@@ -419,11 +412,11 @@ func (beacon *Beacon) SetThreads(threads int) { ...@@ -419,11 +412,11 @@ func (beacon *Beacon) SetThreads(threads int) {
// IsTTDReached checks if the TotalTerminalDifficulty has been surpassed on the `parentHash` block. // IsTTDReached checks if the TotalTerminalDifficulty has been surpassed on the `parentHash` block.
// It depends on the parentHash already being stored in the database. // It depends on the parentHash already being stored in the database.
// If the parentHash is not stored in the database a UnknownAncestor error is returned. // If the parentHash is not stored in the database a UnknownAncestor error is returned.
func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, number uint64) (bool, error) { func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, parentNumber uint64) (bool, error) {
if chain.Config().TerminalTotalDifficulty == nil { if chain.Config().TerminalTotalDifficulty == nil {
return false, nil return false, nil
} }
td := chain.GetTd(parentHash, number) td := chain.GetTd(parentHash, parentNumber)
if td == nil { if td == nil {
return false, consensus.ErrUnknownAncestor return false, consensus.ErrUnknownAncestor
} }
......
package beacon
import (
"fmt"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
type mockChain struct {
config *params.ChainConfig
tds map[uint64]*big.Int
}
func newMockChain() *mockChain {
return &mockChain{
config: new(params.ChainConfig),
tds: make(map[uint64]*big.Int),
}
}
func (m *mockChain) Config() *params.ChainConfig {
return m.config
}
func (m *mockChain) CurrentHeader() *types.Header { panic("not implemented") }
func (m *mockChain) GetHeader(hash common.Hash, number uint64) *types.Header {
panic("not implemented")
}
func (m *mockChain) GetHeaderByNumber(number uint64) *types.Header { panic("not implemented") }
func (m *mockChain) GetHeaderByHash(hash common.Hash) *types.Header { panic("not implemented") }
func (m *mockChain) GetTd(hash common.Hash, number uint64) *big.Int {
num, ok := m.tds[number]
if ok {
return new(big.Int).Set(num)
}
return nil
}
func TestVerifyTerminalBlock(t *testing.T) {
chain := newMockChain()
chain.tds[0] = big.NewInt(10)
chain.config.TerminalTotalDifficulty = big.NewInt(50)
tests := []struct {
preHeaders []*types.Header
ttd *big.Int
err error
index int
}{
// valid ttd
{
preHeaders: []*types.Header{
{Number: big.NewInt(1), Difficulty: big.NewInt(10)},
{Number: big.NewInt(2), Difficulty: big.NewInt(10)},
{Number: big.NewInt(3), Difficulty: big.NewInt(10)},
{Number: big.NewInt(4), Difficulty: big.NewInt(10)},
},
ttd: big.NewInt(50),
},
// last block doesn't reach ttd
{
preHeaders: []*types.Header{
{Number: big.NewInt(1), Difficulty: big.NewInt(10)},
{Number: big.NewInt(2), Difficulty: big.NewInt(10)},
{Number: big.NewInt(3), Difficulty: big.NewInt(10)},
{Number: big.NewInt(4), Difficulty: big.NewInt(9)},
},
ttd: big.NewInt(50),
err: consensus.ErrInvalidTerminalBlock,
index: 3,
},
// two blocks reach ttd
{
preHeaders: []*types.Header{
{Number: big.NewInt(1), Difficulty: big.NewInt(10)},
{Number: big.NewInt(2), Difficulty: big.NewInt(10)},
{Number: big.NewInt(3), Difficulty: big.NewInt(20)},
{Number: big.NewInt(4), Difficulty: big.NewInt(10)},
},
ttd: big.NewInt(50),
err: consensus.ErrInvalidTerminalBlock,
index: 3,
},
// three blocks reach ttd
{
preHeaders: []*types.Header{
{Number: big.NewInt(1), Difficulty: big.NewInt(10)},
{Number: big.NewInt(2), Difficulty: big.NewInt(10)},
{Number: big.NewInt(3), Difficulty: big.NewInt(20)},
{Number: big.NewInt(4), Difficulty: big.NewInt(10)},
{Number: big.NewInt(4), Difficulty: big.NewInt(10)},
},
ttd: big.NewInt(50),
err: consensus.ErrInvalidTerminalBlock,
index: 3,
},
// parent reached ttd
{
preHeaders: []*types.Header{
{Number: big.NewInt(1), Difficulty: big.NewInt(10)},
},
ttd: big.NewInt(9),
err: consensus.ErrInvalidTerminalBlock,
index: 0,
},
// unknown parent
{
preHeaders: []*types.Header{
{Number: big.NewInt(4), Difficulty: big.NewInt(10)},
},
ttd: big.NewInt(9),
err: consensus.ErrUnknownAncestor,
index: 0,
},
}
for i, test := range tests {
fmt.Printf("Test: %v\n", i)
chain.config.TerminalTotalDifficulty = test.ttd
index, err := verifyTerminalPoWBlock(chain, test.preHeaders)
if err != test.err {
t.Fatalf("Invalid error encountered, expected %v got %v", test.err, err)
}
if index != test.index {
t.Fatalf("Invalid index, expected %v got %v", test.index, index)
}
}
}
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
package core package core
import ( import (
"encoding/json"
"math/big" "math/big"
"runtime" "runtime"
"testing" "testing"
...@@ -135,31 +134,29 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { ...@@ -135,31 +134,29 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
config := *params.TestChainConfig config := *params.TestChainConfig
gspec = &Genesis{Config: &config} gspec = &Genesis{Config: &config}
engine = beacon.New(ethash.NewFaker()) engine = beacon.New(ethash.NewFaker())
td := int(params.GenesisDifficulty.Uint64())
td := 0
genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 8, nil) genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 8, nil)
for _, block := range preBlocks { for _, block := range blocks {
// calculate td // calculate td
td += int(block.Difficulty().Uint64()) td += int(block.Difficulty().Uint64())
} }
preBlocks = blocks preBlocks = blocks
gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(td)) gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(td))
postBlocks, _ = GenerateChain(gspec.Config, preBlocks[len(preBlocks)-1], engine, genDb, 8, nil) t.Logf("Set ttd to %v\n", gspec.Config.TerminalTotalDifficulty)
postBlocks, _ = GenerateChain(gspec.Config, preBlocks[len(preBlocks)-1], engine, genDb, 8, func(i int, gen *BlockGen) {
gen.SetPoS()
})
} }
// Assemble header batch // Assemble header batch
preHeaders := make([]*types.Header, len(preBlocks)) preHeaders := make([]*types.Header, len(preBlocks))
for i, block := range preBlocks { for i, block := range preBlocks {
preHeaders[i] = block.Header() preHeaders[i] = block.Header()
t.Logf("Pre-merge header: %d", block.NumberU64())
blob, _ := json.Marshal(block.Header())
t.Logf("Log header before the merging %d: %v", block.NumberU64(), string(blob))
} }
postHeaders := make([]*types.Header, len(postBlocks)) postHeaders := make([]*types.Header, len(postBlocks))
for i, block := range postBlocks { for i, block := range postBlocks {
postHeaders[i] = block.Header() postHeaders[i] = block.Header()
t.Logf("Post-merge header: %d", block.NumberU64())
blob, _ := json.Marshal(block.Header())
t.Logf("Log header after the merging %d: %v", block.NumberU64(), string(blob))
} }
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil)
...@@ -172,15 +169,15 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { ...@@ -172,15 +169,15 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
select { select {
case result := <-results: case result := <-results:
if result != nil { if result != nil {
t.Errorf("test %d: verification failed %v", i, result) t.Errorf("pre-block %d: verification failed %v", i, result)
} }
case <-time.After(time.Second): case <-time.After(time.Second):
t.Fatalf("test %d: verification timeout", i) t.Fatalf("pre-block %d: verification timeout", i)
} }
// Make sure no more data is returned // Make sure no more data is returned
select { select {
case result := <-results: case result := <-results:
t.Fatalf("test %d: unexpected result returned: %v", i, result) t.Fatalf("pre-block %d: unexpected result returned: %v", i, result)
case <-time.After(25 * time.Millisecond): case <-time.After(25 * time.Millisecond):
} }
chain.InsertChain(preBlocks[i : i+1]) chain.InsertChain(preBlocks[i : i+1])
...@@ -197,7 +194,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { ...@@ -197,7 +194,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
select { select {
case result := <-results: case result := <-results:
if result != nil { if result != nil {
t.Errorf("test %d: verification failed %v", i, result) t.Errorf("post-block %d: verification failed %v", i, result)
} }
case <-time.After(time.Second): case <-time.After(time.Second):
t.Fatalf("test %d: verification timeout", i) t.Fatalf("test %d: verification timeout", i)
...@@ -205,7 +202,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { ...@@ -205,7 +202,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
// Make sure no more data is returned // Make sure no more data is returned
select { select {
case result := <-results: case result := <-results:
t.Fatalf("test %d: unexpected result returned: %v", i, result) t.Fatalf("post-block %d: unexpected result returned: %v", i, result)
case <-time.After(25 * time.Millisecond): case <-time.After(25 * time.Millisecond):
} }
chain.InsertBlockWithoutSetHead(postBlocks[i]) chain.InsertBlockWithoutSetHead(postBlocks[i])
......
...@@ -1960,6 +1960,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon ...@@ -1960,6 +1960,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
signer = types.LatestSigner(gspec.Config) signer = types.LatestSigner(gspec.Config)
mergeBlock = math.MaxInt32
) )
// Generate and import the canonical chain // Generate and import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil)
...@@ -1970,6 +1971,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon ...@@ -1970,6 +1971,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
// Activate the transition since genesis if required // Activate the transition since genesis if required
if mergePoint == 0 { if mergePoint == 0 {
mergeBlock = 0
merger.ReachTTD() merger.ReachTTD()
merger.FinalizePoS() merger.FinalizePoS()
...@@ -1982,6 +1984,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon ...@@ -1982,6 +1984,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
t.Fatalf("failed to create tx: %v", err) t.Fatalf("failed to create tx: %v", err)
} }
gen.AddTx(tx) gen.AddTx(tx)
if int(gen.header.Number.Uint64()) >= mergeBlock {
gen.SetPoS()
}
nonce++ nonce++
}) })
if n, err := chain.InsertChain(blocks); err != nil { if n, err := chain.InsertChain(blocks); err != nil {
...@@ -2006,7 +2011,10 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon ...@@ -2006,7 +2011,10 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
merger.ReachTTD() merger.ReachTTD()
merger.FinalizePoS() merger.FinalizePoS()
// Set the terminal total difficulty in the config // Set the terminal total difficulty in the config
gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(len(blocks))) ttd := big.NewInt(int64(len(blocks)))
ttd.Mul(ttd, params.GenesisDifficulty)
gspec.Config.TerminalTotalDifficulty = ttd
mergeBlock = len(blocks)
} }
// Generate the sidechain // Generate the sidechain
...@@ -2018,6 +2026,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon ...@@ -2018,6 +2026,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
parent := blocks[parentIndex] parent := blocks[parentIndex]
fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{2}) b.SetCoinbase(common.Address{2})
if int(b.header.Number.Uint64()) >= mergeBlock {
b.SetPoS()
}
}) })
// Prepend the parent(s) // Prepend the parent(s)
var sidechain []*types.Block var sidechain []*types.Block
...@@ -2227,24 +2238,44 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i ...@@ -2227,24 +2238,44 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
Config: &chainConfig, Config: &chainConfig,
} }
engine = beacon.New(ethash.NewFaker()) engine = beacon.New(ethash.NewFaker())
mergeBlock = uint64(math.MaxUint64)
) )
// Apply merging since genesis // Apply merging since genesis
if mergeHeight == 0 { if mergeHeight == 0 {
genesis.Config.TerminalTotalDifficulty = big.NewInt(0) genesis.Config.TerminalTotalDifficulty = big.NewInt(0)
mergeBlock = uint64(0)
} }
genDb, blocks, receipts := GenerateChainWithGenesis(genesis, engine, 32, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
genDb, blocks, receipts := GenerateChainWithGenesis(genesis, engine, 32,
func(i int, b *BlockGen) {
if b.header.Number.Uint64() >= mergeBlock {
b.SetPoS()
}
b.SetCoinbase(common.Address{1})
})
// Apply merging after the first segment // Apply merging after the first segment
if mergeHeight == 1 { if mergeHeight == 1 {
genesis.Config.TerminalTotalDifficulty = big.NewInt(int64(len(blocks))) // TTD is genesis diff + blocks
ttd := big.NewInt(1 + int64(len(blocks)))
ttd.Mul(ttd, params.GenesisDifficulty)
genesis.Config.TerminalTotalDifficulty = ttd
mergeBlock = uint64(len(blocks))
} }
// Longer chain and shorter chain // Longer chain and shorter chain
blocks2, receipts2 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 65, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) blocks2, receipts2 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 65, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1})
if b.header.Number.Uint64() >= mergeBlock {
b.SetPoS()
}
})
blocks3, receipts3 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 64, func(i int, b *BlockGen) { blocks3, receipts3 := GenerateChain(genesis.Config, blocks[len(blocks)-1], engine, genDb, 64, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1}) b.SetCoinbase(common.Address{1})
b.OffsetTime(-9) // Time shifted, difficulty shouldn't be changed b.OffsetTime(-9) // Time shifted, difficulty shouldn't be changed
if b.header.Number.Uint64() >= mergeBlock {
b.SetPoS()
}
}) })
// Import the shared chain and the original canonical one // Import the shared chain and the original canonical one
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
if err != nil { if err != nil {
...@@ -2268,7 +2299,10 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i ...@@ -2268,7 +2299,10 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
for _, block := range blocks { for _, block := range blocks {
headers = append(headers, block.Header()) headers = append(headers, block.Header())
} }
_, err := chain.InsertHeaderChain(headers, 1) i, err := chain.InsertHeaderChain(headers, 1)
if err != nil {
return fmt.Errorf("index %d, number %d: %w", i, headers[i].Number, err)
}
return err return err
} }
asserter = func(t *testing.T, block *types.Block) { asserter = func(t *testing.T, block *types.Block) {
...@@ -2282,9 +2316,9 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i ...@@ -2282,9 +2316,9 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
for _, block := range blocks { for _, block := range blocks {
headers = append(headers, block.Header()) headers = append(headers, block.Header())
} }
_, err := chain.InsertHeaderChain(headers, 1) i, err := chain.InsertHeaderChain(headers, 1)
if err != nil { if err != nil {
return err return fmt.Errorf("index %d: %w", i, err)
} }
_, err = chain.InsertReceiptChain(blocks, receipts, 0) _, err = chain.InsertReceiptChain(blocks, receipts, 0)
return err return err
...@@ -2296,8 +2330,11 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i ...@@ -2296,8 +2330,11 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
} }
} else { } else {
inserter = func(blocks []*types.Block, receipts []types.Receipts) error { inserter = func(blocks []*types.Block, receipts []types.Receipts) error {
_, err := chain.InsertChain(blocks) i, err := chain.InsertChain(blocks)
return err if err != nil {
return fmt.Errorf("index %d: %w", i, err)
}
return nil
} }
asserter = func(t *testing.T, block *types.Block) { asserter = func(t *testing.T, block *types.Block) {
if chain.CurrentBlock().Hash() != block.Hash() { if chain.CurrentBlock().Hash() != block.Hash() {
......
...@@ -80,6 +80,11 @@ func (b *BlockGen) SetDifficulty(diff *big.Int) { ...@@ -80,6 +80,11 @@ func (b *BlockGen) SetDifficulty(diff *big.Int) {
b.header.Difficulty = diff b.header.Difficulty = diff
} }
// SetPos makes the header a PoS-header (0 difficulty)
func (b *BlockGen) SetPoS() {
b.header.Difficulty = new(big.Int)
}
// addTx adds a transaction to the generated block. If no coinbase has // addTx adds a transaction to the generated block. If no coinbase has
// been set, the block's coinbase is set to the zero address. // been set, the block's coinbase is set to the zero address.
// //
......
...@@ -852,11 +852,11 @@ func TestInvalidBloom(t *testing.T) { ...@@ -852,11 +852,11 @@ func TestInvalidBloom(t *testing.T) {
func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) { func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
genesis, preMergeBlocks := generatePreMergeChain(100) genesis, preMergeBlocks := generatePreMergeChain(100)
genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())
n, ethservice := startEthService(t, genesis, preMergeBlocks) n, ethservice := startEthService(t, genesis, preMergeBlocks)
defer n.Close() defer n.Close()
genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())
var ( var (
api = NewConsensusAPI(ethservice) api = NewConsensusAPI(ethservice)
parent = preMergeBlocks[len(preMergeBlocks)-1] parent = preMergeBlocks[len(preMergeBlocks)-1]
......
...@@ -44,7 +44,7 @@ var ( ...@@ -44,7 +44,7 @@ var (
testBalance = big.NewInt(2e18) testBalance = big.NewInt(2e18)
) )
func generatePreMergeChain(n int) (*core.Genesis, []*types.Header, []*types.Block) { func generatePreMergeChain(pre, post int) (*core.Genesis, []*types.Header, []*types.Block, []*types.Header, []*types.Block) {
config := *params.AllEthashProtocolChanges config := *params.AllEthashProtocolChanges
genesis := &core.Genesis{ genesis := &core.Genesis{
Config: &config, Config: &config,
...@@ -53,21 +53,33 @@ func generatePreMergeChain(n int) (*core.Genesis, []*types.Header, []*types.Bloc ...@@ -53,21 +53,33 @@ func generatePreMergeChain(n int) (*core.Genesis, []*types.Header, []*types.Bloc
Timestamp: 9000, Timestamp: 9000,
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
_, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), n, nil) // Pre-merge blocks
totalDifficulty := big.NewInt(0) db, preBLocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), pre, nil)
totalDifficulty := new(big.Int).Set(params.GenesisDifficulty)
var headers []*types.Header var preHeaders []*types.Header
for _, b := range blocks { for _, b := range preBLocks {
totalDifficulty.Add(totalDifficulty, b.Difficulty()) totalDifficulty.Add(totalDifficulty, b.Difficulty())
headers = append(headers, b.Header()) preHeaders = append(preHeaders, b.Header())
} }
config.TerminalTotalDifficulty = totalDifficulty config.TerminalTotalDifficulty = totalDifficulty
// Post-merge blocks
postBlocks, _ := core.GenerateChain(genesis.Config,
preBLocks[len(preBLocks)-1], ethash.NewFaker(), db, post,
func(i int, b *core.BlockGen) {
b.SetPoS()
})
var postHeaders []*types.Header
for _, b := range postBlocks {
postHeaders = append(postHeaders, b.Header())
}
return genesis, headers, blocks return genesis, preHeaders, preBLocks, postHeaders, postBlocks
} }
func TestSetHeadBeforeTotalDifficulty(t *testing.T) { func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
genesis, headers, blocks := generatePreMergeChain(10) genesis, headers, blocks, _, _ := generatePreMergeChain(10, 0)
n, lesService := startLesService(t, genesis, headers) n, lesService := startLesService(t, genesis, headers)
defer n.Close() defer n.Close()
...@@ -83,21 +95,21 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) { ...@@ -83,21 +95,21 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
} }
func TestExecutePayloadV1(t *testing.T) { func TestExecutePayloadV1(t *testing.T) {
genesis, headers, blocks := generatePreMergeChain(10) genesis, headers, _, _, postBlocks := generatePreMergeChain(10, 2)
n, lesService := startLesService(t, genesis, headers[:9]) n, lesService := startLesService(t, genesis, headers)
lesService.Merger().ReachTTD() lesService.Merger().ReachTTD()
defer n.Close() defer n.Close()
api := NewConsensusAPI(lesService) api := NewConsensusAPI(lesService)
fcState := beacon.ForkchoiceStateV1{ fcState := beacon.ForkchoiceStateV1{
HeadBlockHash: blocks[8].Hash(), HeadBlockHash: postBlocks[0].Hash(),
SafeBlockHash: common.Hash{}, SafeBlockHash: common.Hash{},
FinalizedBlockHash: common.Hash{}, FinalizedBlockHash: common.Hash{},
} }
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
t.Errorf("Failed to update head %v", err) t.Errorf("Failed to update head %v", err)
} }
block := blocks[9] block := postBlocks[0]
fakeBlock := types.NewBlock(&types.Header{ fakeBlock := types.NewBlock(&types.Header{
ParentHash: block.ParentHash(), ParentHash: block.ParentHash(),
......
...@@ -46,6 +46,7 @@ func TestBlockchain(t *testing.T) { ...@@ -46,6 +46,7 @@ func TestBlockchain(t *testing.T) {
// test takes a lot for time and goes easily OOM because of sha3 calculation on a huge range, // test takes a lot for time and goes easily OOM because of sha3 calculation on a huge range,
// using 4.6 TGas // using 4.6 TGas
bt.skipLoad(`.*randomStatetest94.json.*`) bt.skipLoad(`.*randomStatetest94.json.*`)
bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) {
if err := bt.checkFailure(t, test.Run(false)); err != nil { if err := bt.checkFailure(t, test.Run(false)); err != nil {
t.Errorf("test without snapshotter failed: %v", err) t.Errorf("test without snapshotter failed: %v", err)
......
...@@ -29,6 +29,7 @@ import ( ...@@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
...@@ -120,6 +121,9 @@ func (t *BlockTest) Run(snapshotter bool) error { ...@@ -120,6 +121,9 @@ func (t *BlockTest) Run(snapshotter bool) error {
} else { } else {
engine = ethash.NewShared() engine = ethash.NewShared()
} }
// Wrap the original engine within the beacon-engine
engine = beacon.New(engine)
cache := &core.CacheConfig{TrieCleanLimit: 0} cache := &core.CacheConfig{TrieCleanLimit: 0}
if snapshotter { if snapshotter {
cache.SnapshotLimit = 1 cache.SnapshotLimit = 1
......
...@@ -197,6 +197,24 @@ var Forks = map[string]*params.ChainConfig{ ...@@ -197,6 +197,24 @@ var Forks = map[string]*params.ChainConfig{
LondonBlock: big.NewInt(0), LondonBlock: big.NewInt(0),
ArrowGlacierBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0),
}, },
"ArrowGlacierToMergeAtDiffC0000": {
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0),
MergeNetsplitBlock: big.NewInt(0),
TerminalTotalDifficulty: big.NewInt(0xC0000),
},
"GrayGlacier": { "GrayGlacier": {
ChainID: big.NewInt(1), ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0), HomesteadBlock: big.NewInt(0),
...@@ -213,7 +231,7 @@ var Forks = map[string]*params.ChainConfig{ ...@@ -213,7 +231,7 @@ var Forks = map[string]*params.ChainConfig{
ArrowGlacierBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0), GrayGlacierBlock: big.NewInt(0),
}, },
"Merged": { "Merge": {
ChainID: big.NewInt(1), ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0), HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0), EIP150Block: big.NewInt(0),
......
...@@ -56,14 +56,12 @@ func TestState(t *testing.T) { ...@@ -56,14 +56,12 @@ func TestState(t *testing.T) {
// Uses 1GB RAM per tested fork // Uses 1GB RAM per tested fork
st.skipLoad(`^stStaticCall/static_Call1MB`) st.skipLoad(`^stStaticCall/static_Call1MB`)
// Not yet supported TODO
st.skipLoad(`^stEIP3540/`)
st.skipLoad(`^stEIP3860/`)
// Broken tests: // Broken tests:
// Expected failures: // Expected failures:
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/3`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/0`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Constantinople/3`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/0`, "bug in test")
// st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/ConstantinopleFix/3`, "bug in test")
// For Istanbul, older tests were moved into LegacyTests // For Istanbul, older tests were moved into LegacyTests
for _, dir := range []string{ for _, dir := range []string{
......
...@@ -249,10 +249,16 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh ...@@ -249,10 +249,16 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
context.GetHash = vmTestBlockHash context.GetHash = vmTestBlockHash
context.BaseFee = baseFee context.BaseFee = baseFee
context.Random = nil context.Random = nil
if config.IsLondon(new(big.Int)) && t.json.Env.Random != nil { if config.IsLondon(new(big.Int)) {
if t.json.Env.Random != nil {
rnd := common.BigToHash(t.json.Env.Random) rnd := common.BigToHash(t.json.Env.Random)
context.Random = &rnd context.Random = &rnd
}
context.Difficulty = big.NewInt(0) context.Difficulty = big.NewInt(0)
} else {
if t.json.Env.Difficulty != nil {
context.Difficulty = new(big.Int).Set(t.json.Env.Difficulty)
}
} }
evm := vm.NewEVM(context, txContext, statedb, config, vmconfig) evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
// Execute the message. // Execute the message.
......
Subproject commit a380655e5ffab1a5ea0f4d860224bdb19013f06a Subproject commit 24fa31adb30f71ee700b27decb5204e53a11d9f3
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment