core/types: add MarshalBinary, UnmarshalBinary for Receipt (#22806)
This commit is contained in:
parent
f9d683b07f
commit
e4f570fcc6
@ -144,13 +144,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 {
|
||||||
@ -189,6 +205,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) == 0 {
|
||||||
|
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)
|
||||||
@ -354,42 +406,42 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
|
|||||||
|
|
||||||
// DeriveFields fills the receipts with their computed fields based on consensus
|
// DeriveFields fills the receipts with their computed fields based on consensus
|
||||||
// data and contextual infos like containing block and transactions.
|
// data and contextual infos like containing block and transactions.
|
||||||
func (r Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs Transactions) error {
|
func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs Transactions) error {
|
||||||
signer := MakeSigner(config, new(big.Int).SetUint64(number))
|
signer := MakeSigner(config, new(big.Int).SetUint64(number))
|
||||||
|
|
||||||
logIndex := uint(0)
|
logIndex := uint(0)
|
||||||
if len(txs) != len(r) {
|
if len(txs) != len(rs) {
|
||||||
return errors.New("transaction and receipt count mismatch")
|
return errors.New("transaction and receipt count mismatch")
|
||||||
}
|
}
|
||||||
for i := 0; i < len(r); i++ {
|
for i := 0; i < len(rs); i++ {
|
||||||
// The transaction type and hash can be retrieved from the transaction itself
|
// The transaction type and hash can be retrieved from the transaction itself
|
||||||
r[i].Type = txs[i].Type()
|
rs[i].Type = txs[i].Type()
|
||||||
r[i].TxHash = txs[i].Hash()
|
rs[i].TxHash = txs[i].Hash()
|
||||||
|
|
||||||
// block location fields
|
// block location fields
|
||||||
r[i].BlockHash = hash
|
rs[i].BlockHash = hash
|
||||||
r[i].BlockNumber = new(big.Int).SetUint64(number)
|
rs[i].BlockNumber = new(big.Int).SetUint64(number)
|
||||||
r[i].TransactionIndex = uint(i)
|
rs[i].TransactionIndex = uint(i)
|
||||||
|
|
||||||
// The contract address can be derived from the transaction itself
|
// The contract address can be derived from the transaction itself
|
||||||
if txs[i].To() == nil {
|
if txs[i].To() == nil {
|
||||||
// Deriving the signer is expensive, only do if it's actually needed
|
// Deriving the signer is expensive, only do if it's actually needed
|
||||||
from, _ := Sender(signer, txs[i])
|
from, _ := Sender(signer, txs[i])
|
||||||
r[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
|
rs[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
|
||||||
}
|
}
|
||||||
// The used gas can be calculated based on previous r
|
// The used gas can be calculated based on previous r
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
r[i].GasUsed = r[i].CumulativeGasUsed
|
rs[i].GasUsed = rs[i].CumulativeGasUsed
|
||||||
} else {
|
} else {
|
||||||
r[i].GasUsed = r[i].CumulativeGasUsed - r[i-1].CumulativeGasUsed
|
rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed
|
||||||
}
|
}
|
||||||
// The derived log fields can simply be set from the block and transaction
|
// The derived log fields can simply be set from the block and transaction
|
||||||
for j := 0; j < len(r[i].Logs); j++ {
|
for j := 0; j < len(rs[i].Logs); j++ {
|
||||||
r[i].Logs[j].BlockNumber = number
|
rs[i].Logs[j].BlockNumber = number
|
||||||
r[i].Logs[j].BlockHash = hash
|
rs[i].Logs[j].BlockHash = hash
|
||||||
r[i].Logs[j].TxHash = r[i].TxHash
|
rs[i].Logs[j].TxHash = rs[i].TxHash
|
||||||
r[i].Logs[j].TxIndex = uint(i)
|
rs[i].Logs[j].TxIndex = uint(i)
|
||||||
r[i].Logs[j].Index = logIndex
|
rs[i].Logs[j].Index = logIndex
|
||||||
logIndex++
|
logIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,59 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
legacyReceipt = &Receipt{
|
||||||
|
Status: ReceiptStatusFailed,
|
||||||
|
CumulativeGasUsed: 1,
|
||||||
|
Logs: []*Log{
|
||||||
|
{
|
||||||
|
Address: common.BytesToAddress([]byte{0x11}),
|
||||||
|
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Address: common.BytesToAddress([]byte{0x01, 0x11}),
|
||||||
|
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
accessListReceipt = &Receipt{
|
||||||
|
Status: ReceiptStatusFailed,
|
||||||
|
CumulativeGasUsed: 1,
|
||||||
|
Logs: []*Log{
|
||||||
|
{
|
||||||
|
Address: common.BytesToAddress([]byte{0x11}),
|
||||||
|
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Address: common.BytesToAddress([]byte{0x01, 0x11}),
|
||||||
|
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Type: AccessListTxType,
|
||||||
|
}
|
||||||
|
eip1559Receipt = &Receipt{
|
||||||
|
Status: ReceiptStatusFailed,
|
||||||
|
CumulativeGasUsed: 1,
|
||||||
|
Logs: []*Log{
|
||||||
|
{
|
||||||
|
Address: common.BytesToAddress([]byte{0x11}),
|
||||||
|
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
|
||||||
|
Data: []byte{0x01, 0x00, 0xff},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Address: common.BytesToAddress([]byte{0x01, 0x11}),
|
||||||
|
Topics: []common.Hash{common.HexToHash("dead"), common.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
|
||||||
@ -312,6 +365,105 @@ func TestTypedReceiptEncodingDecoding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 := common.FromHex("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 := common.FromHex("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 := common.FromHex("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 := common.FromHex("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 := common.FromHex("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 := common.FromHex("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()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user