@ -41,12 +41,14 @@ import (
"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/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie"
"github.com/mattn/go-colorable"
)
var (
@ -69,7 +71,10 @@ func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) {
}
genesis := & core . Genesis {
Config : & config ,
Alloc : core . GenesisAlloc { testAddr : { Balance : testBalance } } ,
Alloc : core . GenesisAlloc {
testAddr : { Balance : testBalance } ,
params . BeaconRootsStorageAddress : { Balance : common . Big0 , Code : common . Hex2Bytes ( "3373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500" ) } ,
} ,
ExtraData : [ ] byte ( "test genesis" ) ,
Timestamp : 9000 ,
BaseFee : big . NewInt ( params . InitialBaseFee ) ,
@ -204,6 +209,7 @@ func TestEth2PrepareAndGetPayload(t *testing.T) {
Timestamp : blockParams . Timestamp ,
FeeRecipient : blockParams . SuggestedFeeRecipient ,
Random : blockParams . Random ,
BeaconRoot : blockParams . BeaconRoot ,
} ) . Id ( )
execData , err := api . GetPayloadV1 ( payloadID )
if err != nil {
@ -314,7 +320,7 @@ func TestEth2NewBlock(t *testing.T) {
if err != nil {
t . Fatalf ( "Failed to create the executable data %v" , err )
}
block , err := engine . ExecutableDataToBlock ( * execData , nil )
block , err := engine . ExecutableDataToBlock ( * execData , nil , nil )
if err != nil {
t . Fatalf ( "Failed to convert executable data to block %v" , err )
}
@ -356,7 +362,7 @@ func TestEth2NewBlock(t *testing.T) {
if err != nil {
t . Fatalf ( "Failed to create the executable data %v" , err )
}
block , err := engine . ExecutableDataToBlock ( * execData , nil )
block , err := engine . ExecutableDataToBlock ( * execData , nil , nil )
if err != nil {
t . Fatalf ( "Failed to convert executable data to block %v" , err )
}
@ -667,6 +673,7 @@ func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *engine.Pay
FeeRecipient : params . SuggestedFeeRecipient ,
Random : params . Random ,
Withdrawals : params . Withdrawals ,
BeaconRoot : params . BeaconRoot ,
}
payload , err := api . eth . Miner ( ) . BuildPayload ( args )
if err != nil {
@ -988,7 +995,7 @@ func TestSimultaneousNewBlock(t *testing.T) {
t . Fatal ( testErr )
}
}
block , err := engine . ExecutableDataToBlock ( * execData , nil )
block , err := engine . ExecutableDataToBlock ( * execData , nil , nil )
if err != nil {
t . Fatalf ( "Failed to convert executable data to block %v" , err )
}
@ -1068,6 +1075,7 @@ func TestWithdrawals(t *testing.T) {
FeeRecipient : blockParams . SuggestedFeeRecipient ,
Random : blockParams . Random ,
Withdrawals : blockParams . Withdrawals ,
BeaconRoot : blockParams . BeaconRoot ,
} ) . Id ( )
execData , err := api . GetPayloadV2 ( payloadID )
if err != nil {
@ -1115,6 +1123,7 @@ func TestWithdrawals(t *testing.T) {
FeeRecipient : blockParams . SuggestedFeeRecipient ,
Random : blockParams . Random ,
Withdrawals : blockParams . Withdrawals ,
BeaconRoot : blockParams . BeaconRoot ,
} ) . Id ( )
execData , err = api . GetPayloadV2 ( payloadID )
if err != nil {
@ -1245,6 +1254,7 @@ func TestNilWithdrawals(t *testing.T) {
Timestamp : test . blockParams . Timestamp ,
FeeRecipient : test . blockParams . SuggestedFeeRecipient ,
Random : test . blockParams . Random ,
BeaconRoot : test . blockParams . BeaconRoot ,
} ) . Id ( )
execData , err := api . GetPayloadV2 ( payloadID )
if err != nil {
@ -1544,8 +1554,91 @@ func TestBlockToPayloadWithBlobs(t *testing.T) {
if got := len ( envelope . BlobsBundle . Blobs ) ; got != want {
t . Fatalf ( "invalid number of blobs: got %v, want %v" , got , want )
}
_ , err := engine . ExecutableDataToBlock ( * envelope . ExecutionPayload , make ( [ ] common . Hash , 1 ) )
_ , err := engine . ExecutableDataToBlock ( * envelope . ExecutionPayload , make ( [ ] common . Hash , 1 ) , nil )
if err != nil {
t . Error ( err )
}
}
// This checks that beaconRoot is applied to the state from the engine API.
func TestParentBeaconBlockRoot ( t * testing . T ) {
log . Root ( ) . SetHandler ( log . LvlFilterHandler ( log . LvlTrace , log . StreamHandler ( colorable . NewColorableStderr ( ) , log . TerminalFormat ( true ) ) ) )
genesis , blocks := generateMergeChain ( 10 , true )
// Set cancun time to last block + 5 seconds
time := blocks [ len ( blocks ) - 1 ] . Time ( ) + 5
genesis . Config . ShanghaiTime = & time
genesis . Config . CancunTime = & time
n , ethservice := startEthService ( t , genesis , blocks )
ethservice . Merger ( ) . ReachTTD ( )
defer n . Close ( )
api := NewConsensusAPI ( ethservice )
// 11: Build Shanghai block with no withdrawals.
parent := ethservice . BlockChain ( ) . CurrentHeader ( )
blockParams := engine . PayloadAttributes {
Timestamp : parent . Time + 5 ,
Withdrawals : make ( [ ] * types . Withdrawal , 0 ) ,
BeaconRoot : & common . Hash { 42 } ,
}
fcState := engine . ForkchoiceStateV1 {
HeadBlockHash : parent . Hash ( ) ,
}
resp , err := api . ForkchoiceUpdatedV2 ( fcState , & blockParams )
if err != nil {
t . Fatalf ( "error preparing payload, err=%v" , err . ( * engine . EngineAPIError ) . ErrorData ( ) )
}
if resp . PayloadStatus . Status != engine . VALID {
t . Fatalf ( "unexpected status (got: %s, want: %s)" , resp . PayloadStatus . Status , engine . VALID )
}
// 11: verify state root is the same as parent
payloadID := ( & miner . BuildPayloadArgs {
Parent : fcState . HeadBlockHash ,
Timestamp : blockParams . Timestamp ,
FeeRecipient : blockParams . SuggestedFeeRecipient ,
Random : blockParams . Random ,
Withdrawals : blockParams . Withdrawals ,
BeaconRoot : blockParams . BeaconRoot ,
} ) . Id ( )
execData , err := api . GetPayloadV3 ( payloadID )
if err != nil {
t . Fatalf ( "error getting payload, err=%v" , err )
}
// 11: verify locally built block
if status , err := api . NewPayloadV3 ( * execData . ExecutionPayload , [ ] common . Hash { } , & common . Hash { 42 } ) ; err != nil {
t . Fatalf ( "error validating payload: %v" , err )
} else if status . Status != engine . VALID {
t . Fatalf ( "invalid payload" )
}
fcState . HeadBlockHash = execData . ExecutionPayload . BlockHash
resp , err = api . ForkchoiceUpdatedV3 ( fcState , nil )
if err != nil {
t . Fatalf ( "error preparing payload, err=%v" , err . ( * engine . EngineAPIError ) . ErrorData ( ) )
}
if resp . PayloadStatus . Status != engine . VALID {
t . Fatalf ( "unexpected status (got: %s, want: %s)" , resp . PayloadStatus . Status , engine . VALID )
}
// 11: verify beacon root was processed.
db , _ , err := ethservice . APIBackend . StateAndHeaderByNumber ( context . Background ( ) , rpc . BlockNumber ( execData . ExecutionPayload . Number ) )
if err != nil {
t . Fatalf ( "unable to load db: %v" , err )
}
var (
timeIdx = common . BigToHash ( big . NewInt ( int64 ( execData . ExecutionPayload . Timestamp % 98304 ) ) )
rootIdx = common . BigToHash ( big . NewInt ( int64 ( ( execData . ExecutionPayload . Timestamp % 98304 ) + 98304 ) ) )
)
if num := db . GetState ( params . BeaconRootsStorageAddress , timeIdx ) ; num != timeIdx {
t . Fatalf ( "incorrect number stored: want %s, got %s" , timeIdx , num )
}
if root := db . GetState ( params . BeaconRootsStorageAddress , rootIdx ) ; root != * blockParams . BeaconRoot {
t . Fatalf ( "incorrect root stored: want %s, got %s" , * blockParams . BeaconRoot , root )
}
}