all: implement withdrawals (EIP-4895) (#26484)
This change implements withdrawals as specified in EIP-4895. Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com> Co-authored-by: marioevz <marioevz@gmail.com> Co-authored-by: Martin Holst Swende <martin@swende.se> Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
co-authored by
lightclient@protonmail.com
marioevz
Martin Holst Swende
Felix Lange
parent
2b57a27d9e
commit
2a2b0419fb
+42
-4
@@ -155,7 +155,19 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI {
|
||||
//
|
||||
// If there are payloadAttributes: we try to assemble a block with the payloadAttributes
|
||||
// and return its payloadID.
|
||||
func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributesV1) (beacon.ForkChoiceResponse, error) {
|
||||
func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) {
|
||||
if payloadAttributes != nil && payloadAttributes.Withdrawals != nil {
|
||||
return beacon.STATUS_INVALID, fmt.Errorf("withdrawals not supported in V1")
|
||||
}
|
||||
return api.forkchoiceUpdated(update, payloadAttributes)
|
||||
}
|
||||
|
||||
// ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes.
|
||||
func (api *ConsensusAPI) ForkchoiceUpdatedV2(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) {
|
||||
return api.forkchoiceUpdated(update, payloadAttributes)
|
||||
}
|
||||
|
||||
func (api *ConsensusAPI) forkchoiceUpdated(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributes) (beacon.ForkChoiceResponse, error) {
|
||||
api.forkchoiceLock.Lock()
|
||||
defer api.forkchoiceLock.Unlock()
|
||||
|
||||
@@ -285,6 +297,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
|
||||
Timestamp: payloadAttributes.Timestamp,
|
||||
FeeRecipient: payloadAttributes.SuggestedFeeRecipient,
|
||||
Random: payloadAttributes.Random,
|
||||
Withdrawals: payloadAttributes.Withdrawals,
|
||||
}
|
||||
id := args.Id()
|
||||
// If we already are busy generating this work, then we do not need
|
||||
@@ -334,7 +347,20 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.Transit
|
||||
}
|
||||
|
||||
// GetPayloadV1 returns a cached payload by id.
|
||||
func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableDataV1, error) {
|
||||
func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableData, error) {
|
||||
data, err := api.getPayload(payloadID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data.ExecutionPayload, nil
|
||||
}
|
||||
|
||||
// GetPayloadV2 returns a cached payload by id.
|
||||
func (api *ConsensusAPI) GetPayloadV2(payloadID beacon.PayloadID) (*beacon.ExecutionPayloadEnvelope, error) {
|
||||
return api.getPayload(payloadID)
|
||||
}
|
||||
|
||||
func (api *ConsensusAPI) getPayload(payloadID beacon.PayloadID) (*beacon.ExecutionPayloadEnvelope, error) {
|
||||
log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID)
|
||||
data := api.localBlocks.get(payloadID)
|
||||
if data == nil {
|
||||
@@ -344,7 +370,19 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.Execu
|
||||
}
|
||||
|
||||
// NewPayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||
func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.PayloadStatusV1, error) {
|
||||
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")
|
||||
}
|
||||
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) {
|
||||
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
|
||||
@@ -361,7 +399,7 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa
|
||||
api.newPayloadLock.Lock()
|
||||
defer api.newPayloadLock.Unlock()
|
||||
|
||||
log.Trace("Engine API request received", "method", "ExecutePayload", "number", params.Number, "hash", params.BlockHash)
|
||||
log.Trace("Engine API request received", "method", "NewPayload", "number", params.Number, "hash", params.BlockHash)
|
||||
block, err := beacon.ExecutableDataToBlock(params)
|
||||
if err != nil {
|
||||
log.Debug("Invalid NewPayload params", "params", params, "error", err)
|
||||
|
||||
+168
-39
@@ -18,6 +18,7 @@ package catalyst
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
@@ -26,6 +27,8 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
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"
|
||||
@@ -38,6 +41,7 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -51,8 +55,14 @@ var (
|
||||
testBalance = big.NewInt(2e18)
|
||||
)
|
||||
|
||||
func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) {
|
||||
func generateMergeChain(n int, merged bool) (*core.Genesis, []*types.Block) {
|
||||
config := *params.AllEthashProtocolChanges
|
||||
engine := consensus.Engine(beaconConsensus.New(ethash.NewFaker()))
|
||||
if merged {
|
||||
config.TerminalTotalDifficulty = common.Big0
|
||||
config.TerminalTotalDifficultyPassed = true
|
||||
engine = beaconConsensus.NewFaker()
|
||||
}
|
||||
genesis := &core.Genesis{
|
||||
Config: &config,
|
||||
Alloc: core.GenesisAlloc{testAddr: {Balance: testBalance}},
|
||||
@@ -69,17 +79,21 @@ 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, engine, 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 := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, blocks)
|
||||
defer n.Close()
|
||||
|
||||
@@ -90,7 +104,7 @@ func TestEth2AssembleBlock(t *testing.T) {
|
||||
t.Fatalf("error signing transaction, err=%v", err)
|
||||
}
|
||||
ethservice.TxPool().AddLocal(tx)
|
||||
blockParams := beacon.PayloadAttributesV1{
|
||||
blockParams := beacon.PayloadAttributes{
|
||||
Timestamp: blocks[9].Time() + 5,
|
||||
}
|
||||
// The miner needs to pick up on the txs in the pool, so a few retries might be
|
||||
@@ -102,7 +116,7 @@ func TestEth2AssembleBlock(t *testing.T) {
|
||||
|
||||
// assembleWithTransactions tries to assemble a block, retrying until it has 'want',
|
||||
// number of transactions in it, or it has retried three times.
|
||||
func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributesV1, want int) (execData *beacon.ExecutableDataV1, err error) {
|
||||
func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributes, want int) (execData *beacon.ExecutableData, err error) {
|
||||
for retries := 3; retries > 0; retries-- {
|
||||
execData, err = assembleBlock(api, parentHash, params)
|
||||
if err != nil {
|
||||
@@ -118,7 +132,7 @@ func assembleWithTransactions(api *ConsensusAPI, parentHash common.Hash, params
|
||||
}
|
||||
|
||||
func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
|
||||
genesis, blocks := generatePreMergeChain(10)
|
||||
genesis, blocks := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, blocks[:9])
|
||||
defer n.Close()
|
||||
|
||||
@@ -126,7 +140,7 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
|
||||
|
||||
// Put the 10th block's tx in the pool and produce a new block
|
||||
api.eth.TxPool().AddRemotesSync(blocks[9].Transactions())
|
||||
blockParams := beacon.PayloadAttributesV1{
|
||||
blockParams := beacon.PayloadAttributes{
|
||||
Timestamp: blocks[8].Time() + 5,
|
||||
}
|
||||
// The miner needs to pick up on the txs in the pool, so a few retries might be
|
||||
@@ -137,7 +151,7 @@ func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
|
||||
genesis, blocks := generatePreMergeChain(10)
|
||||
genesis, blocks := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, blocks)
|
||||
defer n.Close()
|
||||
|
||||
@@ -155,7 +169,7 @@ func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEth2PrepareAndGetPayload(t *testing.T) {
|
||||
genesis, blocks := generatePreMergeChain(10)
|
||||
genesis, blocks := generateMergeChain(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])
|
||||
@@ -165,7 +179,7 @@ func TestEth2PrepareAndGetPayload(t *testing.T) {
|
||||
|
||||
// Put the 10th block's tx in the pool and produce a new block
|
||||
ethservice.TxPool().AddLocals(blocks[9].Transactions())
|
||||
blockParams := beacon.PayloadAttributesV1{
|
||||
blockParams := beacon.PayloadAttributes{
|
||||
Timestamp: blocks[8].Time() + 5,
|
||||
}
|
||||
fcState := beacon.ForkchoiceStateV1{
|
||||
@@ -221,7 +235,7 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan co
|
||||
}
|
||||
|
||||
func TestInvalidPayloadTimestamp(t *testing.T) {
|
||||
genesis, preMergeBlocks := generatePreMergeChain(10)
|
||||
genesis, preMergeBlocks := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
var (
|
||||
@@ -244,7 +258,7 @@ func TestInvalidPayloadTimestamp(t *testing.T) {
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("Timestamp test: %v", i), func(t *testing.T) {
|
||||
params := beacon.PayloadAttributesV1{
|
||||
params := beacon.PayloadAttributes{
|
||||
Timestamp: test.time,
|
||||
Random: crypto.Keccak256Hash([]byte{byte(123)}),
|
||||
SuggestedFeeRecipient: parent.Coinbase(),
|
||||
@@ -265,7 +279,7 @@ func TestInvalidPayloadTimestamp(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEth2NewBlock(t *testing.T) {
|
||||
genesis, preMergeBlocks := generatePreMergeChain(10)
|
||||
genesis, preMergeBlocks := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
|
||||
@@ -288,7 +302,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||
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)
|
||||
|
||||
execData, err := assembleWithTransactions(api, parent.Hash(), &beacon.PayloadAttributesV1{
|
||||
execData, err := assembleWithTransactions(api, parent.Hash(), &beacon.PayloadAttributes{
|
||||
Timestamp: parent.Time() + 5,
|
||||
}, 1)
|
||||
if err != nil {
|
||||
@@ -330,7 +344,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||
)
|
||||
parent = preMergeBlocks[len(preMergeBlocks)-1]
|
||||
for i := 0; i < 10; i++ {
|
||||
execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{
|
||||
execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributes{
|
||||
Timestamp: parent.Time() + 6,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -367,7 +381,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 := generateMergeChain(core.TriesInMemory * 2, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
|
||||
@@ -442,7 +456,7 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block)
|
||||
}
|
||||
|
||||
func TestFullAPI(t *testing.T) {
|
||||
genesis, preMergeBlocks := generatePreMergeChain(10)
|
||||
genesis, preMergeBlocks := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
var (
|
||||
@@ -494,7 +508,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 := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
|
||||
@@ -555,7 +569,7 @@ We expect
|
||||
└── P1''
|
||||
*/
|
||||
func TestNewPayloadOnInvalidChain(t *testing.T) {
|
||||
genesis, preMergeBlocks := generatePreMergeChain(10)
|
||||
genesis, preMergeBlocks := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
|
||||
@@ -577,7 +591,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) {
|
||||
})
|
||||
ethservice.TxPool().AddRemotesSync([]*types.Transaction{tx})
|
||||
var (
|
||||
params = beacon.PayloadAttributesV1{
|
||||
params = beacon.PayloadAttributes{
|
||||
Timestamp: parent.Time() + 1,
|
||||
Random: crypto.Keccak256Hash([]byte{byte(i)}),
|
||||
SuggestedFeeRecipient: parent.Coinbase(),
|
||||
@@ -587,7 +601,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) {
|
||||
SafeBlockHash: common.Hash{},
|
||||
FinalizedBlockHash: common.Hash{},
|
||||
}
|
||||
payload *beacon.ExecutableDataV1
|
||||
payload *beacon.ExecutableData
|
||||
resp beacon.ForkChoiceResponse
|
||||
err error
|
||||
)
|
||||
@@ -634,22 +648,23 @@ func TestNewPayloadOnInvalidChain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributesV1) (*beacon.ExecutableDataV1, error) {
|
||||
func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributes) (*beacon.ExecutableData, error) {
|
||||
args := &miner.BuildPayloadArgs{
|
||||
Parent: parentHash,
|
||||
Timestamp: params.Timestamp,
|
||||
FeeRecipient: params.SuggestedFeeRecipient,
|
||||
Random: params.Random,
|
||||
Withdrawals: params.Withdrawals,
|
||||
}
|
||||
payload, err := api.eth.Miner().BuildPayload(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload.ResolveFull(), nil
|
||||
return payload.ResolveFull().ExecutionPayload, nil
|
||||
}
|
||||
|
||||
func TestEmptyBlocks(t *testing.T) {
|
||||
genesis, preMergeBlocks := generatePreMergeChain(10)
|
||||
genesis, preMergeBlocks := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
|
||||
@@ -708,8 +723,8 @@ func TestEmptyBlocks(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon.ExecutableDataV1 {
|
||||
params := beacon.PayloadAttributesV1{
|
||||
func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon.ExecutableData {
|
||||
params := beacon.PayloadAttributes{
|
||||
Timestamp: parent.Time() + 1,
|
||||
Random: crypto.Keccak256Hash([]byte{byte(1)}),
|
||||
SuggestedFeeRecipient: parent.Coinbase(),
|
||||
@@ -724,7 +739,7 @@ func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon
|
||||
|
||||
// setBlockhash sets the blockhash of a modified ExecutableData.
|
||||
// Can be used to make modified payloads look valid.
|
||||
func setBlockhash(data *beacon.ExecutableDataV1) *beacon.ExecutableDataV1 {
|
||||
func setBlockhash(data *beacon.ExecutableData) *beacon.ExecutableData {
|
||||
txs, _ := decodeTransactions(data.Transactions)
|
||||
number := big.NewInt(0)
|
||||
number.SetUint64(data.Number)
|
||||
@@ -764,7 +779,7 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
||||
|
||||
func TestTrickRemoteBlockCache(t *testing.T) {
|
||||
// Setup two nodes
|
||||
genesis, preMergeBlocks := generatePreMergeChain(10)
|
||||
genesis, preMergeBlocks := generateMergeChain(10, false)
|
||||
nodeA, ethserviceA := startEthService(t, genesis, preMergeBlocks)
|
||||
nodeB, ethserviceB := startEthService(t, genesis, preMergeBlocks)
|
||||
defer nodeA.Close()
|
||||
@@ -783,7 +798,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
|
||||
setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Block) {})
|
||||
commonAncestor = ethserviceA.BlockChain().CurrentBlock()
|
||||
|
||||
var invalidChain []*beacon.ExecutableDataV1
|
||||
var invalidChain []*beacon.ExecutableData
|
||||
// create a valid payload (P1)
|
||||
//payload1 := getNewPayload(t, apiA, commonAncestor)
|
||||
//invalidChain = append(invalidChain, payload1)
|
||||
@@ -827,7 +842,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInvalidBloom(t *testing.T) {
|
||||
genesis, preMergeBlocks := generatePreMergeChain(10)
|
||||
genesis, preMergeBlocks := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
ethservice.Merger().ReachTTD()
|
||||
defer n.Close()
|
||||
@@ -851,12 +866,12 @@ func TestInvalidBloom(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
|
||||
genesis, preMergeBlocks := generatePreMergeChain(100)
|
||||
|
||||
genesis, preMergeBlocks := generateMergeChain(100, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
|
||||
genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())
|
||||
|
||||
var (
|
||||
api = NewConsensusAPI(ethservice)
|
||||
parent = preMergeBlocks[len(preMergeBlocks)-1]
|
||||
@@ -887,7 +902,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("error preparing payload, err=%v", err)
|
||||
}
|
||||
data := *payload.Resolve()
|
||||
data := *payload.Resolve().ExecutionPayload
|
||||
resp2, err := api.NewPayloadV1(data)
|
||||
if err != nil {
|
||||
t.Fatalf("error sending NewPayload, err=%v", err)
|
||||
@@ -901,7 +916,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 := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
|
||||
@@ -910,7 +925,7 @@ func TestSimultaneousNewBlock(t *testing.T) {
|
||||
parent = preMergeBlocks[len(preMergeBlocks)-1]
|
||||
)
|
||||
for i := 0; i < 10; i++ {
|
||||
execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{
|
||||
execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributes{
|
||||
Timestamp: parent.Time() + 5,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -984,3 +999,117 @@ func TestSimultaneousNewBlock(t *testing.T) {
|
||||
parent = block
|
||||
}
|
||||
}
|
||||
|
||||
// TestWithdrawals creates and verifies two post-Shanghai blocks. The first
|
||||
// includes zero withdrawals and the second includes two.
|
||||
func TestWithdrawals(t *testing.T) {
|
||||
genesis, blocks := generateMergeChain(10, true)
|
||||
// Set shanghai time to last block + 5 seconds (first post-merge block)
|
||||
time := blocks[len(blocks)-1].Time() + 5
|
||||
genesis.Config.ShanghaiTime = &time
|
||||
|
||||
n, ethservice := startEthService(t, genesis, blocks)
|
||||
ethservice.Merger().ReachTTD()
|
||||
defer n.Close()
|
||||
|
||||
api := NewConsensusAPI(ethservice)
|
||||
|
||||
// 10: Build Shanghai block with no withdrawals.
|
||||
parent := ethservice.BlockChain().CurrentHeader()
|
||||
blockParams := beacon.PayloadAttributes{
|
||||
Timestamp: parent.Time + 5,
|
||||
Withdrawals: make([]*types.Withdrawal, 0),
|
||||
}
|
||||
fcState := beacon.ForkchoiceStateV1{
|
||||
HeadBlockHash: parent.Hash(),
|
||||
}
|
||||
resp, err := api.ForkchoiceUpdatedV2(fcState, &blockParams)
|
||||
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)
|
||||
}
|
||||
|
||||
// 10: verify state root is the same as parent
|
||||
payloadID := (&miner.BuildPayloadArgs{
|
||||
Parent: fcState.HeadBlockHash,
|
||||
Timestamp: blockParams.Timestamp,
|
||||
FeeRecipient: blockParams.SuggestedFeeRecipient,
|
||||
Random: blockParams.Random,
|
||||
}).Id()
|
||||
execData, err := api.GetPayloadV2(payloadID)
|
||||
if err != nil {
|
||||
t.Fatalf("error getting payload, err=%v", err)
|
||||
}
|
||||
if execData.ExecutionPayload.StateRoot != parent.Root {
|
||||
t.Fatalf("mismatch state roots (got: %s, want: %s)", execData.ExecutionPayload.StateRoot, blocks[8].Root())
|
||||
}
|
||||
|
||||
// 10: verify locally built block
|
||||
if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil {
|
||||
t.Fatalf("error validating payload: %v", err)
|
||||
} else if status.Status != beacon.VALID {
|
||||
t.Fatalf("invalid payload")
|
||||
}
|
||||
|
||||
// 11: build shanghai block with withdrawal
|
||||
aa := common.Address{0xaa}
|
||||
bb := common.Address{0xbb}
|
||||
blockParams = beacon.PayloadAttributes{
|
||||
Timestamp: execData.ExecutionPayload.Timestamp + 5,
|
||||
Withdrawals: []*types.Withdrawal{
|
||||
{
|
||||
Index: 0,
|
||||
Address: aa,
|
||||
Amount: 32,
|
||||
},
|
||||
{
|
||||
Index: 1,
|
||||
Address: bb,
|
||||
Amount: 33,
|
||||
},
|
||||
},
|
||||
}
|
||||
fcState.HeadBlockHash = execData.ExecutionPayload.BlockHash
|
||||
_, err = api.ForkchoiceUpdatedV2(fcState, &blockParams)
|
||||
if err != nil {
|
||||
t.Fatalf("error preparing payload, err=%v", err)
|
||||
}
|
||||
|
||||
// 11: verify locally build block.
|
||||
payloadID = (&miner.BuildPayloadArgs{
|
||||
Parent: fcState.HeadBlockHash,
|
||||
Timestamp: blockParams.Timestamp,
|
||||
FeeRecipient: blockParams.SuggestedFeeRecipient,
|
||||
Random: blockParams.Random,
|
||||
}).Id()
|
||||
execData, err = api.GetPayloadV2(payloadID)
|
||||
if err != nil {
|
||||
t.Fatalf("error getting payload, err=%v", err)
|
||||
}
|
||||
if status, err := api.NewPayloadV2(*execData.ExecutionPayload); err != nil {
|
||||
t.Fatalf("error validating payload: %v", err)
|
||||
} else if status.Status != beacon.VALID {
|
||||
t.Fatalf("invalid payload")
|
||||
}
|
||||
|
||||
// 11: set block as head.
|
||||
fcState.HeadBlockHash = execData.ExecutionPayload.BlockHash
|
||||
_, err = api.ForkchoiceUpdatedV2(fcState, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("error preparing payload, err=%v", err)
|
||||
}
|
||||
|
||||
// 11: verify withdrawals were processed.
|
||||
db, _, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to load db: %v", err)
|
||||
}
|
||||
for i, w := range blockParams.Withdrawals {
|
||||
// w.Amount is in gwei, balance in wei
|
||||
if db.GetBalance(w.Address).Uint64() != w.Amount*params.GWei {
|
||||
t.Fatalf("failed to process withdrawal %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func (q *payloadQueue) put(id beacon.PayloadID, payload *miner.Payload) {
|
||||
}
|
||||
|
||||
// get retrieves a previously stored payload item or nil if it does not exist.
|
||||
func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutableDataV1 {
|
||||
func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutionPayloadEnvelope {
|
||||
q.lock.RLock()
|
||||
defer q.lock.RUnlock()
|
||||
|
||||
|
||||
@@ -1548,7 +1548,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error {
|
||||
)
|
||||
blocks := make([]*types.Block, len(results))
|
||||
for i, result := range results {
|
||||
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles)
|
||||
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals)
|
||||
}
|
||||
// Downloaded blocks are always regarded as trusted after the
|
||||
// transition. Because the downloaded chain is guided by the
|
||||
@@ -1748,7 +1748,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state
|
||||
blocks := make([]*types.Block, len(results))
|
||||
receipts := make([]types.Receipts, len(results))
|
||||
for i, result := range results {
|
||||
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles)
|
||||
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals)
|
||||
receipts[i] = result.Receipts
|
||||
}
|
||||
if index, err := d.blockchain.InsertReceiptChain(blocks, receipts, d.ancientLimit); err != nil {
|
||||
@@ -1759,7 +1759,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state
|
||||
}
|
||||
|
||||
func (d *Downloader) commitPivotBlock(result *fetchResult) error {
|
||||
block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles)
|
||||
block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals)
|
||||
log.Debug("Committing snap sync pivot as new head", "number", block.Number(), "hash", block.Hash())
|
||||
|
||||
// Commit the pivot block as the new head, will require full sync from here on
|
||||
|
||||
@@ -273,8 +273,9 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et
|
||||
rlp.DecodeBytes(blob, bodies[i])
|
||||
}
|
||||
var (
|
||||
txsHashes = make([]common.Hash, len(bodies))
|
||||
uncleHashes = make([]common.Hash, len(bodies))
|
||||
txsHashes = make([]common.Hash, len(bodies))
|
||||
uncleHashes = make([]common.Hash, len(bodies))
|
||||
withdrawalHashes = make([]common.Hash, len(bodies))
|
||||
)
|
||||
hasher := trie.NewStackTrie(nil)
|
||||
for i, body := range bodies {
|
||||
@@ -287,7 +288,7 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et
|
||||
res := ð.Response{
|
||||
Req: req,
|
||||
Res: (*eth.BlockBodiesPacket)(&bodies),
|
||||
Meta: [][]common.Hash{txsHashes, uncleHashes},
|
||||
Meta: [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes},
|
||||
Time: 1,
|
||||
Done: make(chan error, 1), // Ignore the returned status
|
||||
}
|
||||
|
||||
@@ -89,10 +89,10 @@ func (q *bodyQueue) request(peer *peerConnection, req *fetchRequest, resCh chan
|
||||
// deliver is responsible for taking a generic response packet from the concurrent
|
||||
// fetcher, unpacking the body data and delivering it to the downloader's queue.
|
||||
func (q *bodyQueue) deliver(peer *peerConnection, packet *eth.Response) (int, error) {
|
||||
txs, uncles := packet.Res.(*eth.BlockBodiesPacket).Unpack()
|
||||
hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes}
|
||||
txs, uncles, withdrawals := packet.Res.(*eth.BlockBodiesPacket).Unpack()
|
||||
hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes, withdrawal hashes}
|
||||
|
||||
accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1])
|
||||
accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1], withdrawals, hashsets[2])
|
||||
switch {
|
||||
case err == nil && len(txs) == 0:
|
||||
peer.log.Trace("Requested bodies delivered")
|
||||
|
||||
+11
-1
@@ -67,6 +67,7 @@ type fetchResult struct {
|
||||
Uncles []*types.Header
|
||||
Transactions types.Transactions
|
||||
Receipts types.Receipts
|
||||
Withdrawals types.Withdrawals
|
||||
}
|
||||
|
||||
func newFetchResult(header *types.Header, fastSync bool) *fetchResult {
|
||||
@@ -764,7 +765,9 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, hashes []comm
|
||||
// DeliverBodies injects a block body retrieval response into the results queue.
|
||||
// The method returns the number of blocks bodies accepted from the delivery and
|
||||
// also wakes any threads waiting for data delivery.
|
||||
func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListHashes []common.Hash, uncleLists [][]*types.Header, uncleListHashes []common.Hash) (int, error) {
|
||||
func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListHashes []common.Hash,
|
||||
uncleLists [][]*types.Header, uncleListHashes []common.Hash,
|
||||
withdrawalLists [][]*types.Withdrawal, withdrawalListHashes []common.Hash) (int, error) {
|
||||
q.lock.Lock()
|
||||
defer q.lock.Unlock()
|
||||
|
||||
@@ -775,12 +778,19 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH
|
||||
if uncleListHashes[index] != header.UncleHash {
|
||||
return errInvalidBody
|
||||
}
|
||||
if header.WithdrawalsHash == nil {
|
||||
// discard any withdrawals if we don't have a withdrawal hash set
|
||||
withdrawalLists[index] = nil
|
||||
} else if withdrawalListHashes[index] != *header.WithdrawalsHash {
|
||||
return errInvalidBody
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
reconstruct := func(index int, result *fetchResult) {
|
||||
result.Transactions = txLists[index]
|
||||
result.Uncles = uncleLists[index]
|
||||
result.Withdrawals = withdrawalLists[index]
|
||||
result.SetBodyDone()
|
||||
}
|
||||
return q.deliver(id, q.blockTaskPool, q.blockTaskQueue, q.blockPendPool,
|
||||
|
||||
@@ -339,7 +339,7 @@ func XTestDelivery(t *testing.T) {
|
||||
uncleHashes[i] = types.CalcUncleHash(uncles)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
_, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes)
|
||||
_, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes, nil, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("delivered %d bodies %v\n", len(txset), err)
|
||||
}
|
||||
|
||||
@@ -540,8 +540,8 @@ func (f *BlockFetcher) loop() {
|
||||
select {
|
||||
case res := <-resCh:
|
||||
res.Done <- nil
|
||||
|
||||
txs, uncles := res.Res.(*eth.BlockBodiesPacket).Unpack()
|
||||
// Ignoring withdrawals here, since the block fetcher is not used post-merge.
|
||||
txs, uncles, _ := res.Res.(*eth.BlockBodiesPacket).Unpack()
|
||||
f.FilterBodies(peer, txs, uncles, time.Now())
|
||||
|
||||
case <-timeout.C:
|
||||
|
||||
@@ -23,6 +23,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"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/rawdb"
|
||||
@@ -45,6 +47,8 @@ var (
|
||||
testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
)
|
||||
|
||||
func u64(val uint64) *uint64 { return &val }
|
||||
|
||||
// testBackend is a mock implementation of the live Ethereum message handler. Its
|
||||
// purpose is to allow testing the request/reply workflows and wire serialization
|
||||
// in the `eth` protocol without actually doing any data processing.
|
||||
@@ -56,21 +60,53 @@ type testBackend struct {
|
||||
|
||||
// newTestBackend creates an empty chain and wraps it into a mock backend.
|
||||
func newTestBackend(blocks int) *testBackend {
|
||||
return newTestBackendWithGenerator(blocks, nil)
|
||||
return newTestBackendWithGenerator(blocks, false, nil)
|
||||
}
|
||||
|
||||
// newTestBackend creates a chain with a number of explicitly defined blocks and
|
||||
// wraps it into a mock backend.
|
||||
func newTestBackendWithGenerator(blocks int, generator func(int, *core.BlockGen)) *testBackend {
|
||||
// Create a database pre-initialize with a genesis block
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, *core.BlockGen)) *testBackend {
|
||||
var (
|
||||
// Create a database pre-initialize with a genesis block
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
config = params.TestChainConfig
|
||||
engine consensus.Engine = ethash.NewFaker()
|
||||
)
|
||||
|
||||
if shanghai {
|
||||
config = ¶ms.ChainConfig{
|
||||
ChainID: big.NewInt(1),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: true,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ConstantinopleBlock: big.NewInt(0),
|
||||
PetersburgBlock: big.NewInt(0),
|
||||
IstanbulBlock: big.NewInt(0),
|
||||
MuirGlacierBlock: big.NewInt(0),
|
||||
BerlinBlock: big.NewInt(0),
|
||||
LondonBlock: big.NewInt(0),
|
||||
ArrowGlacierBlock: big.NewInt(0),
|
||||
GrayGlacierBlock: big.NewInt(0),
|
||||
MergeNetsplitBlock: big.NewInt(0),
|
||||
ShanghaiTime: u64(0),
|
||||
TerminalTotalDifficulty: big.NewInt(0),
|
||||
TerminalTotalDifficultyPassed: true,
|
||||
Ethash: new(params.EthashConfig),
|
||||
}
|
||||
engine = beacon.NewFaker()
|
||||
}
|
||||
|
||||
gspec := &core.Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Config: config,
|
||||
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}},
|
||||
}
|
||||
chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
|
||||
_, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, generator)
|
||||
_, bs, _ := core.GenerateChainWithGenesis(gspec, engine, blocks, generator)
|
||||
if _, err := chain.InsertChain(bs); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -305,7 +341,17 @@ func TestGetBlockBodies68(t *testing.T) { testGetBlockBodies(t, ETH68) }
|
||||
func testGetBlockBodies(t *testing.T, protocol uint) {
|
||||
t.Parallel()
|
||||
|
||||
backend := newTestBackend(maxBodiesServe + 15)
|
||||
gen := func(n int, g *core.BlockGen) {
|
||||
if n%2 == 0 {
|
||||
w := &types.Withdrawal{
|
||||
Address: common.Address{0xaa},
|
||||
Amount: 42,
|
||||
}
|
||||
g.AddWithdrawal(w)
|
||||
}
|
||||
}
|
||||
|
||||
backend := newTestBackendWithGenerator(maxBodiesServe+15, true, gen)
|
||||
defer backend.close()
|
||||
|
||||
peer, _ := newTestPeer("peer", protocol, backend)
|
||||
@@ -355,7 +401,7 @@ func testGetBlockBodies(t *testing.T, protocol uint) {
|
||||
block := backend.chain.GetBlockByNumber(uint64(num))
|
||||
hashes = append(hashes, block.Hash())
|
||||
if len(bodies) < tt.expected {
|
||||
bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
|
||||
bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles(), Withdrawals: block.Withdrawals()})
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -365,9 +411,10 @@ func testGetBlockBodies(t *testing.T, protocol uint) {
|
||||
hashes = append(hashes, hash)
|
||||
if tt.available[j] && len(bodies) < tt.expected {
|
||||
block := backend.chain.GetBlockByHash(hash)
|
||||
bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
|
||||
bodies = append(bodies, &BlockBody{Transactions: block.Transactions(), Uncles: block.Uncles(), Withdrawals: block.Withdrawals()})
|
||||
}
|
||||
}
|
||||
|
||||
// Send the hash request and verify the response
|
||||
p2p.Send(peer.app, GetBlockBodiesMsg, &GetBlockBodiesPacket66{
|
||||
RequestId: 123,
|
||||
@@ -426,7 +473,7 @@ func testGetNodeData(t *testing.T, protocol uint, drop bool) {
|
||||
}
|
||||
}
|
||||
// Assemble the test environment
|
||||
backend := newTestBackendWithGenerator(4, generator)
|
||||
backend := newTestBackendWithGenerator(4, false, generator)
|
||||
defer backend.close()
|
||||
|
||||
peer, _ := newTestPeer("peer", protocol, backend)
|
||||
@@ -544,7 +591,7 @@ func testGetBlockReceipts(t *testing.T, protocol uint) {
|
||||
}
|
||||
}
|
||||
// Assemble the test environment
|
||||
backend := newTestBackendWithGenerator(4, generator)
|
||||
backend := newTestBackendWithGenerator(4, false, generator)
|
||||
defer backend.close()
|
||||
|
||||
peer, _ := newTestPeer("peer", protocol, backend)
|
||||
|
||||
@@ -379,15 +379,19 @@ func handleBlockBodies66(backend Backend, msg Decoder, peer *Peer) error {
|
||||
}
|
||||
metadata := func() interface{} {
|
||||
var (
|
||||
txsHashes = make([]common.Hash, len(res.BlockBodiesPacket))
|
||||
uncleHashes = make([]common.Hash, len(res.BlockBodiesPacket))
|
||||
txsHashes = make([]common.Hash, len(res.BlockBodiesPacket))
|
||||
uncleHashes = make([]common.Hash, len(res.BlockBodiesPacket))
|
||||
withdrawalHashes = make([]common.Hash, len(res.BlockBodiesPacket))
|
||||
)
|
||||
hasher := trie.NewStackTrie(nil)
|
||||
for i, body := range res.BlockBodiesPacket {
|
||||
txsHashes[i] = types.DeriveSha(types.Transactions(body.Transactions), hasher)
|
||||
uncleHashes[i] = types.CalcUncleHash(body.Uncles)
|
||||
if body.Withdrawals != nil {
|
||||
withdrawalHashes[i] = types.DeriveSha(types.Withdrawals(body.Withdrawals), hasher)
|
||||
}
|
||||
}
|
||||
return [][]common.Hash{txsHashes, uncleHashes}
|
||||
return [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes}
|
||||
}
|
||||
return peer.dispatchResponse(&Response{
|
||||
id: res.RequestId,
|
||||
|
||||
@@ -239,19 +239,22 @@ type BlockBodiesRLPPacket66 struct {
|
||||
type BlockBody struct {
|
||||
Transactions []*types.Transaction // Transactions contained within a block
|
||||
Uncles []*types.Header // Uncles contained within a block
|
||||
Withdrawals []*types.Withdrawal `rlp:"optional"` // Withdrawals contained within a block
|
||||
}
|
||||
|
||||
// Unpack retrieves the transactions and uncles from the range packet and returns
|
||||
// them in a split flat format that's more consistent with the internal data structures.
|
||||
func (p *BlockBodiesPacket) Unpack() ([][]*types.Transaction, [][]*types.Header) {
|
||||
func (p *BlockBodiesPacket) Unpack() ([][]*types.Transaction, [][]*types.Header, [][]*types.Withdrawal) {
|
||||
// TODO(matt): add support for withdrawals to fetchers
|
||||
var (
|
||||
txset = make([][]*types.Transaction, len(*p))
|
||||
uncleset = make([][]*types.Header, len(*p))
|
||||
txset = make([][]*types.Transaction, len(*p))
|
||||
uncleset = make([][]*types.Header, len(*p))
|
||||
withdrawalset = make([][]*types.Withdrawal, len(*p))
|
||||
)
|
||||
for i, body := range *p {
|
||||
txset[i], uncleset[i] = body.Transactions, body.Uncles
|
||||
txset[i], uncleset[i], withdrawalset[i] = body.Transactions, body.Uncles, body.Withdrawals
|
||||
}
|
||||
return txset, uncleset
|
||||
return txset, uncleset, withdrawalset
|
||||
}
|
||||
|
||||
// GetNodeDataPacket represents a trie node data query.
|
||||
|
||||
Reference in New Issue
Block a user