mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
eth/protocols/eth: reimplement eth/68 receipts
This commit is contained in:
parent
6b193040bd
commit
12eade0fef
7 changed files with 363 additions and 144 deletions
|
|
@ -176,7 +176,7 @@ var eth68 = map[uint64]msgHandler{
|
|||
GetBlockBodiesMsg: handleGetBlockBodies,
|
||||
BlockBodiesMsg: handleBlockBodies,
|
||||
GetReceiptsMsg: handleGetReceipts68,
|
||||
ReceiptsMsg: handleReceipts68,
|
||||
ReceiptsMsg: handleReceipts[*ReceiptList68],
|
||||
GetPooledTransactionsMsg: handleGetPooledTransactions,
|
||||
PooledTransactionsMsg: handlePooledTransactions,
|
||||
}
|
||||
|
|
@ -189,7 +189,7 @@ var eth69 = map[uint64]msgHandler{
|
|||
GetBlockBodiesMsg: handleGetBlockBodies,
|
||||
BlockBodiesMsg: handleBlockBodies,
|
||||
GetReceiptsMsg: handleGetReceipts69,
|
||||
ReceiptsMsg: handleReceipts69,
|
||||
ReceiptsMsg: handleReceipts[*ReceiptList69],
|
||||
GetPooledTransactionsMsg: handleGetPooledTransactions,
|
||||
PooledTransactionsMsg: handlePooledTransactions,
|
||||
BlockRangeUpdateMsg: handleBlockRangeUpdate,
|
||||
|
|
|
|||
|
|
@ -529,22 +529,23 @@ func testGetBlockReceipts(t *testing.T, protocol uint) {
|
|||
// Collect the hashes to request, and the response to expect
|
||||
var (
|
||||
hashes []common.Hash
|
||||
receipts []types.Receipts
|
||||
receipts []*ReceiptList68
|
||||
)
|
||||
for i := uint64(0); i <= backend.chain.CurrentBlock().Number.Uint64(); i++ {
|
||||
block := backend.chain.GetBlockByNumber(i)
|
||||
|
||||
hashes = append(hashes, block.Hash())
|
||||
receipts = append(receipts, backend.chain.GetReceiptsByHash(block.Hash()))
|
||||
trs := backend.chain.GetReceiptsByHash(block.Hash())
|
||||
receipts = append(receipts, NewReceiptList68(trs))
|
||||
}
|
||||
|
||||
// Send the hash request and verify the response
|
||||
p2p.Send(peer.app, GetReceiptsMsg, &GetReceiptsPacket{
|
||||
RequestId: 123,
|
||||
GetReceiptsRequest: hashes,
|
||||
})
|
||||
if err := p2p.ExpectMsg(peer.app, ReceiptsMsg, &ReceiptsPacket{
|
||||
RequestId: 123,
|
||||
ReceiptsResponse: receipts,
|
||||
if err := p2p.ExpectMsg(peer.app, ReceiptsMsg, &ReceiptsPacket[*ReceiptList68]{
|
||||
RequestId: 123,
|
||||
List: receipts,
|
||||
}); err != nil {
|
||||
t.Errorf("receipts mismatch: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,19 +282,25 @@ func ServiceGetReceiptsQuery68(chain *core.BlockChain, query GetReceiptsRequest)
|
|||
break
|
||||
}
|
||||
// Retrieve the requested block's receipts
|
||||
results := chain.GetReceiptsByHash(hash)
|
||||
results := chain.GetRawReceiptsByHash(hash)
|
||||
if results == nil {
|
||||
if header := chain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash {
|
||||
continue
|
||||
}
|
||||
}
|
||||
// If known, encode and queue for response packet
|
||||
if encoded, err := rlp.EncodeToBytes(results); err != nil {
|
||||
log.Error("Failed to encode receipt", "err", err)
|
||||
} else {
|
||||
receipts = append(receipts, encoded)
|
||||
bytes += len(encoded)
|
||||
body := chain.GetBodyRLP(hash)
|
||||
if body == nil {
|
||||
continue
|
||||
}
|
||||
var err error
|
||||
results, err = blockReceiptsToNetwork68(results, body)
|
||||
if err != nil {
|
||||
log.Error("Error in block receipts conversion", "hash", hash, "err", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
receipts = append(receipts, results)
|
||||
bytes += len(results)
|
||||
}
|
||||
return receipts
|
||||
}
|
||||
|
|
@ -324,7 +330,7 @@ func serviceGetReceiptsQuery69(chain *core.BlockChain, query GetReceiptsRequest)
|
|||
continue
|
||||
}
|
||||
var err error
|
||||
results, err = blockReceiptsToNetwork(results, body)
|
||||
results, err = blockReceiptsToNetwork69(results, body)
|
||||
if err != nil {
|
||||
log.Error("Error in block receipts conversion", "hash", hash, "err", err)
|
||||
continue
|
||||
|
|
@ -393,53 +399,30 @@ func handleBlockBodies(backend Backend, msg Decoder, peer *Peer) error {
|
|||
}, metadata)
|
||||
}
|
||||
|
||||
func handleReceipts68(backend Backend, msg Decoder, peer *Peer) error {
|
||||
func handleReceipts[L ReceiptsList](backend Backend, msg Decoder, peer *Peer) error {
|
||||
// A batch of receipts arrived to one of our previous requests
|
||||
res := new(ReceiptsPacket)
|
||||
res := new(ReceiptsPacket[L])
|
||||
if err := msg.Decode(res); err != nil {
|
||||
return err
|
||||
}
|
||||
metadata := func() interface{} {
|
||||
hasher := trie.NewStackTrie(nil)
|
||||
hashes := make([]common.Hash, len(res.ReceiptsResponse))
|
||||
for i, receipt := range res.ReceiptsResponse {
|
||||
hashes[i] = types.DeriveSha(receipt, hasher)
|
||||
}
|
||||
return hashes
|
||||
}
|
||||
encoded := ReceiptsRLPResponse(types.ReceiptsToRLP(res.ReceiptsResponse))
|
||||
return peer.dispatchResponse(&Response{
|
||||
id: res.RequestId,
|
||||
code: ReceiptsMsg,
|
||||
Res: &encoded,
|
||||
}, metadata)
|
||||
}
|
||||
|
||||
func handleReceipts69(backend Backend, msg Decoder, peer *Peer) error {
|
||||
// A batch of receipts arrived to one of our previous requests
|
||||
var res ReceiptsPacket69
|
||||
if err := msg.Decode(&res); err != nil {
|
||||
return err
|
||||
}
|
||||
// Assign temporary hashing buffer to each list item, the same buffer is shared
|
||||
// between all receipt list instances.
|
||||
buffers := new(receiptListBuffers)
|
||||
for i := range res.List {
|
||||
res.List[i].buf = buffers
|
||||
res.List[i].setBuffers(buffers)
|
||||
}
|
||||
metadata := func() any {
|
||||
|
||||
metadata := func() interface{} {
|
||||
hasher := trie.NewStackTrie(nil)
|
||||
hashes := make([]common.Hash, len(res.List))
|
||||
for i := range res.List {
|
||||
hashes[i] = types.DeriveSha(&res.List[i], hasher)
|
||||
hashes[i] = types.DeriveSha(res.List[i], hasher)
|
||||
}
|
||||
return hashes
|
||||
}
|
||||
|
||||
// TODO this can probably be made 0-alloc.
|
||||
var enc ReceiptsRLPResponse
|
||||
for i := range res.List {
|
||||
enc = append(enc, res.List[i].toStorageReceiptsRLP())
|
||||
enc = append(enc, res.List[i].EncodeForStorage())
|
||||
}
|
||||
return peer.dispatchResponse(&Response{
|
||||
id: res.RequestId,
|
||||
|
|
|
|||
|
|
@ -265,18 +265,19 @@ type GetReceiptsPacket struct {
|
|||
// ReceiptsResponse is the network packet for block receipts distribution.
|
||||
type ReceiptsResponse []types.Receipts
|
||||
|
||||
// ReceiptsPacket is the network packet for block receipts distribution with
|
||||
// request ID wrapping.
|
||||
type ReceiptsPacket struct {
|
||||
RequestId uint64
|
||||
ReceiptsResponse
|
||||
// ReceiptsList is a type constraint for block receceipt list types.
|
||||
type ReceiptsList interface {
|
||||
*ReceiptList68 | *ReceiptList69
|
||||
setBuffers(*receiptListBuffers)
|
||||
EncodeForStorage() rlp.RawValue
|
||||
types.DerivableList
|
||||
}
|
||||
|
||||
// ReceiptsPacket is the network packet for block receipts distribution with
|
||||
// request ID wrapping.
|
||||
type ReceiptsPacket69 struct {
|
||||
type ReceiptsPacket[L ReceiptsList] struct {
|
||||
RequestId uint64
|
||||
List []ReceiptList69
|
||||
List []L
|
||||
}
|
||||
|
||||
// ReceiptsRLPResponse is used for receipts, when we already have it encoded
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ func TestEmptyMessages(t *testing.T) {
|
|||
// All empty messages encodes to the same format
|
||||
want := common.FromHex("c4820457c0")
|
||||
|
||||
for i, msg := range []interface{}{
|
||||
for i, msg := range []any{
|
||||
// Headers
|
||||
GetBlockHeadersPacket{1111, nil},
|
||||
BlockHeadersPacket{1111, nil},
|
||||
|
|
@ -85,7 +85,6 @@ func TestEmptyMessages(t *testing.T) {
|
|||
BlockBodiesRLPPacket{1111, nil},
|
||||
// Receipts
|
||||
GetReceiptsPacket{1111, nil},
|
||||
ReceiptsPacket{1111, nil},
|
||||
// Transactions
|
||||
GetPooledTransactionsPacket{1111, nil},
|
||||
PooledTransactionsPacket{1111, nil},
|
||||
|
|
@ -99,7 +98,8 @@ func TestEmptyMessages(t *testing.T) {
|
|||
BlockBodiesRLPPacket{1111, BlockBodiesRLPResponse([]rlp.RawValue{})},
|
||||
// Receipts
|
||||
GetReceiptsPacket{1111, GetReceiptsRequest([]common.Hash{})},
|
||||
ReceiptsPacket{1111, ReceiptsResponse([]types.Receipts{})},
|
||||
ReceiptsPacket[*ReceiptList68]{1111, []*ReceiptList68{}},
|
||||
ReceiptsPacket[*ReceiptList69]{1111, []*ReceiptList69{}},
|
||||
// Transactions
|
||||
GetPooledTransactionsPacket{1111, GetPooledTransactionsRequest([]common.Hash{})},
|
||||
PooledTransactionsPacket{1111, PooledTransactionsResponse([]*types.Transaction{})},
|
||||
|
|
@ -168,7 +168,7 @@ func TestMessages(t *testing.T) {
|
|||
receipts = []*types.Receipt{
|
||||
{
|
||||
Status: types.ReceiptStatusFailed,
|
||||
CumulativeGasUsed: 1,
|
||||
CumulativeGasUsed: 333,
|
||||
Logs: []*types.Log{
|
||||
{
|
||||
Address: common.BytesToAddress([]byte{0x11}),
|
||||
|
|
@ -176,11 +176,21 @@ func TestMessages(t *testing.T) {
|
|||
Data: []byte{0x01, 0x00, 0xff},
|
||||
},
|
||||
},
|
||||
TxHash: hashes[0],
|
||||
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
|
||||
GasUsed: 111111,
|
||||
},
|
||||
{
|
||||
Status: types.ReceiptStatusSuccessful,
|
||||
CumulativeGasUsed: 444,
|
||||
Logs: []*types.Log{
|
||||
{
|
||||
Address: common.BytesToAddress([]byte{0x22}),
|
||||
Topics: []common.Hash{common.HexToHash("05668"), common.HexToHash("9773")},
|
||||
Data: []byte{0x02, 0x0f, 0x0f, 0x0f, 0x06, 0x08},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
miniDeriveFields(receipts[0], 0)
|
||||
miniDeriveFields(receipts[1], 1)
|
||||
rlpData, err := rlp.EncodeToBytes(receipts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -221,12 +231,17 @@ func TestMessages(t *testing.T) {
|
|||
common.FromHex("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"),
|
||||
},
|
||||
{
|
||||
ReceiptsPacket{1111, ReceiptsResponse([]types.Receipts{receipts})},
|
||||
common.FromHex("f90172820457f9016cf90169f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff"),
|
||||
ReceiptsPacket[*ReceiptList68]{1111, []*ReceiptList68{NewReceiptList68(receipts)}},
|
||||
common.FromHex("f902e6820457f902e0f902ddf901688082014db9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000004000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ffb9016f01f9016b018201bcb9010000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000001000000000000000000000000000000000000000000000000040000000000000000000000000004000000000000000000000000000000000000000000000000000000008000400000000000000000000000000000000000000000000000000000000000000000000000000000040f862f860940000000000000000000000000000000000000022f842a00000000000000000000000000000000000000000000000000000000000005668a0000000000000000000000000000000000000000000000000000000000000977386020f0f0f0608"),
|
||||
},
|
||||
{
|
||||
// Identical to the eth/68 encoding above.
|
||||
ReceiptsRLPPacket{1111, ReceiptsRLPResponse([]rlp.RawValue{receiptsRlp})},
|
||||
common.FromHex("f90172820457f9016cf90169f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff"),
|
||||
common.FromHex("f902e6820457f902e0f902ddf901688082014db9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000004000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ffb9016f01f9016b018201bcb9010000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000001000000000000000000000000000000000000000000000000040000000000000000000000000004000000000000000000000000000000000000000000000000000000008000400000000000000000000000000000000000000000000000000000000000000000000000000000040f862f860940000000000000000000000000000000000000022f842a00000000000000000000000000000000000000000000000000000000000005668a0000000000000000000000000000000000000000000000000000000000000977386020f0f0f0608"),
|
||||
},
|
||||
{
|
||||
ReceiptsPacket[*ReceiptList69]{1111, []*ReceiptList69{NewReceiptList69(receipts)}},
|
||||
common.FromHex("f8da820457f8d5f8d3f866808082014df85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff86901018201bcf862f860940000000000000000000000000000000000000022f842a00000000000000000000000000000000000000000000000000000000000005668a0000000000000000000000000000000000000000000000000000000000000977386020f0f0f0608"),
|
||||
},
|
||||
{
|
||||
GetPooledTransactionsPacket{1111, GetPooledTransactionsRequest(hashes)},
|
||||
|
|
|
|||
|
|
@ -19,13 +19,18 @@ package eth
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"iter"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// Receipt is the eth/69 network encoding of a receipt.
|
||||
// This is just a sanity limit for the size of a single receipt.
|
||||
const maxReceiptSize = 16 * 1024 * 1024
|
||||
|
||||
// Receipt is the representation of receipts for networking purposes.
|
||||
type Receipt struct {
|
||||
TxType byte
|
||||
PostStateOrStatus []byte
|
||||
|
|
@ -33,38 +38,91 @@ type Receipt struct {
|
|||
Logs rlp.RawValue
|
||||
}
|
||||
|
||||
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
||||
if _, err := s.List(); err != nil {
|
||||
func newReceipt(tr *types.Receipt) Receipt {
|
||||
r := Receipt{TxType: tr.Type, GasUsed: tr.CumulativeGasUsed}
|
||||
if tr.PostState != nil {
|
||||
r.PostStateOrStatus = tr.PostState
|
||||
} else {
|
||||
r.PostStateOrStatus = new(big.Int).SetUint64(tr.Status).Bytes()
|
||||
}
|
||||
r.Logs, _ = rlp.EncodeToBytes(tr.Logs)
|
||||
return r
|
||||
}
|
||||
|
||||
// decode68 parses a receipt in the eth/68 network encoding.
|
||||
func (r *Receipt) decode68(buf *receiptListBuffers, s *rlp.Stream) error {
|
||||
k, size, err := s.Kind()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
txtype, err := s.Uint8()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid txType: %w", err)
|
||||
|
||||
*r = Receipt{}
|
||||
if k == rlp.List {
|
||||
// Legacy receipt.
|
||||
return r.decodeInnerList(s, false, true)
|
||||
}
|
||||
postStateOrStatus, err := s.Bytes()
|
||||
// Typed receipt.
|
||||
if size < 2 || size > maxReceiptSize {
|
||||
return fmt.Errorf("invalid receipt size %d", size)
|
||||
}
|
||||
buf.tmp.Reset()
|
||||
buf.tmp.Grow(int(size))
|
||||
payload := buf.tmp.Bytes()[:int(size)]
|
||||
if err := s.ReadBytes(payload); err != nil {
|
||||
return err
|
||||
}
|
||||
r.TxType = payload[0]
|
||||
s2 := rlp.NewStream(bytes.NewReader(payload[1:]), 0)
|
||||
return r.decodeInnerList(s2, false, true)
|
||||
}
|
||||
|
||||
// decode69 parses a receipt in the eth/69 network encoding.
|
||||
func (r *Receipt) decode69(s *rlp.Stream) error {
|
||||
*r = Receipt{}
|
||||
return r.decodeInnerList(s, true, false)
|
||||
}
|
||||
|
||||
// decodeDatabase parses a receipt in the basic database encoding.
|
||||
func (r *Receipt) decodeDatabase(txType byte, s *rlp.Stream) error {
|
||||
*r = Receipt{TxType: txType}
|
||||
return r.decodeInnerList(s, false, false)
|
||||
}
|
||||
|
||||
func (r *Receipt) decodeInnerList(s *rlp.Stream, readTxType, readBloom bool) error {
|
||||
_, err := s.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if readTxType {
|
||||
r.TxType, err = s.Uint8()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid txType: %w", err)
|
||||
}
|
||||
}
|
||||
r.PostStateOrStatus, err = s.Bytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid postStateOrStatus: %w", err)
|
||||
}
|
||||
gasUsed, err := s.Uint64()
|
||||
r.GasUsed, err = s.Uint64()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid gasUsed: %w", err)
|
||||
}
|
||||
logs, err := s.Raw()
|
||||
if readBloom {
|
||||
var b types.Bloom
|
||||
if err := s.ReadBytes(b[:]); err != nil {
|
||||
return fmt.Errorf("invalid bloom: %v", err)
|
||||
}
|
||||
}
|
||||
r.Logs, err = s.Raw()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid logs: %w", err)
|
||||
}
|
||||
*r = Receipt{
|
||||
TxType: txtype,
|
||||
PostStateOrStatus: postStateOrStatus,
|
||||
GasUsed: gasUsed,
|
||||
Logs: logs,
|
||||
}
|
||||
return s.ListEnd()
|
||||
}
|
||||
|
||||
// encodeStorage writes the storage encoding, i.e. the result matches
|
||||
// types.ReceiptForStorage.
|
||||
func (r *Receipt) encodeStorage(w *rlp.EncoderBuffer) {
|
||||
// encodeForStorage produces the the storage encoding, i.e. the result matches
|
||||
// the RLP encoding of types.ReceiptForStorage.
|
||||
func (r *Receipt) encodeForStorage(w *rlp.EncoderBuffer) {
|
||||
list := w.List()
|
||||
w.WriteBytes(r.PostStateOrStatus)
|
||||
w.WriteUint64(r.GasUsed)
|
||||
|
|
@ -72,6 +130,60 @@ func (r *Receipt) encodeStorage(w *rlp.EncoderBuffer) {
|
|||
w.ListEnd(list)
|
||||
}
|
||||
|
||||
// encodeForNetwork68 produces the eth/68 network protocol encoding of a receipt.
|
||||
// Note this recomputes the bloom filter of the receipt.
|
||||
func (r *Receipt) encodeForNetwork68(buf *receiptListBuffers, w *rlp.EncoderBuffer) {
|
||||
writeInner := func(w *rlp.EncoderBuffer) {
|
||||
list := w.List()
|
||||
w.WriteBytes(r.PostStateOrStatus)
|
||||
w.WriteUint64(r.GasUsed)
|
||||
bloom := r.bloom(&buf.bloom)
|
||||
w.WriteBytes(bloom[:])
|
||||
w.Write(r.Logs)
|
||||
w.ListEnd(list)
|
||||
}
|
||||
|
||||
if r.TxType == 0 {
|
||||
writeInner(w)
|
||||
} else {
|
||||
buf.tmp.Reset()
|
||||
buf.tmp.WriteByte(r.TxType)
|
||||
buf.enc.Reset(&buf.tmp)
|
||||
writeInner(&buf.enc)
|
||||
buf.enc.Flush()
|
||||
w.WriteBytes(buf.tmp.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
// encodeForNetwork69 produces the eth/69 network protocol encoding of a receipt.
|
||||
func (r *Receipt) encodeForNetwork69(w *rlp.EncoderBuffer) {
|
||||
list := w.List()
|
||||
w.WriteUint64(uint64(r.TxType))
|
||||
w.WriteBytes(r.PostStateOrStatus)
|
||||
w.WriteUint64(r.GasUsed)
|
||||
w.Write(r.Logs)
|
||||
w.ListEnd(list)
|
||||
}
|
||||
|
||||
// encodeForHash encodes a receipt for the block receiptsRoot derivation.
|
||||
func (r *Receipt) encodeForHash(buf *receiptListBuffers, out *bytes.Buffer) {
|
||||
// For typed receipts, add the tx type.
|
||||
if r.TxType != 0 {
|
||||
out.WriteByte(r.TxType)
|
||||
}
|
||||
// Encode list = [postStateOrStatus, gasUsed, bloom, logs].
|
||||
w := &buf.enc
|
||||
w.Reset(out)
|
||||
l := w.List()
|
||||
w.WriteBytes(r.PostStateOrStatus)
|
||||
w.WriteUint64(r.GasUsed)
|
||||
bloom := r.bloom(&buf.bloom)
|
||||
w.WriteBytes(bloom[:])
|
||||
w.Write(r.Logs)
|
||||
w.ListEnd(l)
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
// bloom computes the bloom filter of the receipt.
|
||||
// Note this doesn't check the validity of encoding, and will produce an invalid filter
|
||||
// for invalid input. This is acceptable for the purpose of this function, which is
|
||||
|
|
@ -83,8 +195,7 @@ func (r *Receipt) bloom(buffer *[6]byte) types.Bloom {
|
|||
return b
|
||||
}
|
||||
for logsIter.Next() {
|
||||
log := logsIter.Value()
|
||||
log, _, _ = rlp.SplitList(log)
|
||||
log, _, _ := rlp.SplitList(logsIter.Value())
|
||||
address, log, _ := rlp.SplitString(log)
|
||||
b.AddWithBuffer(address, buffer)
|
||||
topicsIter, err := rlp.NewListIterator(log)
|
||||
|
|
@ -99,6 +210,133 @@ func (r *Receipt) bloom(buffer *[6]byte) types.Bloom {
|
|||
return b
|
||||
}
|
||||
|
||||
type receiptListBuffers struct {
|
||||
enc rlp.EncoderBuffer
|
||||
bloom [6]byte
|
||||
tmp bytes.Buffer
|
||||
}
|
||||
|
||||
func initBuffers(buf **receiptListBuffers) {
|
||||
if *buf == nil {
|
||||
*buf = new(receiptListBuffers)
|
||||
}
|
||||
}
|
||||
|
||||
// encodeForStorage encodes a list of receipts for the database.
|
||||
func (buf *receiptListBuffers) encodeForStorage(rs []Receipt) rlp.RawValue {
|
||||
var out bytes.Buffer
|
||||
w := &buf.enc
|
||||
w.Reset(&out)
|
||||
outer := w.List()
|
||||
for _, receipts := range rs {
|
||||
receipts.encodeForStorage(w)
|
||||
}
|
||||
w.ListEnd(outer)
|
||||
w.Flush()
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
// ReceiptList68 is a block receipt list as downloaded by eth/68.
|
||||
// This also implements types.DerivableList for validation purposes.
|
||||
type ReceiptList68 struct {
|
||||
buf *receiptListBuffers
|
||||
items []Receipt
|
||||
}
|
||||
|
||||
// NewReceiptList68 creates a receipt list.
|
||||
// This is slow, and exists for testing purposes.
|
||||
func NewReceiptList68(trs []*types.Receipt) *ReceiptList68 {
|
||||
rl := &ReceiptList68{items: make([]Receipt, len(trs))}
|
||||
for i, tr := range trs {
|
||||
rl.items[i] = newReceipt(tr)
|
||||
}
|
||||
return rl
|
||||
}
|
||||
|
||||
func blockReceiptsToNetwork68(blockReceipts, blockBody rlp.RawValue) ([]byte, error) {
|
||||
txTypesIter, err := txTypesInBody(blockBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid block body: %v", err)
|
||||
}
|
||||
nextTxType, stopTxTypes := iter.Pull(txTypesIter)
|
||||
defer stopTxTypes()
|
||||
|
||||
var (
|
||||
out bytes.Buffer
|
||||
buf receiptListBuffers
|
||||
)
|
||||
blockReceiptIter, _ := rlp.NewListIterator(blockReceipts)
|
||||
innerReader := bytes.NewReader(nil)
|
||||
innerStream := rlp.NewStream(innerReader, 0)
|
||||
w := rlp.NewEncoderBuffer(&out)
|
||||
outer := w.List()
|
||||
for i := 0; blockReceiptIter.Next(); i++ {
|
||||
content := blockReceiptIter.Value()
|
||||
innerReader.Reset(content)
|
||||
innerStream.Reset(innerReader, uint64(len(content)))
|
||||
var r Receipt
|
||||
txType, _ := nextTxType()
|
||||
if err := r.decodeDatabase(txType, innerStream); err != nil {
|
||||
return nil, fmt.Errorf("invalid database receipt %d: %v", i, err)
|
||||
}
|
||||
r.encodeForNetwork68(&buf, &w)
|
||||
}
|
||||
w.ListEnd(outer)
|
||||
w.Flush()
|
||||
return out.Bytes(), nil
|
||||
}
|
||||
|
||||
// setBuffers implements ReceiptsList.
|
||||
func (rl *ReceiptList68) setBuffers(buf *receiptListBuffers) {
|
||||
rl.buf = buf
|
||||
}
|
||||
|
||||
// EncodeForStorage encodes the receipts for storage into the database.
|
||||
func (rl *ReceiptList68) EncodeForStorage() rlp.RawValue {
|
||||
initBuffers(&rl.buf)
|
||||
return rl.buf.encodeForStorage(rl.items)
|
||||
}
|
||||
|
||||
// Len implements types.DerivableList.
|
||||
func (rl *ReceiptList68) Len() int {
|
||||
return len(rl.items)
|
||||
}
|
||||
|
||||
// EncodeIndex implements types.DerivableList.
|
||||
func (rl *ReceiptList68) EncodeIndex(i int, out *bytes.Buffer) {
|
||||
initBuffers(&rl.buf)
|
||||
rl.items[i].encodeForHash(rl.buf, out)
|
||||
}
|
||||
|
||||
// DecodeRLP decodes a list of receipts from the network format.
|
||||
func (rl *ReceiptList68) DecodeRLP(s *rlp.Stream) error {
|
||||
initBuffers(&rl.buf)
|
||||
if _, err := s.List(); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; s.MoreDataInList(); i++ {
|
||||
var item Receipt
|
||||
err := item.decode68(rl.buf, s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("receipt %d: %v", i, err)
|
||||
}
|
||||
rl.items = append(rl.items, item)
|
||||
}
|
||||
return s.ListEnd()
|
||||
}
|
||||
|
||||
// EncodeRLP encodes the list into the network format of eth/68.
|
||||
func (rl *ReceiptList68) EncodeRLP(_w io.Writer) error {
|
||||
initBuffers(&rl.buf)
|
||||
w := rlp.NewEncoderBuffer(_w)
|
||||
outer := w.List()
|
||||
for i := range rl.items {
|
||||
rl.items[i].encodeForNetwork68(rl.buf, &w)
|
||||
}
|
||||
w.ListEnd(outer)
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
// ReceiptList69 is the block receipt list as downloaded by eth/69.
|
||||
// This implements types.DerivableList for validation purposes.
|
||||
type ReceiptList69 struct {
|
||||
|
|
@ -106,39 +344,36 @@ type ReceiptList69 struct {
|
|||
items []Receipt
|
||||
}
|
||||
|
||||
type receiptListBuffers struct {
|
||||
enc rlp.EncoderBuffer
|
||||
bloom [6]byte
|
||||
// NewReceiptList69 creates a receipt list.
|
||||
// This is slow, and exists for testing purposes.
|
||||
func NewReceiptList69(trs []*types.Receipt) *ReceiptList69 {
|
||||
rl := &ReceiptList69{items: make([]Receipt, len(trs))}
|
||||
for i, tr := range trs {
|
||||
rl.items[i] = newReceipt(tr)
|
||||
}
|
||||
return rl
|
||||
}
|
||||
|
||||
// Len returns the length of the list.
|
||||
// setBuffers implements ReceiptsList.
|
||||
func (rl *ReceiptList69) setBuffers(buf *receiptListBuffers) {
|
||||
rl.buf = buf
|
||||
}
|
||||
|
||||
// EncodeForStorage encodes the receipts for storage into the database.
|
||||
func (rl *ReceiptList69) EncodeForStorage() rlp.RawValue {
|
||||
initBuffers(&rl.buf)
|
||||
return rl.buf.encodeForStorage(rl.items)
|
||||
}
|
||||
|
||||
// Len implements types.DerivableList.
|
||||
func (rl *ReceiptList69) Len() int {
|
||||
return len(rl.items)
|
||||
}
|
||||
|
||||
// EncodeIndex implements types.DerivableList.
|
||||
func (rl *ReceiptList69) EncodeIndex(i int, b *bytes.Buffer) {
|
||||
if rl.buf == nil {
|
||||
rl.buf = new(receiptListBuffers)
|
||||
}
|
||||
|
||||
var (
|
||||
r = &rl.items[i]
|
||||
bloom = r.bloom(&rl.buf.bloom)
|
||||
w = &rl.buf.enc
|
||||
)
|
||||
if r.TxType != 0 {
|
||||
b.WriteByte(r.TxType)
|
||||
}
|
||||
// encode list = [postStateOrStatus, gasUsed, bloom, logs]
|
||||
w.Reset(b)
|
||||
l := w.List()
|
||||
w.WriteBytes(r.PostStateOrStatus)
|
||||
w.WriteUint64(r.GasUsed)
|
||||
w.WriteBytes(bloom[:])
|
||||
w.Write(r.Logs)
|
||||
w.ListEnd(l)
|
||||
w.Flush()
|
||||
func (rl *ReceiptList69) EncodeIndex(i int, out *bytes.Buffer) {
|
||||
initBuffers(&rl.buf)
|
||||
rl.items[i].encodeForHash(rl.buf, out)
|
||||
}
|
||||
|
||||
// DecodeRLP decodes a list receipts from the network format.
|
||||
|
|
@ -148,7 +383,7 @@ func (rl *ReceiptList69) DecodeRLP(s *rlp.Stream) error {
|
|||
}
|
||||
for i := 0; s.MoreDataInList(); i++ {
|
||||
var item Receipt
|
||||
err := item.DecodeRLP(s)
|
||||
err := item.decode69(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("receipt %d: %v", i, err)
|
||||
}
|
||||
|
|
@ -157,30 +392,21 @@ func (rl *ReceiptList69) DecodeRLP(s *rlp.Stream) error {
|
|||
return s.ListEnd()
|
||||
}
|
||||
|
||||
// toStorageReceiptsRLP encodes the receipts for storage into the database.
|
||||
func (rl *ReceiptList69) toStorageReceiptsRLP() rlp.RawValue {
|
||||
if rl.buf == nil {
|
||||
rl.buf = new(receiptListBuffers)
|
||||
}
|
||||
|
||||
var (
|
||||
out bytes.Buffer
|
||||
w = &rl.buf.enc
|
||||
)
|
||||
w.Reset(&out)
|
||||
// EncodeRLP encodes the list into the network format of eth/69.
|
||||
func (rl *ReceiptList69) EncodeRLP(_w io.Writer) error {
|
||||
w := rlp.NewEncoderBuffer(_w)
|
||||
outer := w.List()
|
||||
for _, receipts := range rl.items {
|
||||
receipts.encodeStorage(w)
|
||||
for i := range rl.items {
|
||||
rl.items[i].encodeForNetwork69(&w)
|
||||
}
|
||||
w.ListEnd(outer)
|
||||
w.Flush()
|
||||
return out.Bytes()
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
// blockReceiptsToNetwork takes a slice of rlp-encoded receipts, and transactions,
|
||||
// blockReceiptsToNetwork69 takes a slice of rlp-encoded receipts, and transactions,
|
||||
// and applies the type-encoding on the receipts (for non-legacy receipts).
|
||||
// e.g. for non-legacy receipts: receipt-data -> {tx-type || receipt-data}
|
||||
func blockReceiptsToNetwork(blockReceipts, blockBody rlp.RawValue) ([]byte, error) {
|
||||
func blockReceiptsToNetwork69(blockReceipts, blockBody rlp.RawValue) ([]byte, error) {
|
||||
txTypesIter, err := txTypesInBody(blockBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid block body: %v", err)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,13 @@ import (
|
|||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
func TestTransformReceipts(t *testing.T) {
|
||||
// miniDeriveFields derives the necessary receipt fields to make types.DeriveSha work.
|
||||
func miniDeriveFields(r *types.Receipt, txType byte) {
|
||||
r.Type = txType
|
||||
r.Bloom = types.CreateBloom(r)
|
||||
}
|
||||
|
||||
func TestReceiptList69(t *testing.T) {
|
||||
logs := []*types.Log{{Address: common.Address{1}, Topics: []common.Hash{{1}}}}
|
||||
encLogs, _ := rlp.EncodeToBytes(logs)
|
||||
|
||||
|
|
@ -66,7 +72,7 @@ func TestTransformReceipts(t *testing.T) {
|
|||
encBlockBody, _ := rlp.EncodeToBytes(blockBody)
|
||||
|
||||
// convert from storage encoding to network encoding
|
||||
network, err := blockReceiptsToNetwork(in, encBlockBody)
|
||||
network, err := blockReceiptsToNetwork69(in, encBlockBody)
|
||||
if err != nil {
|
||||
t.Fatalf("test[%d]: blockReceiptsToNetwork error: %v", i, err)
|
||||
}
|
||||
|
|
@ -76,7 +82,7 @@ func TestTransformReceipts(t *testing.T) {
|
|||
if err := rlp.DecodeBytes(network, &rl); err != nil {
|
||||
t.Fatalf("test[%d]: can't decode network receipts: %v", i, err)
|
||||
}
|
||||
storageEnc := rl.toStorageReceiptsRLP()
|
||||
storageEnc := rl.EncodeForStorage()
|
||||
if !bytes.Equal(storageEnc, in) {
|
||||
t.Fatalf("test[%d]: re-encoded receipts not equal\nhave: %x\nwant: %x", i, storageEnc, in)
|
||||
}
|
||||
|
|
@ -85,9 +91,7 @@ func TestTransformReceipts(t *testing.T) {
|
|||
receipts := make(types.Receipts, len(test.input))
|
||||
for i := range test.input {
|
||||
r := types.Receipt(test.input[i])
|
||||
// need to derive these fields to get the correct result from DeriveSha.
|
||||
r.Type = test.txs[i].Type()
|
||||
r.Bloom = types.CreateBloom(&r)
|
||||
miniDeriveFields(&r, test.txs[i].Type())
|
||||
receipts[i] = &r
|
||||
}
|
||||
expectedHash := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
||||
|
|
@ -99,14 +103,3 @@ func TestTransformReceipts(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReceiptsMessage69(t *testing.T) {
|
||||
msg := common.FromHex("f9037c880e17dea70d94cb05f90370e7e680a0c97ed91127dd6f6a099889686685b3b204a5888a9d84431747324654eca53e4c825208c0e7e680a00ba7c3d24be245396fc5d3f80d8a69813637c63b2750a0aecca0ecf1893ae6de825208c0e7e680a0b1bdb7832a63083237ae909f02b5290e5ead11e947f90ad406ce58af42d9cbf2825208c0e7e680a0a8db4c173896d1961aab985d4084276cfbb5b460184c72ed9148093427813e50825208c0e7e680a02ac83e5239694103e4b8bfe88055573eb6947eb9ec456bd1ecd40c3a390c1184825208c0e7e680a05d61474327cd80ea904886eb01497db86aa4e1826f60ba8041b342b7e3271451825208c0e7e680a0c586c7bffdaa7eafd1e64755f6438d4737d3da328e4bf15bf36f425e35dcba57825208c0e7e680a0db8c7c749080c80efc9b8fec0036b7aebe1fdb130cc0529cd41658f0e4073f32825208c0e7e680a052820bf047785bce72e004175cf20430228ed6e3aafd2f0dc9d881ab4b8247b0825208c0e7e680a00b8fa31c4ba7486ba43779175b05f07e9a913d97f0d784294283c67ca08ecade825208c0e7e680a059d6258b1d014be483b4393850a81fa109d80d0d222acc0ca4897332839f8760825208c0e7e680a0128b6226c363fe1fe0a94bc576b46569ee4d59cfcff913df74165294bb1478de825208c0e7e680a0525f09191eb703dce45154db01474a84191b45bddd36e99b6cbf59a5a40ee935825208c0e7e680a032664bd056b1e2ae4dd7293e578b5d7300f97e1a1a81432d310d7100d1931c2d825208c0e7e680a07d29340b854047e215e787d04073bbf4451a4fbdeaaaac8ef67934eb2612d264825208c0e7e680a054b35228ab2fd0a096976f3c144cb86bed4f48e952ac78b4c4bd8ee377ce686a8256d0c0e7e680a0bf5fb6d0da92232bc4b0a5c8bc6675a9f298c23ce747877074fe24f6e2d75dfa825208c0e7e680a04fbf751cb29c49f34c9da0d8fe456afc8672b2e6049d51b01ff40456661456e9825208c0e7e680a050397035c265d9d628bf382e072fec34e72c98a86f48f7c6afdd7bbb128ea7e2825208c0e7e680a0ed10826649c2bdb34763b3f293cc18564cc883d6b6cbb84df75e7e328d3e2594825208c0e7e680a02ca0ecfc7149619fac0b5376a8a6fd1b0da6371ad875d50603d2adb667f12c2f825208c0e7e680a0801743bd8c5e43b7b77024ff80c4e437d8b505f8295dfb179f667b22c0762637825208c0")
|
||||
var dec ReceiptsPacket69
|
||||
if err := rlp.DecodeBytes(msg, &dec); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(dec.List) != 22 {
|
||||
t.Fatalf("wrong list length %d", len(dec.List))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue