forked from cerc-io/plugeth
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
@@ -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