mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 15:47:21 +00:00
core/types: improve encoding/decoding
This commit is contained in:
parent
41634e60ab
commit
61cc5d0580
1 changed files with 105 additions and 42 deletions
|
|
@ -19,6 +19,7 @@ package types
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
|
|
@ -119,15 +120,21 @@ func (sc *BlobTxSidecar) ValidateBlobCommitmentHashes(hashes []common.Hash) erro
|
|||
return nil
|
||||
}
|
||||
|
||||
// blobTxWithBlobs is used for encoding of transactions when blobs are present.
|
||||
type blobTxWithBlobs struct {
|
||||
// blobTxWithBlobs represents blob tx with its corresponding sidecar.
|
||||
// This is an interface because sidecars are versioned.
|
||||
type blobTxWithBlobs interface {
|
||||
tx() *BlobTx
|
||||
assign(*BlobTxSidecar) error
|
||||
}
|
||||
|
||||
type blobTxWithBlobsV0 struct {
|
||||
BlobTx *BlobTx
|
||||
Blobs []kzg4844.Blob
|
||||
Commitments []kzg4844.Commitment
|
||||
Proofs []kzg4844.Proof
|
||||
}
|
||||
|
||||
type versionedBlobTxWithBlobs struct {
|
||||
type blobTxWithBlobsV1 struct {
|
||||
BlobTx *BlobTx
|
||||
Version byte
|
||||
Blobs []kzg4844.Blob
|
||||
|
|
@ -135,6 +142,33 @@ type versionedBlobTxWithBlobs struct {
|
|||
Proofs []kzg4844.Proof
|
||||
}
|
||||
|
||||
func (btx *blobTxWithBlobsV0) tx() *BlobTx {
|
||||
return btx.BlobTx
|
||||
}
|
||||
|
||||
func (btx *blobTxWithBlobsV0) assign(sc *BlobTxSidecar) error {
|
||||
sc.Version = 0
|
||||
sc.Blobs = btx.Blobs
|
||||
sc.Commitments = btx.Commitments
|
||||
sc.Proofs = btx.Proofs
|
||||
return nil
|
||||
}
|
||||
|
||||
func (btx *blobTxWithBlobsV1) tx() *BlobTx {
|
||||
return btx.BlobTx
|
||||
}
|
||||
|
||||
func (btx *blobTxWithBlobsV1) assign(sc *BlobTxSidecar) error {
|
||||
if btx.Version != 1 {
|
||||
return fmt.Errorf("unsupported blob tx version %d", btx.Version)
|
||||
}
|
||||
sc.Version = 1
|
||||
sc.Blobs = btx.Blobs
|
||||
sc.Commitments = btx.Commitments
|
||||
sc.Proofs = btx.Proofs
|
||||
return nil
|
||||
}
|
||||
|
||||
// copy creates a deep copy of the transaction data and initializes all fields.
|
||||
func (tx *BlobTx) copy() TxData {
|
||||
cpy := &BlobTx{
|
||||
|
|
@ -240,69 +274,98 @@ func (tx *BlobTx) withSidecar(sideCar *BlobTxSidecar) *BlobTx {
|
|||
}
|
||||
|
||||
func (tx *BlobTx) encode(b *bytes.Buffer) error {
|
||||
if tx.Sidecar == nil {
|
||||
switch {
|
||||
case tx.Sidecar == nil:
|
||||
return rlp.Encode(b, tx)
|
||||
}
|
||||
// Encode a cell proof transaction
|
||||
if tx.Sidecar.Version != 0 {
|
||||
inner := &versionedBlobTxWithBlobs{
|
||||
|
||||
case tx.Sidecar.Version == 0:
|
||||
return rlp.Encode(b, &blobTxWithBlobsV0{
|
||||
BlobTx: tx,
|
||||
Blobs: tx.Sidecar.Blobs,
|
||||
Commitments: tx.Sidecar.Commitments,
|
||||
Proofs: tx.Sidecar.Proofs,
|
||||
})
|
||||
|
||||
case tx.Sidecar.Version == 1:
|
||||
return rlp.Encode(b, &blobTxWithBlobsV1{
|
||||
BlobTx: tx,
|
||||
Version: tx.Sidecar.Version,
|
||||
Blobs: tx.Sidecar.Blobs,
|
||||
Commitments: tx.Sidecar.Commitments,
|
||||
Proofs: tx.Sidecar.Proofs,
|
||||
}
|
||||
return rlp.Encode(b, inner)
|
||||
})
|
||||
|
||||
default:
|
||||
return errors.New("unsupported sidecar version")
|
||||
}
|
||||
inner := &blobTxWithBlobs{
|
||||
BlobTx: tx,
|
||||
Blobs: tx.Sidecar.Blobs,
|
||||
Commitments: tx.Sidecar.Commitments,
|
||||
Proofs: tx.Sidecar.Proofs,
|
||||
}
|
||||
return rlp.Encode(b, inner)
|
||||
}
|
||||
|
||||
func (tx *BlobTx) decode(input []byte) error {
|
||||
// Here we need to support two formats: the network protocol encoding of the tx (with
|
||||
// blobs) or the canonical encoding without blobs.
|
||||
// Here we need to support two outer formats: the network protocol encoding of the tx
|
||||
// (with blobs) or the canonical encoding without blobs.
|
||||
//
|
||||
// The two encodings can be distinguished by checking whether the first element of the
|
||||
// input list is itself a list.
|
||||
// The canonical encoding is just a list of fields:
|
||||
//
|
||||
// [chainID, nonce, ...]
|
||||
//
|
||||
// The network encoding is a list where the first element is the tx in the canonical encoding,
|
||||
// and the remaining elements are the 'sidecar':
|
||||
//
|
||||
// [[chainID, nonce, ...], ...]
|
||||
//
|
||||
// The two outer encodings can be distinguished by checking whether the first element
|
||||
// of the input list is itself a list. If it's the canonical encoding, the first
|
||||
// element is the chainID, which is a number.
|
||||
|
||||
outerList, _, err := rlp.SplitList(input)
|
||||
firstElem, _, err := rlp.SplitList(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
firstElemKind, _, _, err := rlp.Split(outerList)
|
||||
firstElemKind, _, secondElem, err := rlp.Split(firstElem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if firstElemKind != rlp.List {
|
||||
// Blob tx without blobs.
|
||||
return rlp.DecodeBytes(input, tx)
|
||||
}
|
||||
|
||||
// It's a tx with blobs. Try to decode it as version 0.
|
||||
var inner versionedBlobTxWithBlobs
|
||||
if err := rlp.DecodeBytes(input, &inner); err != nil {
|
||||
var innerV0 blobTxWithBlobs
|
||||
if err := rlp.DecodeBytes(input, &innerV0); err != nil {
|
||||
return err
|
||||
}
|
||||
inner.BlobTx = innerV0.BlobTx
|
||||
inner.Version = 0
|
||||
inner.Blobs = innerV0.Blobs
|
||||
inner.Commitments = innerV0.Commitments
|
||||
inner.Proofs = innerV0.Proofs
|
||||
// Now we know it's the network encoding with the blob sidecar. Here we again need to
|
||||
// support multiple encodings: legacy sidecars (v0) with a blob proof, and versioned
|
||||
// sidecars.
|
||||
//
|
||||
// The legacy encoding is:
|
||||
//
|
||||
// [tx, blobs, commitments, proofs]
|
||||
//
|
||||
// The versioned encoding is:
|
||||
//
|
||||
// [tx, version, blobs, ...]
|
||||
//
|
||||
// We can tell the two apart by checking whether the second element is the version byte.
|
||||
// For legacy sidecar the second element is a list of blobs.
|
||||
|
||||
secondElemKind, _, _, err := rlp.Split(secondElem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*tx = *inner.BlobTx
|
||||
tx.Sidecar = &BlobTxSidecar{
|
||||
Version: inner.Version,
|
||||
Blobs: inner.Blobs,
|
||||
Commitments: inner.Commitments,
|
||||
Proofs: inner.Proofs,
|
||||
var payload blobTxWithBlobs
|
||||
if secondElemKind == rlp.List {
|
||||
// No version byte: blob sidecar v0.
|
||||
payload = new(blobTxWithBlobsV0)
|
||||
} else {
|
||||
// It has a version byte. Decode as v1, version is checked by assign()
|
||||
payload = new(blobTxWithBlobsV1)
|
||||
}
|
||||
if err := rlp.DecodeBytes(input, payload); err != nil {
|
||||
return err
|
||||
}
|
||||
sc := new(BlobTxSidecar)
|
||||
if err := payload.assign(sc); err != nil {
|
||||
return err
|
||||
}
|
||||
*tx = *payload.tx()
|
||||
tx.Sidecar = sc
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue