Skip to content

Commit

Permalink
Use V3 engine API methods for EIP-4844 (ethereum#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
Inphi authored Dec 6, 2022
1 parent b2d6f07 commit adac24d
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 21 deletions.
32 changes: 32 additions & 0 deletions eth/catalyst/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,15 @@ func (api *ConsensusAPI) GetPayloadV2(payloadID beacon.PayloadID) (*beacon.Execu
return data, nil
}

// GetPayloadV3 returns a cached payload by id.
func (api *ConsensusAPI) GetPayloadV3(payloadID beacon.PayloadID) (*beacon.ExecutableData, error) {
data, err := api.GetPayloadV2(payloadID)
if err != nil {
return nil, err
}
return data, nil
}

// GetBlobsBundleV1 returns a bundle of all blob and corresponding KZG commitments by payload id
func (api *ConsensusAPI) GetBlobsBundleV1(payloadID beacon.PayloadID) (*beacon.BlobsBundle, error) {
log.Trace("Engine API request received", "method", "GetBlobsBundle")
Expand All @@ -380,6 +389,29 @@ func (api *ConsensusAPI) GetBlobsBundleV1(payloadID beacon.PayloadID) (*beacon.B

// NewPayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) {
if params.Withdrawals != nil {
return beacon.PayloadStatusV1{Status: beacon.INVALID}, fmt.Errorf("withdrawals not supported in V1")
}
if params.ExcessDataGas != nil {
return beacon.PayloadStatusV1{Status: beacon.INVALID}, fmt.Errorf("excessDataGas not supported in V1")
}
return api.newPayload(params)
}

// NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
func (api *ConsensusAPI) NewPayloadV2(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) {
if params.ExcessDataGas != nil {
return beacon.PayloadStatusV1{Status: beacon.INVALID}, fmt.Errorf("excessDataGas not supported in V2")
}
return api.newPayload(params)
}

// NewPayloadV3 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
func (api *ConsensusAPI) NewPayloadV3(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) {
return api.newPayload(params)
}

func (api *ConsensusAPI) newPayload(params beacon.ExecutableData) (beacon.PayloadStatusV1, error) {
// The locking here is, strictly, not required. Without these locks, this can happen:
//
// 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to
Expand Down
102 changes: 81 additions & 21 deletions eth/catalyst/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
beaconConsensus "github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/beacon"
Expand All @@ -51,8 +52,13 @@ var (
testBalance = big.NewInt(2e18)
)

func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) {
// generateChain builds a block chain containing n blocks. A post-merge chain is generated iff merge is set
func generateChain(n int, merged bool) (*core.Genesis, []*types.Block) {
config := *params.AllEthashProtocolChanges
if merged {
config.TerminalTotalDifficulty = common.Big0
config.TerminalTotalDifficultyPassed = true
}
genesis := &core.Genesis{
Config: &config,
Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}},
Expand All @@ -69,17 +75,19 @@ func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) {
g.AddTx(tx)
testNonce++
}
_, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), n, generate)
totalDifficulty := big.NewInt(0)
for _, b := range blocks {
totalDifficulty.Add(totalDifficulty, b.Difficulty())
_, blocks, _ := core.GenerateChainWithGenesis(genesis, beaconConsensus.New(ethash.NewFaker()), n, generate)
if !merged {
totalDifficulty := big.NewInt(0)
for _, b := range blocks {
totalDifficulty.Add(totalDifficulty, b.Difficulty())
}
config.TerminalTotalDifficulty = totalDifficulty
}
config.TerminalTotalDifficulty = totalDifficulty
return genesis, blocks
}

func TestEth2AssembleBlock(t *testing.T) {
genesis, blocks := generatePreMergeChain(10)
genesis, blocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, blocks)
defer n.Close()

Expand Down Expand Up @@ -118,7 +126,7 @@ func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params
}

func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
genesis, blocks := generatePreMergeChain(10)
genesis, blocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, blocks[:9])
defer n.Close()

Expand All @@ -137,7 +145,7 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
}

func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
genesis, blocks := generatePreMergeChain(10)
genesis, blocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, blocks)
defer n.Close()

Expand All @@ -155,7 +163,7 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
}

func TestEth2PrepareAndGetPayload(t *testing.T) {
genesis, blocks := generatePreMergeChain(10)
genesis, blocks := generateChain(10, false)
// 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])
Expand Down Expand Up @@ -221,7 +229,7 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan co
}

func TestInvalidPayloadTimestamp(t *testing.T) {
genesis, preMergeBlocks := generatePreMergeChain(10)
genesis, preMergeBlocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, preMergeBlocks)
defer n.Close()
var (
Expand Down Expand Up @@ -265,7 +273,7 @@ func TestInvalidPayloadTimestamp(t *testing.T) {
}

func TestEth2NewBlock(t *testing.T) {
genesis, preMergeBlocks := generatePreMergeChain(10)
genesis, preMergeBlocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, preMergeBlocks)
defer n.Close()

Expand Down Expand Up @@ -367,7 +375,7 @@ 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)
genesis, preMergeBlocks := generateChain(core.TriesInMemory * 2, false)
n, ethservice := startEthService(t, genesis, preMergeBlocks)
defer n.Close()
Expand Down Expand Up @@ -442,7 +450,7 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block)
}

