mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 13:21:37 +00:00
eth/catalyst: add testing_commitBlockV1 (#34995)
Adds `testing_commitBlockV1`. It is the write companion of `testing_buildBlockV1`: it builds a block from the provided payload attributes and transactions on top of the current canonical head, inserts it, and sets it as the new head, returning the new head hash. --------- Co-authored-by: MariusVanDerWijden <m.vanderwijden@live.de>
This commit is contained in:
parent
7122ecc3eb
commit
8c540cb082
3 changed files with 117 additions and 4 deletions
|
|
@ -17,6 +17,7 @@
|
|||
package catalyst
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
|
|
@ -47,6 +48,31 @@ func (api *testingAPI) BuildBlockV1(parentHash common.Hash, payloadAttributes en
|
|||
if api.eth.BlockChain().CurrentBlock().Hash() != parentHash {
|
||||
return nil, errors.New("parentHash is not current head")
|
||||
}
|
||||
_, block, err := api.buildTestingBlock(payloadAttributes, transactions, extraData)
|
||||
return block, err
|
||||
}
|
||||
|
||||
// CommitBlockV1 builds a block from the supplied attributes and transactions, inserts
|
||||
// it into the chain, and sets it as the new canonical head. It is the equivalent of
|
||||
// BuildBlockV1 followed by engine_newPayload + engine_forkchoiceUpdated, but skips the
|
||||
// serialize/deserialize round-trip through ExecutableData. The block is built on top of
|
||||
// the current head.
|
||||
func (api *testingAPI) CommitBlockV1(ctx context.Context, payloadAttributes engine.PayloadAttributes, transactions *[]hexutil.Bytes, extraData *hexutil.Bytes) (common.Hash, error) {
|
||||
block, _, err := api.buildTestingBlock(payloadAttributes, transactions, extraData)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
if _, err := api.eth.BlockChain().InsertBlockWithoutSetHead(ctx, block, false); err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
if _, err := api.eth.BlockChain().SetCanonical(block); err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
return block.Hash(), nil
|
||||
}
|
||||
|
||||
func (api *testingAPI) buildTestingBlock(payloadAttributes engine.PayloadAttributes, transactions *[]hexutil.Bytes, extraData *hexutil.Bytes) (*types.Block, *engine.ExecutionPayloadEnvelope, error) {
|
||||
parentHash := api.eth.BlockChain().CurrentBlock().Hash()
|
||||
// If transactions is empty but not nil, build an empty block
|
||||
// If the transactions is nil, build a block with the current transactions from the txpool
|
||||
// If the transactions is not nil and not empty, build a block with the transactions
|
||||
|
|
@ -60,7 +86,7 @@ func (api *testingAPI) BuildBlockV1(parentHash common.Hash, payloadAttributes en
|
|||
var err error
|
||||
txs, err = engine.DecodeTransactions(dec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
extra := make([]byte, 0)
|
||||
|
|
|
|||
|
|
@ -119,3 +119,90 @@ func TestBuildBlockV1(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCommitBlockV1(t *testing.T) {
|
||||
genesis, blocks := generateMergeChain(5, true)
|
||||
n, ethservice := startEthService(t, genesis, blocks)
|
||||
defer n.Close()
|
||||
|
||||
api := &testingAPI{eth: ethservice}
|
||||
ctx := context.Background()
|
||||
|
||||
nextAttrs := func() engine.PayloadAttributes {
|
||||
head := ethservice.BlockChain().CurrentBlock()
|
||||
return engine.PayloadAttributes{
|
||||
Timestamp: head.Time + 1,
|
||||
Random: crypto.Keccak256Hash([]byte("commit-test")),
|
||||
SuggestedFeeRecipient: head.Coinbase,
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("commitEmptyBlock", func(t *testing.T) {
|
||||
parent := ethservice.BlockChain().CurrentBlock()
|
||||
emptyTxs := []hexutil.Bytes{}
|
||||
hash, err := api.CommitBlockV1(ctx, nextAttrs(), &emptyTxs, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("CommitBlockV1 failed: %v", err)
|
||||
}
|
||||
head := ethservice.BlockChain().CurrentBlock()
|
||||
if head.Hash() != hash {
|
||||
t.Errorf("head hash mismatch: got %x want %x", head.Hash(), hash)
|
||||
}
|
||||
if head.Number.Uint64() != parent.Number.Uint64()+1 {
|
||||
t.Errorf("head number mismatch: got %d want %d", head.Number.Uint64(), parent.Number.Uint64()+1)
|
||||
}
|
||||
block := ethservice.BlockChain().GetBlockByHash(hash)
|
||||
if block == nil {
|
||||
t.Fatal("committed block not found in chain")
|
||||
}
|
||||
if len(block.Transactions()) != 0 {
|
||||
t.Errorf("expected empty block, got %d transactions", len(block.Transactions()))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("commitBlockWithTransactions", func(t *testing.T) {
|
||||
parent := ethservice.BlockChain().CurrentBlock()
|
||||
nonce, _ := ethservice.APIBackend.GetPoolNonce(ctx, testAddr)
|
||||
tx, _ := types.SignTx(types.NewTransaction(nonce, testAddr, big.NewInt(1), params.TxGas, big.NewInt(params.InitialBaseFee*2), nil), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
|
||||
enc, _ := tx.MarshalBinary()
|
||||
txs := []hexutil.Bytes{enc}
|
||||
|
||||
hash, err := api.CommitBlockV1(ctx, nextAttrs(), &txs, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("CommitBlockV1 failed: %v", err)
|
||||
}
|
||||
head := ethservice.BlockChain().CurrentBlock()
|
||||
if head.Hash() != hash {
|
||||
t.Errorf("head hash mismatch: got %x want %x", head.Hash(), hash)
|
||||
}
|
||||
if head.Number.Uint64() != parent.Number.Uint64()+1 {
|
||||
t.Errorf("head number mismatch: got %d want %d", head.Number.Uint64(), parent.Number.Uint64()+1)
|
||||
}
|
||||
block := ethservice.BlockChain().GetBlockByHash(hash)
|
||||
if block == nil {
|
||||
t.Fatal("committed block not found in chain")
|
||||
}
|
||||
if len(block.Transactions()) != 1 {
|
||||
t.Fatalf("expected 1 transaction, got %d", len(block.Transactions()))
|
||||
}
|
||||
if block.Transactions()[0].Hash() != tx.Hash() {
|
||||
t.Errorf("transaction hash mismatch: got %x want %x", block.Transactions()[0].Hash(), tx.Hash())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("commitWithExtraData", func(t *testing.T) {
|
||||
extra := hexutil.Bytes([]byte("hello"))
|
||||
emptyTxs := []hexutil.Bytes{}
|
||||
hash, err := api.CommitBlockV1(ctx, nextAttrs(), &emptyTxs, &extra)
|
||||
if err != nil {
|
||||
t.Fatalf("CommitBlockV1 failed: %v", err)
|
||||
}
|
||||
block := ethservice.BlockChain().GetBlockByHash(hash)
|
||||
if block == nil {
|
||||
t.Fatal("committed block not found in chain")
|
||||
}
|
||||
if string(block.Extra()) != "hello" {
|
||||
t.Errorf("extraData mismatch: got %q want %q", block.Extra(), "hello")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ func (payload *Payload) updateSpanForDelivery(bSpan trace.Span) {
|
|||
|
||||
// BuildTestingPayload is for testing_buildBlockV*. It creates a block with the exact content given
|
||||
// by the parameters instead of using the locally available transactions.
|
||||
func (miner *Miner) BuildTestingPayload(args *BuildPayloadArgs, transactions []*types.Transaction, empty bool, extraData []byte) (*engine.ExecutionPayloadEnvelope, error) {
|
||||
func (miner *Miner) BuildTestingPayload(args *BuildPayloadArgs, transactions []*types.Transaction, empty bool, extraData []byte) (*types.Block, *engine.ExecutionPayloadEnvelope, error) {
|
||||
fullParams := &generateParams{
|
||||
timestamp: args.Timestamp,
|
||||
forceTime: true,
|
||||
|
|
@ -358,7 +358,7 @@ func (miner *Miner) BuildTestingPayload(args *BuildPayloadArgs, transactions []*
|
|||
}
|
||||
res := miner.generateWork(context.Background(), fullParams, false)
|
||||
if res.err != nil {
|
||||
return nil, res.err
|
||||
return nil, nil, res.err
|
||||
}
|
||||
return engine.BlockToExecutableData(res.block, res.fees, res.sidecars, res.requests), nil
|
||||
return res.block, engine.BlockToExecutableData(res.block, res.fees, res.sidecars, res.requests), nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue