forked from cerc-io/plugeth
39fb82bcfb
* eth/protocols/snap: don't include empty snapshot slot slice This PR fixes the snapshot storage serving handler. In snap protocol the response is capped by the response size. Server can cutdown the response if the accumulated byte size exceeds the local hard limit. It means we can meet a special scenario that there is no storage slot included for a requested account, but we attach the proof for this account by mistake. So in the prover side, when it meets a empty storage response but with a valid proof proves there are some more slots left in the trie, then requestor will reject this response and disconnect with server. In this PR, if there is no storage slot served for the requested account, then no proof should be attached as well. * eth/protocols/snap: loosen restrictions for flaky tests * eth/catalyst: fix flaky test in catalyst
530 lines
18 KiB
Go
530 lines
18 KiB
Go
// Copyright 2020 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package catalyst
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/core/beacon"
|
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/eth"
|
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/node"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
)
|
|
|
|
var (
|
|
// testKey is a private key to use for funding a tester account.
|
|
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
|
|
// testAddr is the Ethereum address of the tester account.
|
|
testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
|
|
|
|
testBalance = big.NewInt(2e18)
|
|
)
|
|
|
|
func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) {
|
|
db := rawdb.NewMemoryDatabase()
|
|
config := params.AllEthashProtocolChanges
|
|
genesis := &core.Genesis{
|
|
Config: config,
|
|
Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}},
|
|
ExtraData: []byte("test genesis"),
|
|
Timestamp: 9000,
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
Difficulty: big.NewInt(0),
|
|
}
|
|
testNonce := uint64(0)
|
|
generate := func(i int, g *core.BlockGen) {
|
|
g.OffsetTime(5)
|
|
g.SetExtra([]byte("test"))
|
|
tx, _ := types.SignTx(types.NewTransaction(testNonce, common.HexToAddress("0x9a9070028361F7AAbeB3f2F2Dc07F82C4a98A02a"), big.NewInt(1), params.TxGas, big.NewInt(params.InitialBaseFee*2), nil), types.LatestSigner(config), testKey)
|
|
g.AddTx(tx)
|
|
testNonce++
|
|
}
|
|
gblock := genesis.ToBlock(db)
|
|
engine := ethash.NewFaker()
|
|
blocks, _ := core.GenerateChain(config, gblock, engine, db, n, generate)
|
|
totalDifficulty := big.NewInt(0)
|
|
for _, b := range blocks {
|
|
totalDifficulty.Add(totalDifficulty, b.Difficulty())
|
|
}
|
|
config.TerminalTotalDifficulty = totalDifficulty
|
|
return genesis, blocks
|
|
}
|
|
|
|
func TestEth2AssembleBlock(t *testing.T) {
|
|
genesis, blocks := generatePreMergeChain(10)
|
|
n, ethservice := startEthService(t, genesis, blocks)
|
|
defer n.Close()
|
|
|
|
api := NewConsensusAPI(ethservice)
|
|
signer := types.NewEIP155Signer(ethservice.BlockChain().Config().ChainID)
|
|
tx, err := types.SignTx(types.NewTransaction(uint64(10), blocks[9].Coinbase(), big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, testKey)
|
|
if err != nil {
|
|
t.Fatalf("error signing transaction, err=%v", err)
|
|
}
|
|
ethservice.TxPool().AddLocal(tx)
|
|
blockParams := beacon.PayloadAttributesV1{
|
|
Timestamp: blocks[9].Time() + 5,
|
|
}
|
|
execData, err := api.assembleBlock(blocks[9].Hash(), &blockParams)
|
|
if err != nil {
|
|
t.Fatalf("error producing block, err=%v", err)
|
|
}
|
|
if len(execData.Transactions) != 1 {
|
|
t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions))
|
|
}
|
|
}
|
|
|
|
func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
|
|
genesis, blocks := generatePreMergeChain(10)
|
|
n, ethservice := startEthService(t, genesis, blocks[:9])
|
|
defer n.Close()
|
|
|
|
api := NewConsensusAPI(ethservice)
|
|
|
|
// Put the 10th block's tx in the pool and produce a new block
|
|
api.eth.TxPool().AddRemotesSync(blocks[9].Transactions())
|
|
blockParams := beacon.PayloadAttributesV1{
|
|
Timestamp: blocks[8].Time() + 5,
|
|
}
|
|
execData, err := api.assembleBlock(blocks[8].Hash(), &blockParams)
|
|
if err != nil {
|
|
t.Fatalf("error producing block, err=%v", err)
|
|
}
|
|
if len(execData.Transactions) != blocks[9].Transactions().Len() {
|
|
t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions))
|
|
}
|
|
}
|
|
|
|
func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
|
|
genesis, blocks := generatePreMergeChain(10)
|
|
n, ethservice := startEthService(t, genesis, blocks)
|
|
defer n.Close()
|
|
|
|
api := NewConsensusAPI(ethservice)
|
|
fcState := beacon.ForkchoiceStateV1{
|
|
HeadBlockHash: blocks[5].Hash(),
|
|
SafeBlockHash: common.Hash{},
|
|
FinalizedBlockHash: common.Hash{},
|
|
}
|
|
if resp, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
|
|
t.Errorf("fork choice updated should not error: %v", err)
|
|
} else if resp.PayloadStatus.Status != beacon.INVALIDTERMINALBLOCK {
|
|
t.Errorf("fork choice updated before total terminal difficulty should be INVALID")
|
|
}
|
|
}
|
|
|
|
func TestEth2PrepareAndGetPayload(t *testing.T) {
|
|
// TODO (MariusVanDerWijden) TestEth2PrepareAndGetPayload is currently broken, fixed in upcoming merge-kiln-v2 pr
|
|
/*
|
|
genesis, blocks := generatePreMergeChain(10)
|
|
// We need to properly set the terminal total difficulty
|
|
genesis.Config.TerminalTotalDifficulty.Sub(genesis.Config.TerminalTotalDifficulty, blocks[9].Difficulty())
|
|
n, ethservice := startEthService(t, genesis, blocks[:9])
|
|
defer n.Close()
|
|
|
|
api := NewConsensusAPI(ethservice)
|
|
|
|
// Put the 10th block's tx in the pool and produce a new block
|
|
api.insertTransactions(blocks[9].Transactions())
|
|
blockParams := beacon.PayloadAttributesV1{
|
|
Timestamp: blocks[8].Time() + 5,
|
|
}
|
|
fcState := beacon.ForkchoiceStateV1{
|
|
HeadBlockHash: blocks[8].Hash(),
|
|
SafeBlockHash: common.Hash{},
|
|
FinalizedBlockHash: common.Hash{},
|
|
}
|
|
_, err := api.ForkchoiceUpdatedV1(fcState, &blockParams)
|
|
if err != nil {
|
|
t.Fatalf("error preparing payload, err=%v", err)
|
|
}
|
|
payloadID := computePayloadId(fcState.HeadBlockHash, &blockParams)
|
|
execData, err := api.GetPayloadV1(payloadID)
|
|
if err != nil {
|
|
t.Fatalf("error getting payload, err=%v", err)
|
|
}
|
|
if len(execData.Transactions) != blocks[9].Transactions().Len() {
|
|
t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions))
|
|
}
|
|
// Test invalid payloadID
|
|
var invPayload beacon.PayloadID
|
|
copy(invPayload[:], payloadID[:])
|
|
invPayload[0] = ^invPayload[0]
|
|
_, err = api.GetPayloadV1(invPayload)
|
|
if err == nil {
|
|
t.Fatal("expected error retrieving invalid payload")
|
|
}
|
|
*/
|
|
}
|
|
|
|
func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan core.RemovedLogsEvent, wantNew, wantRemoved int) {
|
|
t.Helper()
|
|
|
|
if len(logsCh) != wantNew {
|
|
t.Fatalf("wrong number of log events: got %d, want %d", len(logsCh), wantNew)
|
|
}
|
|
if len(rmLogsCh) != wantRemoved {
|
|
t.Fatalf("wrong number of removed log events: got %d, want %d", len(rmLogsCh), wantRemoved)
|
|
}
|
|
// Drain events.
|
|
for i := 0; i < len(logsCh); i++ {
|
|
<-logsCh
|
|
}
|
|
for i := 0; i < len(rmLogsCh); i++ {
|
|
<-rmLogsCh
|
|
}
|
|
}
|
|
|
|
func TestInvalidPayloadTimestamp(t *testing.T) {
|
|
genesis, preMergeBlocks := generatePreMergeChain(10)
|
|
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
|
ethservice.Merger().ReachTTD()
|
|
defer n.Close()
|
|
var (
|
|
api = NewConsensusAPI(ethservice)
|
|
parent = ethservice.BlockChain().CurrentBlock()
|
|
)
|
|
tests := []struct {
|
|
time uint64
|
|
shouldErr bool
|
|
}{
|
|
{0, true},
|
|
{parent.Time(), true},
|
|
{parent.Time() - 1, true},
|
|
|
|
// TODO (MariusVanDerWijden) following tests are currently broken,
|
|
// fixed in upcoming merge-kiln-v2 pr
|
|
//{parent.Time() + 1, false},
|
|
//{uint64(time.Now().Unix()) + uint64(time.Minute), false},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("Timestamp test: %v", i), func(t *testing.T) {
|
|
params := beacon.PayloadAttributesV1{
|
|
Timestamp: test.time,
|
|
Random: crypto.Keccak256Hash([]byte{byte(123)}),
|
|
SuggestedFeeRecipient: parent.Coinbase(),
|
|
}
|
|
fcState := beacon.ForkchoiceStateV1{
|
|
HeadBlockHash: parent.Hash(),
|
|
SafeBlockHash: common.Hash{},
|
|
FinalizedBlockHash: common.Hash{},
|
|
}
|
|
_, err := api.ForkchoiceUpdatedV1(fcState, ¶ms)
|
|
if test.shouldErr && err == nil {
|
|
t.Fatalf("expected error preparing payload with invalid timestamp, err=%v", err)
|
|
} else if !test.shouldErr && err != nil {
|
|
t.Fatalf("error preparing payload with valid timestamp, err=%v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEth2NewBlock(t *testing.T) {
|
|
genesis, preMergeBlocks := generatePreMergeChain(10)
|
|
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
|
ethservice.Merger().ReachTTD()
|
|
defer n.Close()
|
|
|
|
var (
|
|
api = NewConsensusAPI(ethservice)
|
|
parent = preMergeBlocks[len(preMergeBlocks)-1]
|
|
|
|
// This EVM code generates a log when the contract is created.
|
|
logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
|
)
|
|
// The event channels.
|
|
newLogCh := make(chan []*types.Log, 10)
|
|
rmLogsCh := make(chan core.RemovedLogsEvent, 10)
|
|
ethservice.BlockChain().SubscribeLogsEvent(newLogCh)
|
|
ethservice.BlockChain().SubscribeRemovedLogsEvent(rmLogsCh)
|
|
|
|
for i := 0; i < 10; i++ {
|
|
statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
|
|
nonce := statedb.GetNonce(testAddr)
|
|
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
|
|
ethservice.TxPool().AddLocal(tx)
|
|
|
|
execData, err := api.assembleBlock(parent.Hash(), &beacon.PayloadAttributesV1{
|
|
Timestamp: parent.Time() + 5,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Failed to create the executable data %v", err)
|
|
}
|
|
block, err := beacon.ExecutableDataToBlock(*execData)
|
|
if err != nil {
|
|
t.Fatalf("Failed to convert executable data to block %v", err)
|
|
}
|
|
newResp, err := api.NewPayloadV1(*execData)
|
|
if err != nil || newResp.Status != "VALID" {
|
|
t.Fatalf("Failed to insert block: %v", err)
|
|
}
|
|
if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1 {
|
|
t.Fatalf("Chain head shouldn't be updated")
|
|
}
|
|
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
|
|
fcState := beacon.ForkchoiceStateV1{
|
|
HeadBlockHash: block.Hash(),
|
|
SafeBlockHash: block.Hash(),
|
|
FinalizedBlockHash: block.Hash(),
|
|
}
|
|
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
|
|
t.Fatalf("Failed to insert block: %v", err)
|
|
}
|
|
if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
|
|
t.Fatalf("Chain head should be updated")
|
|
}
|
|
checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
|
|
|
|
parent = block
|
|
}
|
|
|
|
// Introduce fork chain
|
|
var (
|
|
head = ethservice.BlockChain().CurrentBlock().NumberU64()
|
|
)
|
|
parent = preMergeBlocks[len(preMergeBlocks)-1]
|
|
for i := 0; i < 10; i++ {
|
|
execData, err := api.assembleBlock(parent.Hash(), &beacon.PayloadAttributesV1{
|
|
Timestamp: parent.Time() + 6,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Failed to create the executable data %v", err)
|
|
}
|
|
block, err := beacon.ExecutableDataToBlock(*execData)
|
|
if err != nil {
|
|
t.Fatalf("Failed to convert executable data to block %v", err)
|
|
}
|
|
newResp, err := api.NewPayloadV1(*execData)
|
|
if err != nil || newResp.Status != "VALID" {
|
|
t.Fatalf("Failed to insert block: %v", err)
|
|
}
|
|
if ethservice.BlockChain().CurrentBlock().NumberU64() != head {
|
|
t.Fatalf("Chain head shouldn't be updated")
|
|
}
|
|
|
|
fcState := beacon.ForkchoiceStateV1{
|
|
HeadBlockHash: block.Hash(),
|
|
SafeBlockHash: block.Hash(),
|
|
FinalizedBlockHash: block.Hash(),
|
|
}
|
|
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
|
|
t.Fatalf("Failed to insert block: %v", err)
|
|
}
|
|
if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
|
|
t.Fatalf("Chain head should be updated")
|
|
}
|
|
parent, head = block, block.NumberU64()
|
|
}
|
|
}
|
|
|
|
func TestEth2DeepReorg(t *testing.T) {
|
|
// TODO (MariusVanDerWijden) TestEth2DeepReorg is currently broken, because it tries to reorg
|
|
// before the totalTerminalDifficulty threshold
|
|
/*
|
|
genesis, preMergeBlocks := generatePreMergeChain(core.TriesInMemory * 2)
|
|
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
|
defer n.Close()
|
|
|
|
var (
|
|
api = NewConsensusAPI(ethservice, nil)
|
|
parent = preMergeBlocks[len(preMergeBlocks)-core.TriesInMemory-1]
|
|
head = ethservice.BlockChain().CurrentBlock().NumberU64()
|
|
)
|
|
if ethservice.BlockChain().HasBlockAndState(parent.Hash(), parent.NumberU64()) {
|
|
t.Errorf("Block %d not pruned", parent.NumberU64())
|
|
}
|
|
for i := 0; i < 10; i++ {
|
|
execData, err := api.assembleBlock(AssembleBlockParams{
|
|
ParentHash: parent.Hash(),
|
|
Timestamp: parent.Time() + 5,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Failed to create the executable data %v", err)
|
|
}
|
|
block, err := ExecutableDataToBlock(ethservice.BlockChain().Config(), parent.Header(), *execData)
|
|
if err != nil {
|
|
t.Fatalf("Failed to convert executable data to block %v", err)
|
|
}
|
|
newResp, err := api.ExecutePayload(*execData)
|
|
if err != nil || newResp.Status != "VALID" {
|
|
t.Fatalf("Failed to insert block: %v", err)
|
|
}
|
|
if ethservice.BlockChain().CurrentBlock().NumberU64() != head {
|
|
t.Fatalf("Chain head shouldn't be updated")
|
|
}
|
|
if err := api.setHead(block.Hash()); err != nil {
|
|
t.Fatalf("Failed to set head: %v", err)
|
|
}
|
|
if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
|
|
t.Fatalf("Chain head should be updated")
|
|
}
|
|
parent, head = block, block.NumberU64()
|
|
}
|
|
*/
|
|
}
|
|
|
|
// startEthService creates a full node instance for testing.
|
|
func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) (*node.Node, *eth.Ethereum) {
|
|
t.Helper()
|
|
|
|
// Disable verbose log output which is noise to some extent.
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlCrit, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
n, err := node.New(&node.Config{})
|
|
if err != nil {
|
|
t.Fatal("can't create node:", err)
|
|
}
|
|
ethcfg := ðconfig.Config{Genesis: genesis, Ethash: ethash.Config{PowMode: ethash.ModeFake}, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256}
|
|
ethservice, err := eth.New(n, ethcfg)
|
|
if err != nil {
|
|
t.Fatal("can't create eth service:", err)
|
|
}
|
|
if err := n.Start(); err != nil {
|
|
t.Fatal("can't start node:", err)
|
|
}
|
|
if _, err := ethservice.BlockChain().InsertChain(blocks); err != nil {
|
|
n.Close()
|
|
t.Fatal("can't import test blocks:", err)
|
|
}
|
|
time.Sleep(500 * time.Millisecond) // give txpool enough time to consume head event
|
|
|
|
ethservice.SetEtherbase(testAddr)
|
|
ethservice.SetSynced()
|
|
return n, ethservice
|
|
}
|
|
|
|
func TestFullAPI(t *testing.T) {
|
|
genesis, preMergeBlocks := generatePreMergeChain(10)
|
|
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
|
ethservice.Merger().ReachTTD()
|
|
defer n.Close()
|
|
var (
|
|
api = NewConsensusAPI(ethservice)
|
|
parent = ethservice.BlockChain().CurrentBlock()
|
|
// This EVM code generates a log when the contract is created.
|
|
logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
|
)
|
|
for i := 0; i < 10; i++ {
|
|
statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
|
|
nonce := statedb.GetNonce(testAddr)
|
|
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
|
|
ethservice.TxPool().AddLocal(tx)
|
|
|
|
params := beacon.PayloadAttributesV1{
|
|
Timestamp: parent.Time() + 1,
|
|
Random: crypto.Keccak256Hash([]byte{byte(i)}),
|
|
SuggestedFeeRecipient: parent.Coinbase(),
|
|
}
|
|
|
|
fcState := beacon.ForkchoiceStateV1{
|
|
HeadBlockHash: parent.Hash(),
|
|
SafeBlockHash: common.Hash{},
|
|
FinalizedBlockHash: common.Hash{},
|
|
}
|
|
resp, err := api.ForkchoiceUpdatedV1(fcState, ¶ms)
|
|
if err != nil {
|
|
t.Fatalf("error preparing payload, err=%v", err)
|
|
}
|
|
if resp.PayloadStatus.Status != beacon.VALID {
|
|
t.Fatalf("error preparing payload, invalid status: %v", resp.PayloadStatus.Status)
|
|
}
|
|
payload, err := api.GetPayloadV1(*resp.PayloadID)
|
|
if err != nil {
|
|
t.Fatalf("can't get payload: %v", err)
|
|
}
|
|
execResp, err := api.NewPayloadV1(*payload)
|
|
if err != nil {
|
|
t.Fatalf("can't execute payload: %v", err)
|
|
}
|
|
if execResp.Status != beacon.VALID {
|
|
t.Fatalf("invalid status: %v", execResp.Status)
|
|
}
|
|
fcState = beacon.ForkchoiceStateV1{
|
|
HeadBlockHash: payload.BlockHash,
|
|
SafeBlockHash: payload.ParentHash,
|
|
FinalizedBlockHash: payload.ParentHash,
|
|
}
|
|
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
|
|
t.Fatalf("Failed to insert block: %v", err)
|
|
}
|
|
if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number {
|
|
t.Fatalf("Chain head should be updated")
|
|
}
|
|
parent = ethservice.BlockChain().CurrentBlock()
|
|
}
|
|
}
|
|
|
|
func TestExchangeTransitionConfig(t *testing.T) {
|
|
genesis, preMergeBlocks := generatePreMergeChain(10)
|
|
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
|
ethservice.Merger().ReachTTD()
|
|
defer n.Close()
|
|
var (
|
|
api = NewConsensusAPI(ethservice)
|
|
)
|
|
// invalid ttd
|
|
config := beacon.TransitionConfigurationV1{
|
|
TerminalTotalDifficulty: (*hexutil.Big)(big.NewInt(0)),
|
|
TerminalBlockHash: common.Hash{},
|
|
TerminalBlockNumber: 0,
|
|
}
|
|
if _, err := api.ExchangeTransitionConfigurationV1(config); err == nil {
|
|
t.Fatal("expected error on invalid config, invalid ttd")
|
|
}
|
|
// invalid terminal block hash
|
|
config = beacon.TransitionConfigurationV1{
|
|
TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty),
|
|
TerminalBlockHash: common.Hash{1},
|
|
TerminalBlockNumber: 0,
|
|
}
|
|
if _, err := api.ExchangeTransitionConfigurationV1(config); err == nil {
|
|
t.Fatal("expected error on invalid config, invalid hash")
|
|
}
|
|
// valid config
|
|
config = beacon.TransitionConfigurationV1{
|
|
TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty),
|
|
TerminalBlockHash: common.Hash{},
|
|
TerminalBlockNumber: 0,
|
|
}
|
|
if _, err := api.ExchangeTransitionConfigurationV1(config); err != nil {
|
|
t.Fatalf("expected no error on valid config, got %v", err)
|
|
}
|
|
// valid config
|
|
config = beacon.TransitionConfigurationV1{
|
|
TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty),
|
|
TerminalBlockHash: preMergeBlocks[5].Hash(),
|
|
TerminalBlockNumber: 6,
|
|
}
|
|
if _, err := api.ExchangeTransitionConfigurationV1(config); err != nil {
|
|
t.Fatalf("expected no error on valid config, got %v", err)
|
|
}
|
|
}
|