mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 08:49:29 +00:00
Merge 75e4fe44c5 into 12eabbd76d
This commit is contained in:
commit
123b9dd15e
3 changed files with 162 additions and 3 deletions
|
|
@ -17,6 +17,7 @@
|
||||||
package catalyst
|
package catalyst
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||||
|
|
@ -78,3 +79,52 @@ func (api *testingAPI) BuildBlockV1(parentHash common.Hash, payloadAttributes en
|
||||||
}
|
}
|
||||||
return api.eth.Miner().BuildTestingPayload(args, txs, buildEmpty, extra)
|
return api.eth.Miner().BuildTestingPayload(args, txs, buildEmpty, extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
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
|
||||||
|
buildEmpty := transactions != nil && len(*transactions) == 0
|
||||||
|
var txs []*types.Transaction
|
||||||
|
if transactions != nil {
|
||||||
|
dec := make([][]byte, 0, len(*transactions))
|
||||||
|
for _, tx := range *transactions {
|
||||||
|
dec = append(dec, tx)
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
txs, err = engine.DecodeTransactions(dec)
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extra := make([]byte, 0)
|
||||||
|
if extraData != nil {
|
||||||
|
extra = *extraData
|
||||||
|
}
|
||||||
|
args := &miner.BuildPayloadArgs{
|
||||||
|
Parent: parentHash,
|
||||||
|
Timestamp: payloadAttributes.Timestamp,
|
||||||
|
FeeRecipient: payloadAttributes.SuggestedFeeRecipient,
|
||||||
|
Random: payloadAttributes.Random,
|
||||||
|
Withdrawals: payloadAttributes.Withdrawals,
|
||||||
|
BeaconRoot: payloadAttributes.BeaconRoot,
|
||||||
|
SlotNum: payloadAttributes.SlotNumber,
|
||||||
|
}
|
||||||
|
block, err := api.eth.Miner().CommitTestingBlock(args, txs, buildEmpty, extra)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -339,9 +339,10 @@ func (payload *Payload) updateSpanForDelivery(bSpan trace.Span) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildTestingPayload is for testing_buildBlockV*. It creates a block with the exact content given
|
// buildTestingBlock runs generateWork with the override flags used by the testing_
|
||||||
// by the parameters instead of using the locally available transactions.
|
// namespace, producing a block whose contents are dictated by the caller rather than
|
||||||
func (miner *Miner) BuildTestingPayload(args *BuildPayloadArgs, transactions []*types.Transaction, empty bool, extraData []byte) (*engine.ExecutionPayloadEnvelope, error) {
|
// drawn from the local txpool.
|
||||||
|
func (miner *Miner) buildTestingBlock(args *BuildPayloadArgs, transactions []*types.Transaction, empty bool, extraData []byte) (*newPayloadResult, error) {
|
||||||
fullParams := &generateParams{
|
fullParams := &generateParams{
|
||||||
timestamp: args.Timestamp,
|
timestamp: args.Timestamp,
|
||||||
forceTime: true,
|
forceTime: true,
|
||||||
|
|
@ -360,5 +361,26 @@ func (miner *Miner) BuildTestingPayload(args *BuildPayloadArgs, transactions []*
|
||||||
if res.err != nil {
|
if res.err != nil {
|
||||||
return nil, res.err
|
return nil, res.err
|
||||||
}
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
res, err := miner.buildTestingBlock(args, transactions, empty, extraData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return engine.BlockToExecutableData(res.block, res.fees, res.sidecars, res.requests), nil
|
return engine.BlockToExecutableData(res.block, res.fees, res.sidecars, res.requests), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CommitTestingBlock is for testing_commitBlockV*. Like BuildTestingPayload it generates
|
||||||
|
// a block from the caller-supplied parameters, but returns the raw block so the caller
|
||||||
|
// can insert and canonicalize it without an ExecutableData round-trip.
|
||||||
|
func (miner *Miner) CommitTestingBlock(args *BuildPayloadArgs, transactions []*types.Transaction, empty bool, extraData []byte) (*types.Block, error) {
|
||||||
|
res, err := miner.buildTestingBlock(args, transactions, empty, extraData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.block, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue