mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-11 02:26:38 +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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
|
@ -119,15 +120,21 @@ func (sc *BlobTxSidecar) ValidateBlobCommitmentHashes(hashes []common.Hash) erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// blobTxWithBlobs is used for encoding of transactions when blobs are present.
|
// blobTxWithBlobs represents blob tx with its corresponding sidecar.
|
||||||
type blobTxWithBlobs struct {
|
// This is an interface because sidecars are versioned.
|
||||||
|
type blobTxWithBlobs interface {
|
||||||
|
tx() *BlobTx
|
||||||
|
assign(*BlobTxSidecar) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type blobTxWithBlobsV0 struct {
|
||||||
BlobTx *BlobTx
|
BlobTx *BlobTx
|
||||||
Blobs []kzg4844.Blob
|
Blobs []kzg4844.Blob
|
||||||
Commitments []kzg4844.Commitment
|
Commitments []kzg4844.Commitment
|
||||||
Proofs []kzg4844.Proof
|
Proofs []kzg4844.Proof
|
||||||
}
|
}
|
||||||
|
|
||||||
type versionedBlobTxWithBlobs struct {
|
type blobTxWithBlobsV1 struct {
|
||||||
BlobTx *BlobTx
|
BlobTx *BlobTx
|
||||||
Version byte
|
Version byte
|
||||||
Blobs []kzg4844.Blob
|
Blobs []kzg4844.Blob
|
||||||
|
|
@ -135,6 +142,33 @@ type versionedBlobTxWithBlobs struct {
|
||||||
Proofs []kzg4844.Proof
|
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.
|
// copy creates a deep copy of the transaction data and initializes all fields.
|
||||||
func (tx *BlobTx) copy() TxData {
|
func (tx *BlobTx) copy() TxData {
|
||||||
cpy := &BlobTx{
|
cpy := &BlobTx{
|
||||||
|
|
@ -240,69 +274,98 @@ func (tx *BlobTx) withSidecar(sideCar *BlobTxSidecar) *BlobTx {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *BlobTx) encode(b *bytes.Buffer) error {
|
func (tx *BlobTx) encode(b *bytes.Buffer) error {
|
||||||
if tx.Sidecar == nil {
|
switch {
|
||||||
|
case tx.Sidecar == nil:
|
||||||
return rlp.Encode(b, tx)
|
return rlp.Encode(b, tx)
|
||||||
}
|
|
||||||
// Encode a cell proof transaction
|
case tx.Sidecar.Version == 0:
|
||||||
if tx.Sidecar.Version != 0 {
|
return rlp.Encode(b, &blobTxWithBlobsV0{
|
||||||
inner := &versionedBlobTxWithBlobs{
|
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,
|
BlobTx: tx,
|
||||||
Version: tx.Sidecar.Version,
|
Version: tx.Sidecar.Version,
|
||||||
Blobs: tx.Sidecar.Blobs,
|
Blobs: tx.Sidecar.Blobs,
|
||||||
Commitments: tx.Sidecar.Commitments,
|
Commitments: tx.Sidecar.Commitments,
|
||||||
Proofs: tx.Sidecar.Proofs,
|
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 {
|
func (tx *BlobTx) decode(input []byte) error {
|
||||||
// Here we need to support two formats: the network protocol encoding of the tx (with
|
// Here we need to support two outer formats: the network protocol encoding of the tx
|
||||||
// blobs) or the canonical encoding without blobs.
|
// (with blobs) or the canonical encoding without blobs.
|
||||||
//
|
//
|
||||||
// The two encodings can be distinguished by checking whether the first element of the
|
// The canonical encoding is just a list of fields:
|
||||||
// input list is itself a list.
|
//
|
||||||
|
// [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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
firstElemKind, _, _, err := rlp.Split(outerList)
|
firstElemKind, _, secondElem, err := rlp.Split(firstElem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if firstElemKind != rlp.List {
|
if firstElemKind != rlp.List {
|
||||||
|
// Blob tx without blobs.
|
||||||
return rlp.DecodeBytes(input, tx)
|
return rlp.DecodeBytes(input, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's a tx with blobs. Try to decode it as version 0.
|
// Now we know it's the network encoding with the blob sidecar. Here we again need to
|
||||||
var inner versionedBlobTxWithBlobs
|
// support multiple encodings: legacy sidecars (v0) with a blob proof, and versioned
|
||||||
if err := rlp.DecodeBytes(input, &inner); err != nil {
|
// sidecars.
|
||||||
var innerV0 blobTxWithBlobs
|
//
|
||||||
if err := rlp.DecodeBytes(input, &innerV0); err != nil {
|
// The legacy encoding is:
|
||||||
return err
|
//
|
||||||
}
|
// [tx, blobs, commitments, proofs]
|
||||||
inner.BlobTx = innerV0.BlobTx
|
//
|
||||||
inner.Version = 0
|
// The versioned encoding is:
|
||||||
inner.Blobs = innerV0.Blobs
|
//
|
||||||
inner.Commitments = innerV0.Commitments
|
// [tx, version, blobs, ...]
|
||||||
inner.Proofs = innerV0.Proofs
|
//
|
||||||
|
// 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
|
var payload blobTxWithBlobs
|
||||||
tx.Sidecar = &BlobTxSidecar{
|
if secondElemKind == rlp.List {
|
||||||
Version: inner.Version,
|
// No version byte: blob sidecar v0.
|
||||||
Blobs: inner.Blobs,
|
payload = new(blobTxWithBlobsV0)
|
||||||
Commitments: inner.Commitments,
|
} else {
|
||||||
Proofs: inner.Proofs,
|
// 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue