restricted/types: add MarshalBinary, UnmarshalBinary for Receipt

Port of https://github.com/ethereum/go-ethereum/pull/22806
This commit is contained in:
Roy Crihfield 2023-06-03 00:22:26 +08:00
parent 80a4c5f4c5
commit d69102afec
2 changed files with 211 additions and 7 deletions

View File

@ -25,8 +25,8 @@ import (
"unsafe" "unsafe"
"github.com/openrelayxyz/plugeth-utils/core" "github.com/openrelayxyz/plugeth-utils/core"
"github.com/openrelayxyz/plugeth-utils/restricted/hexutil"
"github.com/openrelayxyz/plugeth-utils/restricted/crypto" "github.com/openrelayxyz/plugeth-utils/restricted/crypto"
"github.com/openrelayxyz/plugeth-utils/restricted/hexutil"
"github.com/openrelayxyz/plugeth-utils/restricted/params" "github.com/openrelayxyz/plugeth-utils/restricted/params"
"github.com/openrelayxyz/plugeth-utils/restricted/rlp" "github.com/openrelayxyz/plugeth-utils/restricted/rlp"
) )
@ -63,13 +63,13 @@ type Receipt struct {
// They are stored in the chain database. // They are stored in the chain database.
TxHash core.Hash `json:"transactionHash" gencodec:"required"` TxHash core.Hash `json:"transactionHash" gencodec:"required"`
ContractAddress core.Address `json:"contractAddress"` ContractAddress core.Address `json:"contractAddress"`
GasUsed uint64 `json:"gasUsed" gencodec:"required"` GasUsed uint64 `json:"gasUsed" gencodec:"required"`
// Inclusion information: These fields provide information about the inclusion of the // Inclusion information: These fields provide information about the inclusion of the
// transaction corresponding to this receipt. // transaction corresponding to this receipt.
BlockHash core.Hash `json:"blockHash,omitempty"` BlockHash core.Hash `json:"blockHash,omitempty"`
BlockNumber *big.Int `json:"blockNumber,omitempty"` BlockNumber *big.Int `json:"blockNumber,omitempty"`
TransactionIndex uint `json:"transactionIndex"` TransactionIndex uint `json:"transactionIndex"`
} }
type receiptMarshaling struct { type receiptMarshaling struct {
@ -123,13 +123,29 @@ func (r *Receipt) EncodeRLP(w io.Writer) error {
buf := encodeBufferPool.Get().(*bytes.Buffer) buf := encodeBufferPool.Get().(*bytes.Buffer)
defer encodeBufferPool.Put(buf) defer encodeBufferPool.Put(buf)
buf.Reset() buf.Reset()
buf.WriteByte(r.Type) if err := r.encodeTyped(data, buf); err != nil {
if err := rlp.Encode(buf, data); err != nil {
return err return err
} }
return rlp.Encode(w, buf.Bytes()) return rlp.Encode(w, buf.Bytes())
} }
// encodeTyped writes the canonical encoding of a typed receipt to w.
func (r *Receipt) encodeTyped(data *receiptRLP, w *bytes.Buffer) error {
w.WriteByte(r.Type)
return rlp.Encode(w, data)
}
// MarshalBinary returns the consensus encoding of the receipt.
func (r *Receipt) MarshalBinary() ([]byte, error) {
if r.Type == LegacyTxType {
return rlp.EncodeToBytes(r)
}
data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
var buf bytes.Buffer
err := r.encodeTyped(data, &buf)
return buf.Bytes(), err
}
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
// from an RLP stream. // from an RLP stream.
func (r *Receipt) DecodeRLP(s *rlp.Stream) error { func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
@ -168,6 +184,42 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
} }
} }
// UnmarshalBinary decodes the consensus encoding of receipts.
// It supports legacy RLP receipts and EIP-2718 typed receipts.
func (r *Receipt) UnmarshalBinary(b []byte) error {
if len(b) > 0 && b[0] > 0x7f {
// It's a legacy receipt decode the RLP
var data receiptRLP
err := rlp.DecodeBytes(b, &data)
if err != nil {
return err
}
r.Type = LegacyTxType
return r.setFromRLP(data)
}
// It's an EIP2718 typed transaction envelope.
return r.decodeTyped(b)
}
// decodeTyped decodes a typed receipt from the canonical format.
func (r *Receipt) decodeTyped(b []byte) error {
if len(b) <= 1 {
return errEmptyTypedReceipt
}
switch b[0] {
case DynamicFeeTxType, AccessListTxType:
var data receiptRLP
err := rlp.DecodeBytes(b[1:], &data)
if err != nil {
return err
}
r.Type = b[0]
return r.setFromRLP(data)
default:
return ErrTxTypeNotSupported
}
}
func (r *Receipt) setFromRLP(data receiptRLP) error { func (r *Receipt) setFromRLP(data receiptRLP) error {
r.CumulativeGasUsed, r.Bloom, r.Logs = data.CumulativeGasUsed, data.Bloom, data.Logs r.CumulativeGasUsed, r.Bloom, r.Logs = data.CumulativeGasUsed, data.Bloom, data.Logs
return r.setStatus(data.PostStateOrStatus) return r.setStatus(data.PostStateOrStatus)

View File

@ -18,10 +18,11 @@ package types
import ( import (
"bytes" "bytes"
"encoding/hex"
"math" "math"
"math/big" "math/big"
"reflect"
"testing" "testing"
"encoding/hex"
"github.com/openrelayxyz/plugeth-utils/core" "github.com/openrelayxyz/plugeth-utils/core"
"github.com/openrelayxyz/plugeth-utils/restricted/crypto" "github.com/openrelayxyz/plugeth-utils/restricted/crypto"
@ -29,6 +30,59 @@ import (
"github.com/openrelayxyz/plugeth-utils/restricted/rlp" "github.com/openrelayxyz/plugeth-utils/restricted/rlp"
) )
var (
legacyReceipt = &Receipt{
Status: ReceiptStatusFailed,
CumulativeGasUsed: 1,
Logs: []*Log{
{
Address: core.BytesToAddress([]byte{0x11}),
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
Data: []byte{0x01, 0x00, 0xff},
},
{
Address: core.BytesToAddress([]byte{0x01, 0x11}),
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
Data: []byte{0x01, 0x00, 0xff},
},
},
}
accessListReceipt = &Receipt{
Status: ReceiptStatusFailed,
CumulativeGasUsed: 1,
Logs: []*Log{
{
Address: core.BytesToAddress([]byte{0x11}),
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
Data: []byte{0x01, 0x00, 0xff},
},
{
Address: core.BytesToAddress([]byte{0x01, 0x11}),
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
Data: []byte{0x01, 0x00, 0xff},
},
},
Type: AccessListTxType,
}
eip1559Receipt = &Receipt{
Status: ReceiptStatusFailed,
CumulativeGasUsed: 1,
Logs: []*Log{
{
Address: core.BytesToAddress([]byte{0x11}),
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
Data: []byte{0x01, 0x00, 0xff},
},
{
Address: core.BytesToAddress([]byte{0x01, 0x11}),
Topics: []core.Hash{core.HexToHash("dead"), core.HexToHash("beef")},
Data: []byte{0x01, 0x00, 0xff},
},
},
Type: DynamicFeeTxType,
}
)
func TestDecodeEmptyTypedReceipt(t *testing.T) { func TestDecodeEmptyTypedReceipt(t *testing.T) {
input := []byte{0x80} input := []byte{0x80}
var r Receipt var r Receipt
@ -192,6 +246,104 @@ func TestTypedReceiptEncodingDecoding(t *testing.T) {
check(bundle) check(bundle)
} }
} }
func TestReceiptMarshalBinary(t *testing.T) {
// Legacy Receipt
legacyReceipt.Bloom = CreateBloom(Receipts{legacyReceipt})
have, err := legacyReceipt.MarshalBinary()
if err != nil {
t.Fatalf("marshal binary error: %v", err)
}
legacyReceipts := Receipts{legacyReceipt}
buf := new(bytes.Buffer)
legacyReceipts.EncodeIndex(0, buf)
haveEncodeIndex := buf.Bytes()
if !bytes.Equal(have, haveEncodeIndex) {
t.Errorf("BinaryMarshal and EncodeIndex mismatch, got %x want %x", have, haveEncodeIndex)
}
buf.Reset()
if err := legacyReceipt.EncodeRLP(buf); err != nil {
t.Fatalf("encode rlp error: %v", err)
}
haveRLPEncode := buf.Bytes()
if !bytes.Equal(have, haveRLPEncode) {
t.Errorf("BinaryMarshal and EncodeRLP mismatch for legacy tx, got %x want %x", have, haveRLPEncode)
}
legacyWant, _ := hex.DecodeString("f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
if !bytes.Equal(have, legacyWant) {
t.Errorf("encoded RLP mismatch, got %x want %x", have, legacyWant)
}
// 2930 Receipt
buf.Reset()
accessListReceipt.Bloom = CreateBloom(Receipts{accessListReceipt})
have, err = accessListReceipt.MarshalBinary()
if err != nil {
t.Fatalf("marshal binary error: %v", err)
}
accessListReceipts := Receipts{accessListReceipt}
accessListReceipts.EncodeIndex(0, buf)
haveEncodeIndex = buf.Bytes()
if !bytes.Equal(have, haveEncodeIndex) {
t.Errorf("BinaryMarshal and EncodeIndex mismatch, got %x want %x", have, haveEncodeIndex)
}
accessListWant, _ := hex.DecodeString("01f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
if !bytes.Equal(have, accessListWant) {
t.Errorf("encoded RLP mismatch, got %x want %x", have, accessListWant)
}
// 1559 Receipt
buf.Reset()
eip1559Receipt.Bloom = CreateBloom(Receipts{eip1559Receipt})
have, err = eip1559Receipt.MarshalBinary()
if err != nil {
t.Fatalf("marshal binary error: %v", err)
}
eip1559Receipts := Receipts{eip1559Receipt}
eip1559Receipts.EncodeIndex(0, buf)
haveEncodeIndex = buf.Bytes()
if !bytes.Equal(have, haveEncodeIndex) {
t.Errorf("BinaryMarshal and EncodeIndex mismatch, got %x want %x", have, haveEncodeIndex)
}
eip1559Want, _ := hex.DecodeString("02f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
if !bytes.Equal(have, eip1559Want) {
t.Errorf("encoded RLP mismatch, got %x want %x", have, eip1559Want)
}
}
func TestReceiptUnmarshalBinary(t *testing.T) {
// Legacy Receipt
legacyBinary, _ := hex.DecodeString("f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
gotLegacyReceipt := new(Receipt)
if err := gotLegacyReceipt.UnmarshalBinary(legacyBinary); err != nil {
t.Fatalf("unmarshal binary error: %v", err)
}
legacyReceipt.Bloom = CreateBloom(Receipts{legacyReceipt})
if !reflect.DeepEqual(gotLegacyReceipt, legacyReceipt) {
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotLegacyReceipt, legacyReceipt)
}
// 2930 Receipt
accessListBinary, _ := hex.DecodeString("01f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
gotAccessListReceipt := new(Receipt)
if err := gotAccessListReceipt.UnmarshalBinary(accessListBinary); err != nil {
t.Fatalf("unmarshal binary error: %v", err)
}
accessListReceipt.Bloom = CreateBloom(Receipts{accessListReceipt})
if !reflect.DeepEqual(gotAccessListReceipt, accessListReceipt) {
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotAccessListReceipt, accessListReceipt)
}
// 1559 Receipt
eip1559RctBinary, _ := hex.DecodeString("02f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
got1559Receipt := new(Receipt)
if err := got1559Receipt.UnmarshalBinary(eip1559RctBinary); err != nil {
t.Fatalf("unmarshal binary error: %v", err)
}
eip1559Receipt.Bloom = CreateBloom(Receipts{eip1559Receipt})
if !reflect.DeepEqual(got1559Receipt, eip1559Receipt) {
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", got1559Receipt, eip1559Receipt)
}
}
func clearComputedFieldsOnReceipts(t *testing.T, receipts Receipts) { func clearComputedFieldsOnReceipts(t *testing.T, receipts Receipts) {
t.Helper() t.Helper()