func TestFullAPI(t *testing.T) {
genesis, preMergeBlocks := generatePreMergeChain(10)
genesis, preMergeBlocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, preMergeBlocks)
defer n.Close()
var (
Expand Down Expand Up @@ -494,7 +502,7 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Bl
}

func TestExchangeTransitionConfig(t *testing.T) {
genesis, preMergeBlocks := generatePreMergeChain(10)
genesis, preMergeBlocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, preMergeBlocks)
defer n.Close()

Expand Down Expand Up @@ -555,7 +563,7 @@ We expect
└── P1''
*/
func TestNewPayloadOnInvalidChain(t *testing.T) {
genesis, preMergeBlocks := generatePreMergeChain(10)
genesis, preMergeBlocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, preMergeBlocks)
defer n.Close()

Expand Down Expand Up @@ -649,7 +657,7 @@ func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.Pay
}

func TestEmptyBlocks(t *testing.T) {
genesis, preMergeBlocks := generatePreMergeChain(10)
genesis, preMergeBlocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, preMergeBlocks)
defer n.Close()

Expand Down Expand Up @@ -765,7 +773,7 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {

func TestTrickRemoteBlockCache(t *testing.T) {
// Setup two nodes
genesis, preMergeBlocks := generatePreMergeChain(10)
genesis, preMergeBlocks := generateChain(10, false)
nodeA, ethserviceA := startEthService(t, genesis, preMergeBlocks)
nodeB, ethserviceB := startEthService(t, genesis, preMergeBlocks)
defer nodeA.Close()
Expand Down Expand Up @@ -828,7 +836,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
}

func TestInvalidBloom(t *testing.T) {
genesis, preMergeBlocks := generatePreMergeChain(10)
genesis, preMergeBlocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, preMergeBlocks)
ethservice.Merger().ReachTTD()
defer n.Close()
Expand All @@ -852,7 +860,7 @@ func TestInvalidBloom(t *testing.T) {
}

func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
genesis, preMergeBlocks := generatePreMergeChain(100)
genesis, preMergeBlocks := generateChain(100, false)
genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())

n, ethservice := startEthService(t, genesis, preMergeBlocks)
Expand Down Expand Up @@ -902,7 +910,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
// newPayLoad and forkchoiceUpdate. This is to test that the api behaves
// well even of the caller is not being 'serial'.
func TestSimultaneousNewBlock(t *testing.T) {
genesis, preMergeBlocks := generatePreMergeChain(10)
genesis, preMergeBlocks := generateChain(10, false)
n, ethservice := startEthService(t, genesis, preMergeBlocks)
defer n.Close()

Expand Down Expand Up @@ -985,3 +993,55 @@ func TestSimultaneousNewBlock(t *testing.T) {
parent = block
}
}

func TestEIP4844(t *testing.T) {
genesis, blocks := generateChain(10, true)
lastBlockTime := blocks[len(blocks)-1].Time()
genesis.Config.ShanghaiTime = new(uint64)
*genesis.Config.ShanghaiTime = lastBlockTime + 10 // chainmakers block time is fixed at 10 seconds
genesis.Config.ShardingForkTime = new(uint64)
*genesis.Config.ShardingForkTime = lastBlockTime + 10 // chainmakers block time is fixed at 10 seconds
genesis.Config.TerminalTotalDifficulty.Sub(genesis.Config.TerminalTotalDifficulty, blocks[0].Difficulty())

n, ethservice := startEthService(t, genesis, blocks)
ethservice.Merger().ReachTTD()
defer n.Close()

api := NewConsensusAPI(ethservice)

parent := ethservice.BlockChain().CurrentHeader()
params := beacon.PayloadAttributes{
Timestamp: parent.Time + 10,
}
fcState := beacon.ForkchoiceStateV1{
HeadBlockHash: parent.Hash(),
}
resp, err := api.ForkchoiceUpdatedV2(fcState, &params)
if err != nil {
t.Fatalf("error preparing payload, err=%v", err)
}
if resp.PayloadStatus.Status != beacon.VALID {
t.Fatalf("unexpected status (got: %s, want: %s)", resp.PayloadStatus.Status, beacon.VALID)
}

execData, err := api.GetPayloadV3(*resp.PayloadID)
if err != nil {
t.Fatalf("error getting payload, err=%v", err)
}
if status, err := api.NewPayloadV3(*execData); err != nil {
t.Fatalf("error validating payload: %v", err)
} else if status.Status != beacon.VALID {
t.Fatalf("invalid payload")
}

fcState.HeadBlockHash = execData.BlockHash
_, err = api.ForkchoiceUpdatedV2(fcState, nil)
if err != nil {
t.Fatalf("error preparing payload, err=%v", err)
}

block := ethservice.APIBackend.CurrentBlock()
if block.ExcessDataGas() == nil {
t.Fatal("latest block is missing excessDataGas")
}
}

0 comments on commit adac24d

Please sign in to comment.