Skip to content

Commit

Permalink
Always encode EIP-4844 transactions unwrapped (without blobs) (#8012)
Browse files Browse the repository at this point in the history
The only time we need to serialize blobs/commitments/proofs is when we
reply to `GetPooledTransactions` (and that's handled by the txpool).
  • Loading branch information
yperbasis authored Aug 13, 2023
1 parent b7070a9 commit 7947fc8
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 194 deletions.
116 changes: 12 additions & 104 deletions core/types/blob_tx_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,110 +345,6 @@ func (txw *BlobTxWrapper) IsContractDeploy() bool { return txw.Tx.IsContractDepl

func (txw *BlobTxWrapper) Unwrap() Transaction { return &txw.Tx }

func (txw BlobTxWrapper) EncodingSize() int {
total, _, _, _, _ := txw.payloadSize()
envelopeSize := total
// Add envelope size and type size
if total >= 56 {
envelopeSize += libcommon.BitLenToByteLen(bits.Len(uint(total)))
}
envelopeSize += 2
return envelopeSize
}

func (txw BlobTxWrapper) payloadSize() (int, int, int, int, int) {
total := 1
txSize, _, _, _, _ := txw.Tx.payloadSize()
if txSize >= 56 {
total += libcommon.BitLenToByteLen(bits.Len(uint(txSize)))
}
total += txSize

total++
commitmentsSize := txw.Commitments.payloadSize()
if commitmentsSize >= 56 {
total += libcommon.BitLenToByteLen(bits.Len(uint(commitmentsSize)))
}
total += commitmentsSize

total++
blobsSize := txw.Blobs.payloadSize()
if blobsSize >= 56 {
total += libcommon.BitLenToByteLen(bits.Len(uint(blobsSize)))
}
total += blobsSize

total++
proofsSize := txw.Proofs.payloadSize()
if proofsSize >= 56 {
total += libcommon.BitLenToByteLen(bits.Len(uint(proofsSize)))
}
total += proofsSize
return total, txSize, commitmentsSize, blobsSize, proofsSize
}

func (txw BlobTxWrapper) encodePayload(w io.Writer, b []byte, total, txSize, commitmentsSize, blobsSize, proofsSize int) error {
// prefix, encode txw payload size
if err := EncodeStructSizePrefix(total, w, b); err != nil {
return err
}

txPayloadSize, nonceLen, gasLen, accessListLen, blobHashesLen := txw.Tx.payloadSize()

if err := txw.Tx.encodePayload(w, b, txPayloadSize, nonceLen, gasLen, accessListLen, blobHashesLen); err != nil {
return err
}

if err := txw.Blobs.encodePayload(w, b, blobsSize); err != nil {
return err
}
if err := txw.Commitments.encodePayload(w, b, commitmentsSize); err != nil {
return err
}
if err := txw.Proofs.encodePayload(w, b, proofsSize); err != nil {
return err
}
return nil
}

func (txw *BlobTxWrapper) MarshalBinary(w io.Writer) error {
total, txSize, commitmentsSize, blobsSize, proofsSize := txw.payloadSize()
var b [33]byte
// encode TxType
b[0] = BlobTxType
if _, err := w.Write(b[:1]); err != nil {
return err
}
if err := txw.encodePayload(w, b[:], total, txSize, commitmentsSize, blobsSize, proofsSize); err != nil {
return err
}
return nil
}

func (txw BlobTxWrapper) EncodeRLP(w io.Writer) error {
total, txSize, commitmentsSize, proofsSize, blobsSize := txw.payloadSize()
envelopeSize := total
if total >= 56 {
envelopeSize += libcommon.BitLenToByteLen(bits.Len(uint(total)))
}
// size of struct prefix and TxType
envelopeSize += 2
var b [33]byte
// envelope
if err := rlp.EncodeStringSizePrefix(envelopeSize, w, b[:]); err != nil {
return err
}
// encode TxType
b[0] = BlobTxType
if _, err := w.Write(b[:1]); err != nil {
return err
}
if err := txw.encodePayload(w, b[:], total, txSize, commitmentsSize, proofsSize, blobsSize); err != nil {
return err
}
return nil
}

func (txw *BlobTxWrapper) DecodeRLP(s *rlp.Stream) error {
_, err := s.List()
if err != nil {
Expand All @@ -473,3 +369,15 @@ func (txw *BlobTxWrapper) DecodeRLP(s *rlp.Stream) error {

return s.ListEnd()
}

// We deliberately encode only the transaction payload because the only case we need to serialize
// blobs/commitments/proofs is when we reply to GetPooledTransactions (and that's handled by the txpool).
func (txw BlobTxWrapper) EncodingSize() int {
return txw.Tx.EncodingSize()
}
func (txw *BlobTxWrapper) MarshalBinary(w io.Writer) error {
return txw.Tx.MarshalBinary(w)
}
func (txw BlobTxWrapper) EncodeRLP(w io.Writer) error {
return txw.Tx.EncodeRLP(w)
}
23 changes: 12 additions & 11 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -1594,18 +1594,19 @@ func CopyTxs(in Transactions) Transactions {
if err != nil {
panic(fmt.Errorf("MarshalTransactionsBinary failed: %w", err))
}
out := make([]Transaction, len(in))
out, err := DecodeTransactions(transactionsData)
if err != nil {
panic(fmt.Errorf("DecodeTransactions failed: %w", err))
}
for i, tx := range in {
if _, ok := tx.(*BlobTxWrapper); ok {
out[i], err = UnmarshalWrappedTransactionFromBinary(transactionsData[i])
} else {
out[i], err = UnmarshalTransactionFromBinary(transactionsData[i])
}
if err != nil {
panic(fmt.Errorf("DecodeTransactions failed: %w", err))
}
if s, ok := in[i].GetSender(); ok {
out[i].SetSender(s)
if txWrapper, ok := tx.(*BlobTxWrapper); ok {
blobTx := out[i].(*BlobTx)
out[i] = &BlobTxWrapper{
Tx: *blobTx,
Commitments: txWrapper.Commitments.copy(),
Blobs: txWrapper.Blobs.copy(),
Proofs: txWrapper.Proofs.copy(),
}
}
}
return out
Expand Down
2 changes: 1 addition & 1 deletion core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ type Transaction interface {
GetSender() (libcommon.Address, bool)
SetSender(libcommon.Address)
IsContractDeploy() bool
Unwrap() Transaction // If this is a network wrapper, returns the unwrapped tx. Otherwiwes returns itself.
Unwrap() Transaction // If this is a network wrapper, returns the unwrapped tx. Otherwise returns itself.
}

// TransactionMisc is collection of miscelaneous fields for transaction that is supposed to be embedded into concrete
Expand Down
66 changes: 5 additions & 61 deletions core/types/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,19 +563,6 @@ func encodeDecodeBinary(tx Transaction) (Transaction, error) {
return parsedTx, nil
}

func encodeDecodeWrappedBinary(tx *BlobTxWrapper) (*BlobTxWrapper, error) {
var buf bytes.Buffer
var err error
if err = tx.MarshalBinary(&buf); err != nil {
return nil, fmt.Errorf("rlp encoding failed: %w", err)
}
var parsedTx Transaction
if parsedTx, err = UnmarshalWrappedTransactionFromBinary(buf.Bytes()); err != nil {
return nil, fmt.Errorf("rlp decoding failed: %w", err)
}
return parsedTx.(*BlobTxWrapper), nil
}

func assertEqual(orig Transaction, cpy Transaction) error {
// compare nonce, price, gaslimit, recipient, amount, payload, V, R, S
if want, got := orig.Hash(), cpy.Hash(); want != got {
Expand Down Expand Up @@ -686,20 +673,17 @@ func newRandBlobTx() *BlobTx {
To: randAddr(),
Value: uint256.NewInt(rand.Uint64()),
Data: randData(),
// V: *uint256.NewInt(rand.Uint64()),
// R: *uint256.NewInt(rand.Uint64()),
// S: *uint256.NewInt(rand.Uint64()),
V: *uint256.NewInt(0),
R: *uint256.NewInt(rand.Uint64()),
S: *uint256.NewInt(rand.Uint64()),
V: *uint256.NewInt(0),
R: *uint256.NewInt(rand.Uint64()),
S: *uint256.NewInt(rand.Uint64()),
},
ChainID: uint256.NewInt(rand.Uint64()),
Tip: uint256.NewInt(rand.Uint64()),
FeeCap: uint256.NewInt(rand.Uint64()),
AccessList: randAccessList(),
},
MaxFeePerBlobGas: uint256.NewInt(rand.Uint64()),
BlobVersionedHashes: randHashes(randIntInRange(0, 6)),
BlobVersionedHashes: randHashes(randIntInRange(1, 6)),
}
return stx
}
Expand Down Expand Up @@ -791,16 +775,9 @@ func populateBlobTxs() {
}

func populateBlobWrapperTxs() {
for i := 0; i < N-1; i++ {
for i := 0; i < N; i++ {
dummyBlobWrapperTxs[i] = newRandBlobWrapper()
}

dummyBlobWrapperTxs[N-1] = &BlobTxWrapper{
Tx: *newRandBlobTx(),
Commitments: nil,
Blobs: nil,
Proofs: nil,
}
}

func TestBlobTxEncodeDecode(t *testing.T) {
Expand All @@ -825,38 +802,5 @@ func TestBlobTxEncodeDecode(t *testing.T) {
if err = assertEqual(dummyBlobTxs[i], tx); err != nil {
t.Fatal(err)
}

}
}

func TestBlobTxWrappedEncodeDecode(t *testing.T) {
rand.Seed(time.Now().UnixNano())
populateBlobWrapperTxs()
for i := 0; i < N; i++ {
tx, err := encodeDecodeWrappedBinary(dummyBlobWrapperTxs[i])
if err != nil {
t.Fatal(err)
}
if err := assertEqual(dummyBlobWrapperTxs[i], tx); err != nil {
t.Fatal(err)
}
if err := assertEqualBlobWrapper(dummyBlobWrapperTxs[i], tx); err != nil {
t.Fatal(err)
}

// JSON
// fails in ValidateBlobTransactionWrapper()
// error during proof verification: invalid infinity point encoding

// jtx, err := encodeDecodeJSON(dummyBlobWrapperTxs[i])
// if err != nil {
// t.Fatal(err)
// }
// if err = assertEqual(dummyBlobWrapperTxs[i], jtx); err != nil {
// t.Fatal(err)
// }
// if err := assertEqualBlobWrapper(dummyBlobWrapperTxs[i], jtx.(*BlobTxWrapper)); err != nil {
// t.Fatal(err)
// }
}
}
18 changes: 1 addition & 17 deletions turbo/engineapi/engine_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/consensus/merge"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/rlp"
"github.com/ledgerwatch/erigon/rpc"
"github.com/ledgerwatch/erigon/turbo/engineapi/engine_block_downloader"
"github.com/ledgerwatch/erigon/turbo/engineapi/engine_helpers"
Expand Down Expand Up @@ -566,28 +565,13 @@ func (e *EngineServer) GetPayloadV1(ctx context.Context, payloadId hexutility.By
func (e *EngineServer) GetPayloadV2(ctx context.Context, payloadID hexutility.Bytes) (*engine_types.GetPayloadResponse, error) {
decodedPayloadId := binary.BigEndian.Uint64(payloadID)
e.logger.Info("Received GetPayloadV2", "payloadId", decodedPayloadId)

return e.getPayload(ctx, decodedPayloadId)
}

func (e *EngineServer) GetPayloadV3(ctx context.Context, payloadID hexutility.Bytes) (*engine_types.GetPayloadResponse, error) {
decodedPayloadId := binary.BigEndian.Uint64(payloadID)
e.logger.Info("Received GetPayloadV3", "payloadId", decodedPayloadId)
payloadV3, err := e.getPayload(ctx, decodedPayloadId)
transactions := payloadV3.ExecutionPayload.Transactions
for i, transaction := range transactions {
if transaction[0] == 0x03 {
bWtx := types.BlobTxWrapper{}
rlpStream := rlp.NewStream(bytes.NewReader(transaction[1:]), 0)
bWtx.DecodeRLP(rlpStream)

encodedTx := bytes.Buffer{}
bWtx.Tx.EncodeRLP(&encodedTx)
transactions[i] = encodedTx.Bytes()
}
}
return payloadV3, err
// return e.getPayload(ctx, decodedPayloadId)
return e.getPayload(ctx, decodedPayloadId)
}

func (e *EngineServer) ForkchoiceUpdatedV1(ctx context.Context, forkChoiceState *engine_types.ForkChoiceState, payloadAttributes *engine_types.PayloadAttributes) (*engine_types.ForkChoiceUpdatedResponse, error) {
Expand Down

0 comments on commit 7947fc8

Please sign in to comment.