mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-01 04:28:37 +00:00
core: move blobTxForPool type to blobpool.go
This commit is contained in:
parent
bddf792428
commit
e3f25c2fc9
5 changed files with 147 additions and 167 deletions
|
|
@ -147,14 +147,57 @@ type blobTxMeta struct {
|
||||||
evictionBlobFeeJumps float64 // Worse blob fee (converted to fee jumps) across all previous nonces
|
evictionBlobFeeJumps float64 // Worse blob fee (converted to fee jumps) across all previous nonces
|
||||||
}
|
}
|
||||||
|
|
||||||
// newBlobTxForPool decomposes a blob transaction into BlobTxForPool
|
// blobTxForPool is the storage representation of a blob transaction in the
|
||||||
// type.
|
// blobpool.
|
||||||
func newBlobTxForPool(tx *types.Transaction) *types.BlobTxForPool {
|
type blobTxForPool struct {
|
||||||
|
Tx *types.Transaction // tx without sidecar
|
||||||
|
Version byte
|
||||||
|
Commitments []kzg4844.Commitment
|
||||||
|
Proofs []kzg4844.Proof
|
||||||
|
Blobs []kzg4844.Blob
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sidecar returns BlobTxSidecar of ptx.
|
||||||
|
func (ptx *blobTxForPool) Sidecar() *types.BlobTxSidecar {
|
||||||
|
return types.NewBlobTxSidecar(ptx.Version, ptx.Blobs, ptx.Commitments, ptx.Proofs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSidecar copies the sidecar's fields into the flat fields.
|
||||||
|
func (ptx *blobTxForPool) WithSidecar(sc *types.BlobTxSidecar) {
|
||||||
|
ptx.Version = sc.Version
|
||||||
|
ptx.Commitments = sc.Commitments
|
||||||
|
ptx.Proofs = sc.Proofs
|
||||||
|
ptx.Blobs = sc.Blobs
|
||||||
|
}
|
||||||
|
|
||||||
|
// TxSize returns the transaction size on the network without
|
||||||
|
// reconstructing the transaction.
|
||||||
|
func (ptx *blobTxForPool) TxSize() uint64 {
|
||||||
|
var blobs, commitments, proofs uint64
|
||||||
|
for i := range ptx.Blobs {
|
||||||
|
blobs += rlp.BytesSize(ptx.Blobs[i][:])
|
||||||
|
}
|
||||||
|
for i := range ptx.Commitments {
|
||||||
|
commitments += rlp.BytesSize(ptx.Commitments[i][:])
|
||||||
|
}
|
||||||
|
for i := range ptx.Proofs {
|
||||||
|
proofs += rlp.BytesSize(ptx.Proofs[i][:])
|
||||||
|
}
|
||||||
|
return ptx.Tx.Size() + rlp.ListSize(rlp.ListSize(blobs)+rlp.ListSize(commitments)+rlp.ListSize(proofs))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToTx reconstructs a full Transaction with the sidecar attached.
|
||||||
|
func (ptx *blobTxForPool) ToTx() *types.Transaction {
|
||||||
|
return ptx.Tx.WithBlobTxSidecar(ptx.Sidecar())
|
||||||
|
}
|
||||||
|
|
||||||
|
// newBlobTxForPool decomposes a blob transaction into blobTxForPool type.
|
||||||
|
func newBlobTxForPool(tx *types.Transaction) *blobTxForPool {
|
||||||
sc := tx.BlobTxSidecar()
|
sc := tx.BlobTxSidecar()
|
||||||
if sc == nil {
|
if sc == nil {
|
||||||
panic("missing blob tx sidecar")
|
panic("missing blob tx sidecar")
|
||||||
}
|
}
|
||||||
return &types.BlobTxForPool{
|
return &blobTxForPool{
|
||||||
Tx: tx.WithoutBlobTxSidecar(),
|
Tx: tx.WithoutBlobTxSidecar(),
|
||||||
Version: sc.Version,
|
Version: sc.Version,
|
||||||
Commitments: sc.Commitments,
|
Commitments: sc.Commitments,
|
||||||
|
|
@ -163,9 +206,72 @@ func newBlobTxForPool(tx *types.Transaction) *types.BlobTxForPool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// encodeForNetwork transforms stored blobTxForPool RLP into the standard
|
||||||
|
// network transaction encoding. This is used for getRLP.
|
||||||
|
//
|
||||||
|
// Stored RLP: [type_byte || tx_fields, version, [comms], [proofs], [blobs]]
|
||||||
|
// V0: type_byte || rlp([tx_fields, [blobs], [comms], [proofs]])
|
||||||
|
// V1: type_byte || rlp([tx_fields, version, [blobs], [comms], [proofs]])
|
||||||
|
func encodeForNetwork(storedRLP []byte) ([]byte, error) {
|
||||||
|
elems, err := rlp.SplitListValues(storedRLP)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid blobTxForPool RLP: %w", err)
|
||||||
|
}
|
||||||
|
if len(elems) < 5 {
|
||||||
|
return nil, fmt.Errorf("blobTxForPool has %d elements, need at least 5", len(elems))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Extract tx byte and other tx fields
|
||||||
|
txBytes, _, err := rlp.SplitString(elems[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid tx bytes: %w", err)
|
||||||
|
}
|
||||||
|
if len(txBytes) < 2 {
|
||||||
|
return nil, errors.New("tx bytes too short")
|
||||||
|
}
|
||||||
|
typeByte := txBytes[0]
|
||||||
|
txRLP := txBytes[1:]
|
||||||
|
|
||||||
|
// 2. Find the version of sidecar.
|
||||||
|
version, _, err := rlp.SplitString(elems[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid version: %w", err)
|
||||||
|
}
|
||||||
|
var versionByte byte
|
||||||
|
switch len(version) {
|
||||||
|
case 0:
|
||||||
|
versionByte = 0
|
||||||
|
case 1:
|
||||||
|
versionByte = version[0]
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid version length: %d", len(version))
|
||||||
|
}
|
||||||
|
// 3. Extract sidecar elements.
|
||||||
|
commitmentsRLP := elems[2]
|
||||||
|
proofsRLP := elems[3]
|
||||||
|
blobsRLP := elems[4]
|
||||||
|
|
||||||
|
// 4. Reconstruct into the network format.
|
||||||
|
var outer [][]byte
|
||||||
|
if versionByte == types.BlobSidecarVersion0 {
|
||||||
|
outer = [][]byte{txRLP, blobsRLP, commitmentsRLP, proofsRLP}
|
||||||
|
} else {
|
||||||
|
outer = [][]byte{txRLP, elems[1], blobsRLP, commitmentsRLP, proofsRLP}
|
||||||
|
}
|
||||||
|
body, err := rlp.MergeListValues(outer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Prepend type byte and wrap as an RLP string.
|
||||||
|
inner := make([]byte, 1+len(body))
|
||||||
|
inner[0] = typeByte
|
||||||
|
copy(inner[1:], body)
|
||||||
|
return rlp.EncodeToBytes(inner)
|
||||||
|
}
|
||||||
|
|
||||||
// newBlobTxMeta retrieves the indexed metadata fields from a pooled blob
|
// newBlobTxMeta retrieves the indexed metadata fields from a pooled blob
|
||||||
// transaction and assembles a helper struct to track in memory.
|
// transaction and assembles a helper struct to track in memory.
|
||||||
func newBlobTxMeta(id uint64, size uint64, storageSize uint32, ptx *types.BlobTxForPool) *blobTxMeta {
|
func newBlobTxMeta(id uint64, size uint64, storageSize uint32, ptx *blobTxForPool) *blobTxMeta {
|
||||||
meta := &blobTxMeta{
|
meta := &blobTxMeta{
|
||||||
hash: ptx.Tx.Hash(),
|
hash: ptx.Tx.Hash(),
|
||||||
vhashes: ptx.Tx.BlobHashes(),
|
vhashes: ptx.Tx.BlobHashes(),
|
||||||
|
|
@ -608,7 +714,7 @@ func (p *BlobPool) Close() error {
|
||||||
// each transaction on disk to create the in-memory metadata index.
|
// each transaction on disk to create the in-memory metadata index.
|
||||||
// Return value `bool` is set to true when the entry has old Transaction type.
|
// Return value `bool` is set to true when the entry has old Transaction type.
|
||||||
func (p *BlobPool) parseTransaction(id uint64, size uint32, blob []byte) (bool, error) {
|
func (p *BlobPool) parseTransaction(id uint64, size uint32, blob []byte) (bool, error) {
|
||||||
ptx := new(types.BlobTxForPool)
|
ptx := new(blobTxForPool)
|
||||||
if err := rlp.DecodeBytes(blob, ptx); err != nil {
|
if err := rlp.DecodeBytes(blob, ptx); err != nil {
|
||||||
tx := new(types.Transaction)
|
tx := new(types.Transaction)
|
||||||
if err := rlp.DecodeBytes(blob, tx); err != nil {
|
if err := rlp.DecodeBytes(blob, tx); err != nil {
|
||||||
|
|
@ -916,7 +1022,7 @@ func (p *BlobPool) offload(addr common.Address, nonce uint64, id uint64, inclusi
|
||||||
log.Error("Blobs missing for included transaction", "from", addr, "nonce", nonce, "id", id, "err", err)
|
log.Error("Blobs missing for included transaction", "from", addr, "nonce", nonce, "id", id, "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ptx := new(types.BlobTxForPool)
|
ptx := new(blobTxForPool)
|
||||||
if err := rlp.DecodeBytes(data, ptx); err != nil {
|
if err := rlp.DecodeBytes(data, ptx); err != nil {
|
||||||
log.Error("Blobs corrupted for included transaction", "from", addr, "nonce", nonce, "id", id, "err", err)
|
log.Error("Blobs corrupted for included transaction", "from", addr, "nonce", nonce, "id", id, "err", err)
|
||||||
return
|
return
|
||||||
|
|
@ -1456,7 +1562,7 @@ func (p *BlobPool) Get(hash common.Hash) *types.Transaction {
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ptx := new(types.BlobTxForPool)
|
ptx := new(blobTxForPool)
|
||||||
if err := rlp.DecodeBytes(data, ptx); err != nil {
|
if err := rlp.DecodeBytes(data, ptx); err != nil {
|
||||||
id, _ := p.lookup.storeidOfTx(hash)
|
id, _ := p.lookup.storeidOfTx(hash)
|
||||||
|
|
||||||
|
|
@ -1470,7 +1576,7 @@ func (p *BlobPool) Get(hash common.Hash) *types.Transaction {
|
||||||
// GetRLP returns a RLP-encoded transaction for network if it is contained in the pool.
|
// GetRLP returns a RLP-encoded transaction for network if it is contained in the pool.
|
||||||
func (p *BlobPool) GetRLP(hash common.Hash) []byte {
|
func (p *BlobPool) GetRLP(hash common.Hash) []byte {
|
||||||
data := p.getRLP(hash)
|
data := p.getRLP(hash)
|
||||||
rlp, err := types.EncodeForNetwork(data)
|
rlp, err := encodeForNetwork(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to encode pooled tx into the network type", "hash", hash, "err", err)
|
log.Error("Failed to encode pooled tx into the network type", "hash", hash, "err", err)
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -1545,7 +1651,7 @@ func (p *BlobPool) GetBlobs(vhashes []common.Hash, version byte) ([]*kzg4844.Blo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode the blob transaction
|
// Decode the blob transaction
|
||||||
ptx := new(types.BlobTxForPool)
|
ptx := new(blobTxForPool)
|
||||||
if err := rlp.DecodeBytes(data, ptx); err != nil {
|
if err := rlp.DecodeBytes(data, ptx); err != nil {
|
||||||
log.Error("Blobs corrupted for traced transaction", "id", txID, "err", err)
|
log.Error("Blobs corrupted for traced transaction", "id", txID, "err", err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,7 @@ func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64,
|
||||||
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
|
return types.MustSignNewTx(key, types.LatestSigner(params.MainnetChainConfig), blobtx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// encodeForPool encodes a blob transaction in the BlobTxForPool storage format.
|
// encodeForPool encodes a blob transaction in the blobTxForPool storage format.
|
||||||
func encodeForPool(tx *types.Transaction) []byte {
|
func encodeForPool(tx *types.Transaction) []byte {
|
||||||
blob, _ := rlp.EncodeToBytes(newBlobTxForPool(tx))
|
blob, _ := rlp.EncodeToBytes(newBlobTxForPool(tx))
|
||||||
return blob
|
return blob
|
||||||
|
|
@ -2061,6 +2061,32 @@ func TestGetBlobs(t *testing.T) {
|
||||||
pool.Close()
|
pool.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestEncodeForNetwork verifies that encodeForNetwork produces output identical
|
||||||
|
// to rlp.EncodeToBytes on the original transaction, for both V0 and V1 sidecars.
|
||||||
|
func TestEncodeForNetwork(t *testing.T) {
|
||||||
|
t.Run("v0", func(t *testing.T) { testEncodeForNetwork(t, types.BlobSidecarVersion0) })
|
||||||
|
t.Run("v1", func(t *testing.T) { testEncodeForNetwork(t, types.BlobSidecarVersion1) })
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEncodeForNetwork(t *testing.T, version byte) {
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
tx := makeMultiBlobTx(0, 1, 1, 1, 1, 0, key, version)
|
||||||
|
|
||||||
|
wantRLP, err := rlp.EncodeToBytes(tx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to encode tx: %v", err)
|
||||||
|
}
|
||||||
|
storedRLP := encodeForPool(tx)
|
||||||
|
|
||||||
|
gotRLP, err := encodeForNetwork(storedRLP)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("encodeForNetwork failed: %v", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(gotRLP, wantRLP) {
|
||||||
|
t.Fatalf("network encoding mismatch (version %d): got %d bytes, want %d bytes", version, len(gotRLP), len(wantRLP))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fakeBilly is a billy.Database implementation which just drops data on the floor.
|
// fakeBilly is a billy.Database implementation which just drops data on the floor.
|
||||||
type fakeBilly struct {
|
type fakeBilly struct {
|
||||||
billy.Database
|
billy.Database
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import (
|
||||||
type limboBlob struct {
|
type limboBlob struct {
|
||||||
TxHash common.Hash // Owner transaction's hash to support resurrecting reorged txs
|
TxHash common.Hash // Owner transaction's hash to support resurrecting reorged txs
|
||||||
Block uint64 // Block in which the blob transaction was included
|
Block uint64 // Block in which the blob transaction was included
|
||||||
Ptx *types.BlobTxForPool
|
Ptx *blobTxForPool
|
||||||
}
|
}
|
||||||
|
|
||||||
// limbo is a light, indexed database to temporarily store recently included
|
// limbo is a light, indexed database to temporarily store recently included
|
||||||
|
|
@ -146,7 +146,7 @@ func (l *limbo) finalize(final *types.Header) {
|
||||||
|
|
||||||
// push stores a new blob transaction into the limbo, waiting until finality for
|
// push stores a new blob transaction into the limbo, waiting until finality for
|
||||||
// it to be automatically evicted.
|
// it to be automatically evicted.
|
||||||
func (l *limbo) push(ptx *types.BlobTxForPool, block uint64) error {
|
func (l *limbo) push(ptx *blobTxForPool, block uint64) error {
|
||||||
hash := ptx.Tx.Hash()
|
hash := ptx.Tx.Hash()
|
||||||
if _, ok := l.index[hash]; ok {
|
if _, ok := l.index[hash]; ok {
|
||||||
log.Error("Limbo cannot push already tracked blobs", "tx", hash)
|
log.Error("Limbo cannot push already tracked blobs", "tx", hash)
|
||||||
|
|
@ -162,7 +162,7 @@ func (l *limbo) push(ptx *types.BlobTxForPool, block uint64) error {
|
||||||
// pull retrieves a previously pushed set of blobs back from the limbo, removing
|
// pull retrieves a previously pushed set of blobs back from the limbo, removing
|
||||||
// it at the same time. This method should be used when a previously included blob
|
// it at the same time. This method should be used when a previously included blob
|
||||||
// transaction gets reorged out.
|
// transaction gets reorged out.
|
||||||
func (l *limbo) pull(tx common.Hash) (*types.BlobTxForPool, error) {
|
func (l *limbo) pull(tx common.Hash) (*blobTxForPool, error) {
|
||||||
// If the blobs are not tracked by the limbo, there's not much to do. This
|
// If the blobs are not tracked by the limbo, there's not much to do. This
|
||||||
// can happen for example if a blob transaction is mined without pushing it
|
// can happen for example if a blob transaction is mined without pushing it
|
||||||
// into the network first.
|
// into the network first.
|
||||||
|
|
@ -239,7 +239,7 @@ func (l *limbo) getAndDrop(id uint64) (*limboBlob, error) {
|
||||||
|
|
||||||
// setAndIndex assembles a limbo blob database entry and stores it, also updating
|
// setAndIndex assembles a limbo blob database entry and stores it, also updating
|
||||||
// the in-memory indices.
|
// the in-memory indices.
|
||||||
func (l *limbo) setAndIndex(ptx *types.BlobTxForPool, block uint64) error {
|
func (l *limbo) setAndIndex(ptx *blobTxForPool, block uint64) error {
|
||||||
txhash := ptx.Tx.Hash()
|
txhash := ptx.Tx.Hash()
|
||||||
item := &limboBlob{
|
item := &limboBlob{
|
||||||
TxHash: txhash,
|
TxHash: txhash,
|
||||||
|
|
|
||||||
|
|
@ -176,112 +176,6 @@ func (sc *BlobTxSidecar) Copy() *BlobTxSidecar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlobTxForPool is a type used for blob transaction in the blobpool.
|
|
||||||
type BlobTxForPool struct {
|
|
||||||
Tx *Transaction // tx without sidecar
|
|
||||||
Version byte
|
|
||||||
Commitments []kzg4844.Commitment
|
|
||||||
Proofs []kzg4844.Proof
|
|
||||||
Blobs []kzg4844.Blob
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sidecar returns BlobTxSidecar of ptx.
|
|
||||||
func (ptx *BlobTxForPool) Sidecar() *BlobTxSidecar {
|
|
||||||
return NewBlobTxSidecar(ptx.Version, ptx.Blobs, ptx.Commitments, ptx.Proofs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithSidecar copies the sidecar's fields into the flat fields.
|
|
||||||
func (ptx *BlobTxForPool) WithSidecar(sc *BlobTxSidecar) {
|
|
||||||
ptx.Version = sc.Version
|
|
||||||
ptx.Commitments = sc.Commitments
|
|
||||||
ptx.Proofs = sc.Proofs
|
|
||||||
ptx.Blobs = sc.Blobs
|
|
||||||
}
|
|
||||||
|
|
||||||
// TxSize returns the transaction size on the network without
|
|
||||||
// reconstructing the transaction.
|
|
||||||
func (ptx *BlobTxForPool) TxSize() uint64 {
|
|
||||||
var blobs, commitments, proofs uint64
|
|
||||||
for i := range ptx.Blobs {
|
|
||||||
blobs += rlp.BytesSize(ptx.Blobs[i][:])
|
|
||||||
}
|
|
||||||
for i := range ptx.Commitments {
|
|
||||||
commitments += rlp.BytesSize(ptx.Commitments[i][:])
|
|
||||||
}
|
|
||||||
for i := range ptx.Proofs {
|
|
||||||
proofs += rlp.BytesSize(ptx.Proofs[i][:])
|
|
||||||
}
|
|
||||||
return ptx.Tx.Size() + rlp.ListSize(rlp.ListSize(blobs)+rlp.ListSize(commitments)+rlp.ListSize(proofs))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToTx reconstructs a full Transaction with the sidecar attached.
|
|
||||||
func (ptx *BlobTxForPool) ToTx() *Transaction {
|
|
||||||
return ptx.Tx.WithBlobTxSidecar(ptx.Sidecar())
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeForNetwork transforms stored BlobTxForPool RLP into the standard
|
|
||||||
// network transaction encoding.
|
|
||||||
//
|
|
||||||
// Stored RLP: [type_byte || tx_fields, version, [comms], [proofs], [blobs]]
|
|
||||||
// V0: type_byte || rlp([tx_fields, [blobs], [comms], [proofs]])
|
|
||||||
// V1: type_byte || rlp([tx_fields, version, [blobs], [comms], [proofs]])
|
|
||||||
func EncodeForNetwork(storedRLP []byte) ([]byte, error) {
|
|
||||||
elems, err := rlp.SplitListValues(storedRLP)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid BlobTxForPool RLP: %w", err)
|
|
||||||
}
|
|
||||||
if len(elems) < 5 {
|
|
||||||
return nil, fmt.Errorf("BlobTxForPool has %d elements, need at least 5", len(elems))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. Extract tx byte and other tx fields
|
|
||||||
txBytes, _, err := rlp.SplitString(elems[0])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid tx bytes: %w", err)
|
|
||||||
}
|
|
||||||
if len(txBytes) < 2 {
|
|
||||||
return nil, errors.New("tx bytes too short")
|
|
||||||
}
|
|
||||||
typeByte := txBytes[0]
|
|
||||||
txRLP := txBytes[1:]
|
|
||||||
|
|
||||||
// 2. Find the version of sidecar.
|
|
||||||
version, _, err := rlp.SplitString(elems[1])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid version: %w", err)
|
|
||||||
}
|
|
||||||
var versionByte byte
|
|
||||||
switch len(version) {
|
|
||||||
case 0:
|
|
||||||
versionByte = 0
|
|
||||||
case 1:
|
|
||||||
versionByte = version[0]
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("invalid version length: %d", len(version))
|
|
||||||
}
|
|
||||||
// 3. Extract sidecar elements.
|
|
||||||
commitmentsRLP := elems[2]
|
|
||||||
proofsRLP := elems[3]
|
|
||||||
blobsRLP := elems[4]
|
|
||||||
|
|
||||||
// 4. Reconstruct into the network format.
|
|
||||||
var outer [][]byte
|
|
||||||
if versionByte == BlobSidecarVersion0 {
|
|
||||||
outer = [][]byte{txRLP, blobsRLP, commitmentsRLP, proofsRLP}
|
|
||||||
} else {
|
|
||||||
outer = [][]byte{txRLP, elems[1], blobsRLP, commitmentsRLP, proofsRLP}
|
|
||||||
}
|
|
||||||
body, err := rlp.MergeListValues(outer)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Prepend type byte and wrap as an RLP string.
|
|
||||||
inner := make([]byte, 1+len(body))
|
|
||||||
inner[0] = typeByte
|
|
||||||
copy(inner[1:], body)
|
|
||||||
return rlp.EncodeToBytes(inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
// blobTxWithBlobs represents blob tx with its corresponding sidecar.
|
// blobTxWithBlobs represents blob tx with its corresponding sidecar.
|
||||||
// This is an interface because sidecars are versioned.
|
// This is an interface because sidecars are versioned.
|
||||||
type blobTxWithBlobs interface {
|
type blobTxWithBlobs interface {
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,12 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -88,50 +86,6 @@ func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
|
||||||
return MustSignNewTx(key, signer, blobtx)
|
return MustSignNewTx(key, signer, blobtx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestEncodeForNetwork verifies that EncodeForNetwork produces output identical
|
|
||||||
// to rlp.EncodeToBytes on the original transaction, for both V0 and V1 sidecars.
|
|
||||||
func TestEncodeForNetwork(t *testing.T) {
|
|
||||||
t.Run("v0", func(t *testing.T) { testEncodeForNetwork(t, BlobSidecarVersion0) })
|
|
||||||
t.Run("v1", func(t *testing.T) { testEncodeForNetwork(t, BlobSidecarVersion1) })
|
|
||||||
}
|
|
||||||
|
|
||||||
func testEncodeForNetwork(t *testing.T, version byte) {
|
|
||||||
key, _ := crypto.GenerateKey()
|
|
||||||
tx := createEmptyBlobTx(key, true)
|
|
||||||
if version == BlobSidecarVersion1 {
|
|
||||||
if err := tx.BlobTxSidecar().ToV1(); err != nil {
|
|
||||||
t.Fatalf("failed to convert sidecar to v1: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wantRLP, err := rlp.EncodeToBytes(tx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to encode tx: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sc := tx.BlobTxSidecar()
|
|
||||||
ptx := &BlobTxForPool{
|
|
||||||
Tx: tx.WithoutBlobTxSidecar(),
|
|
||||||
Version: sc.Version,
|
|
||||||
Commitments: sc.Commitments,
|
|
||||||
Proofs: sc.Proofs,
|
|
||||||
Blobs: sc.Blobs,
|
|
||||||
}
|
|
||||||
storedRLP, err := rlp.EncodeToBytes(ptx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to encode BlobTxForPool: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
gotRLP, err := EncodeForNetwork(storedRLP)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("EncodeForNetwork failed: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(gotRLP, wantRLP) {
|
|
||||||
t.Fatalf("network encoding mismatch (version %d): got %d bytes, want %d bytes", version, len(gotRLP), len(wantRLP))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createEmptyBlobTxInner(withSidecar bool) *BlobTx {
|
func createEmptyBlobTxInner(withSidecar bool) *BlobTx {
|
||||||
sidecar := NewBlobTxSidecar(BlobSidecarVersion0, []kzg4844.Blob{*emptyBlob}, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof})
|
sidecar := NewBlobTxSidecar(BlobSidecarVersion0, []kzg4844.Blob{*emptyBlob}, []kzg4844.Commitment{emptyBlobCommit}, []kzg4844.Proof{emptyBlobProof})
|
||||||
blobtx := &BlobTx{
|
blobtx := &BlobTx{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue