|
|
|
@ -17,9 +17,9 @@
|
|
|
|
|
package catalyst
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
|
|
|
|
"math/big"
|
|
|
|
|
"os"
|
|
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
@ -32,10 +32,12 @@ import (
|
|
|
|
|
"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/downloader"
|
|
|
|
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
|
|
|
|
"github.com/ethereum/go-ethereum/node"
|
|
|
|
|
"github.com/ethereum/go-ethereum/p2p"
|
|
|
|
|
"github.com/ethereum/go-ethereum/params"
|
|
|
|
|
"github.com/ethereum/go-ethereum/trie"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
@ -142,47 +144,44 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
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)
|
|
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
// Put the 10th block's tx in the pool and produce a new block
|
|
|
|
|
ethservice.TxPool().AddLocals(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) {
|
|
|
|
@ -396,13 +395,17 @@ func TestEth2DeepReorg(t *testing.T) {
|
|
|
|
|
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{})
|
|
|
|
|
n, err := node.New(&node.Config{
|
|
|
|
|
P2P: p2p.Config{
|
|
|
|
|
ListenAddr: "0.0.0.0:0",
|
|
|
|
|
NoDiscovery: true,
|
|
|
|
|
MaxPeers: 25,
|
|
|
|
|
}})
|
|
|
|
|
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}
|
|
|
|
|
|
|
|
|
|
ethcfg := ðconfig.Config{Genesis: genesis, Ethash: ethash.Config{PowMode: ethash.ModeFake}, SyncMode: downloader.SnapSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256}
|
|
|
|
|
ethservice, err := eth.New(n, ethcfg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal("can't create eth service:", err)
|
|
|
|
@ -427,39 +430,28 @@ func TestFullAPI(t *testing.T) {
|
|
|
|
|
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++ {
|
|
|
|
|
|
|
|
|
|
callback := func(parent *types.Block) {
|
|
|
|
|
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(),
|
|
|
|
|
}
|
|
|
|
|
setupBlocks(t, ethservice, 10, parent, callback)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Block, callback func(parent *types.Block)) {
|
|
|
|
|
api := NewConsensusAPI(ethservice)
|
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
|
callback(parent)
|
|
|
|
|
|
|
|
|
|
payload := getNewPayload(t, api, parent)
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
@ -467,7 +459,7 @@ func TestFullAPI(t *testing.T) {
|
|
|
|
|
if execResp.Status != beacon.VALID {
|
|
|
|
|
t.Fatalf("invalid status: %v", execResp.Status)
|
|
|
|
|
}
|
|
|
|
|
fcState = beacon.ForkchoiceStateV1{
|
|
|
|
|
fcState := beacon.ForkchoiceStateV1{
|
|
|
|
|
HeadBlockHash: payload.BlockHash,
|
|
|
|
|
SafeBlockHash: payload.ParentHash,
|
|
|
|
|
FinalizedBlockHash: payload.ParentHash,
|
|
|
|
@ -531,11 +523,29 @@ func TestExchangeTransitionConfig(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestEmptyBlocks(t *testing.T) {
|
|
|
|
|
/*
|
|
|
|
|
TestNewPayloadOnInvalidChain sets up a valid chain and tries to feed blocks
|
|
|
|
|
from an invalid chain to test if latestValidHash (LVH) works correctly.
|
|
|
|
|
|
|
|
|
|
We set up the following chain where P1 ... Pn and P1'' are valid while
|
|
|
|
|
P1' is invalid.
|
|
|
|
|
We expect
|
|
|
|
|
(1) The LVH to point to the current inserted payload if it was valid.
|
|
|
|
|
(2) The LVH to point to the valid parent on an invalid payload (if the parent is available).
|
|
|
|
|
(3) If the parent is unavailable, the LVH should not be set.
|
|
|
|
|
|
|
|
|
|
CommonAncestor◄─▲── P1 ◄── P2 ◄─ P3 ◄─ ... ◄─ Pn
|
|
|
|
|
│
|
|
|
|
|
└── P1' ◄─ P2' ◄─ P3' ◄─ ... ◄─ Pn'
|
|
|
|
|
│
|
|
|
|
|
└── P1''
|
|
|
|
|
*/
|
|
|
|
|
func TestNewPayloadOnInvalidChain(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()
|
|
|
|
@ -604,3 +614,183 @@ func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.Pay
|
|
|
|
|
}
|
|
|
|
|
return beacon.BlockToExecutableData(block), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestEmptyBlocks(t *testing.T) {
|
|
|
|
|
genesis, preMergeBlocks := generatePreMergeChain(10)
|
|
|
|
|
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
|
|
|
|
ethservice.Merger().ReachTTD()
|
|
|
|
|
defer n.Close()
|
|
|
|
|
|
|
|
|
|
commonAncestor := ethservice.BlockChain().CurrentBlock()
|
|
|
|
|
api := NewConsensusAPI(ethservice)
|
|
|
|
|
|
|
|
|
|
// Setup 10 blocks on the canonical chain
|
|
|
|
|
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Block) {})
|
|
|
|
|
|
|
|
|
|
// (1) check LatestValidHash by sending a normal payload (P1'')
|
|
|
|
|
payload := getNewPayload(t, api, commonAncestor)
|
|
|
|
|
|
|
|
|
|
status, err := api.NewPayloadV1(*payload)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if status.Status != beacon.VALID {
|
|
|
|
|
t.Errorf("invalid status: expected VALID got: %v", status.Status)
|
|
|
|
|
}
|
|
|
|
|
if !bytes.Equal(status.LatestValidHash[:], payload.BlockHash[:]) {
|
|
|
|
|
t.Fatalf("invalid LVH: got %v want %v", status.LatestValidHash, payload.BlockHash)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (2) Now send P1' which is invalid
|
|
|
|
|
payload = getNewPayload(t, api, commonAncestor)
|
|
|
|
|
payload.GasUsed += 1
|
|
|
|
|
payload = setBlockhash(payload)
|
|
|
|
|
// Now latestValidHash should be the common ancestor
|
|
|
|
|
status, err = api.NewPayloadV1(*payload)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if status.Status != beacon.INVALID {
|
|
|
|
|
t.Errorf("invalid status: expected INVALID got: %v", status.Status)
|
|
|
|
|
}
|
|
|
|
|
expected := commonAncestor.Hash()
|
|
|
|
|
if !bytes.Equal(status.LatestValidHash[:], expected[:]) {
|
|
|
|
|
t.Fatalf("invalid LVH: got %v want %v", status.LatestValidHash, expected)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (3) Now send a payload with unknown parent
|
|
|
|
|
payload = getNewPayload(t, api, commonAncestor)
|
|
|
|
|
payload.ParentHash = common.Hash{1}
|
|
|
|
|
payload = setBlockhash(payload)
|
|
|
|
|
// Now latestValidHash should be the common ancestor
|
|
|
|
|
status, err = api.NewPayloadV1(*payload)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if status.Status != beacon.ACCEPTED {
|
|
|
|
|
t.Errorf("invalid status: expected ACCEPTED got: %v", status.Status)
|
|
|
|
|
}
|
|
|
|
|
if status.LatestValidHash != nil {
|
|
|
|
|
t.Fatalf("invalid LVH: got %v wanted nil", status.LatestValidHash)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon.ExecutableDataV1 {
|
|
|
|
|
params := beacon.PayloadAttributesV1{
|
|
|
|
|
Timestamp: parent.Time() + 1,
|
|
|
|
|
Random: crypto.Keccak256Hash([]byte{byte(1)}),
|
|
|
|
|
SuggestedFeeRecipient: parent.Coinbase(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
payload, err := assembleBlock(api, parent.Hash(), ¶ms)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
return payload
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setBlockhash sets the blockhash of a modified ExecutableData.
|
|
|
|
|
// Can be used to make modified payloads look valid.
|
|
|
|
|
func setBlockhash(data *beacon.ExecutableDataV1) *beacon.ExecutableDataV1 {
|
|
|
|
|
txs, _ := decodeTransactions(data.Transactions)
|
|
|
|
|
number := big.NewInt(0)
|
|
|
|
|
number.SetUint64(data.Number)
|
|
|
|
|
header := &types.Header{
|
|
|
|
|
ParentHash: data.ParentHash,
|
|
|
|
|
UncleHash: types.EmptyUncleHash,
|
|
|
|
|
Coinbase: data.FeeRecipient,
|
|
|
|
|
Root: data.StateRoot,
|
|
|
|
|
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
|
|
|
|
|
ReceiptHash: data.ReceiptsRoot,
|
|
|
|
|
Bloom: types.BytesToBloom(data.LogsBloom),
|
|
|
|
|
Difficulty: common.Big0,
|
|
|
|
|
Number: number,
|
|
|
|
|
GasLimit: data.GasLimit,
|
|
|
|
|
GasUsed: data.GasUsed,
|
|
|
|
|
Time: data.Timestamp,
|
|
|
|
|
BaseFee: data.BaseFeePerGas,
|
|
|
|
|
Extra: data.ExtraData,
|
|
|
|
|
MixDigest: data.Random,
|
|
|
|
|
}
|
|
|
|
|
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */)
|
|
|
|
|
data.BlockHash = block.Hash()
|
|
|
|
|
return data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
|
|
|
|
var txs = make([]*types.Transaction, len(enc))
|
|
|
|
|
for i, encTx := range enc {
|
|
|
|
|
var tx types.Transaction
|
|
|
|
|
if err := tx.UnmarshalBinary(encTx); err != nil {
|
|
|
|
|
return nil, fmt.Errorf("invalid transaction %d: %v", i, err)
|
|
|
|
|
}
|
|
|
|
|
txs[i] = &tx
|
|
|
|
|
}
|
|
|
|
|
return txs, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestTrickRemoteBlockCache(t *testing.T) {
|
|
|
|
|
// Setup two nodes
|
|
|
|
|
genesis, preMergeBlocks := generatePreMergeChain(10)
|
|
|
|
|
nodeA, ethserviceA := startEthService(t, genesis, preMergeBlocks)
|
|
|
|
|
nodeB, ethserviceB := startEthService(t, genesis, preMergeBlocks)
|
|
|
|
|
ethserviceA.Merger().ReachTTD()
|
|
|
|
|
ethserviceB.Merger().ReachTTD()
|
|
|
|
|
defer nodeA.Close()
|
|
|
|
|
defer nodeB.Close()
|
|
|
|
|
for nodeB.Server().NodeInfo().Ports.Listener == 0 {
|
|
|
|
|
time.Sleep(250 * time.Millisecond)
|
|
|
|
|
}
|
|
|
|
|
nodeA.Server().AddPeer(nodeB.Server().Self())
|
|
|
|
|
nodeB.Server().AddPeer(nodeA.Server().Self())
|
|
|
|
|
apiA := NewConsensusAPI(ethserviceA)
|
|
|
|
|
apiB := NewConsensusAPI(ethserviceB)
|
|
|
|
|
|
|
|
|
|
commonAncestor := ethserviceA.BlockChain().CurrentBlock()
|
|
|
|
|
|
|
|
|
|
// Setup 10 blocks on the canonical chain
|
|
|
|
|
setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Block) {})
|
|
|
|
|
commonAncestor = ethserviceA.BlockChain().CurrentBlock()
|
|
|
|
|
|
|
|
|
|
var invalidChain []*beacon.ExecutableDataV1
|
|
|
|
|
// create a valid payload (P1)
|
|
|
|
|
//payload1 := getNewPayload(t, apiA, commonAncestor)
|
|
|
|
|
//invalidChain = append(invalidChain, payload1)
|
|
|
|
|
|
|
|
|
|
// create an invalid payload2 (P2)
|
|
|
|
|
payload2 := getNewPayload(t, apiA, commonAncestor)
|
|
|
|
|
//payload2.ParentHash = payload1.BlockHash
|
|
|
|
|
payload2.GasUsed += 1
|
|
|
|
|
payload2 = setBlockhash(payload2)
|
|
|
|
|
invalidChain = append(invalidChain, payload2)
|
|
|
|
|
|
|
|
|
|
head := payload2
|
|
|
|
|
// create some valid payloads on top
|
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
|
payload := getNewPayload(t, apiA, commonAncestor)
|
|
|
|
|
payload.ParentHash = head.BlockHash
|
|
|
|
|
payload = setBlockhash(payload)
|
|
|
|
|
invalidChain = append(invalidChain, payload)
|
|
|
|
|
head = payload
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// feed the payloads to node B
|
|
|
|
|
for _, payload := range invalidChain {
|
|
|
|
|
status, err := apiB.NewPayloadV1(*payload)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
if status.Status == beacon.INVALID {
|
|
|
|
|
panic("success")
|
|
|
|
|
}
|
|
|
|
|
// Now reorg to the head of the invalid chain
|
|
|
|
|
resp, err := apiB.ForkchoiceUpdatedV1(beacon.ForkchoiceStateV1{HeadBlockHash: payload.BlockHash, SafeBlockHash: payload.BlockHash, FinalizedBlockHash: payload.ParentHash}, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if resp.PayloadStatus.Status == beacon.VALID {
|
|
|
|
|
t.Errorf("invalid status: expected INVALID got: %v", resp.PayloadStatus.Status)
|
|
|
|
|
}
|
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|