mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
internal/ethapi: fill blob sidecar
This commit is contained in:
parent
d299d770b0
commit
e469b41a45
4 changed files with 128 additions and 3 deletions
|
|
@ -424,6 +424,26 @@ func (tx *Transaction) BlobGasFeeCapIntCmp(other *big.Int) int {
|
||||||
return tx.BlobGasFeeCap().Cmp(other)
|
return tx.BlobGasFeeCap().Cmp(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithBlobTxSidecar returns a copy of tx with the blob sidecar.
|
||||||
|
func (tx *Transaction) WithBlobTxSidecar(sidecar *BlobTxSidecar) *Transaction {
|
||||||
|
blobtx, ok := tx.inner.(*BlobTx)
|
||||||
|
if !ok {
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
cpy := &Transaction{
|
||||||
|
inner: blobtx.withSidecar(sidecar),
|
||||||
|
time: tx.time,
|
||||||
|
}
|
||||||
|
// Note: tx.size cache not carried over because the sidecar was not included in size!
|
||||||
|
if h := tx.hash.Load(); h != nil {
|
||||||
|
cpy.hash.Store(h)
|
||||||
|
}
|
||||||
|
if f := tx.from.Load(); f != nil {
|
||||||
|
cpy.from.Store(f)
|
||||||
|
}
|
||||||
|
return cpy
|
||||||
|
}
|
||||||
|
|
||||||
// WithoutBlobTxSidecar returns a copy of tx with the blob sidecar removed.
|
// WithoutBlobTxSidecar returns a copy of tx with the blob sidecar removed.
|
||||||
func (tx *Transaction) WithoutBlobTxSidecar() *Transaction {
|
func (tx *Transaction) WithoutBlobTxSidecar() *Transaction {
|
||||||
blobtx, ok := tx.inner.(*BlobTx)
|
blobtx, ok := tx.inner.(*BlobTx)
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ type BlobTxSidecar struct {
|
||||||
func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
|
func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
|
||||||
h := make([]common.Hash, len(sc.Commitments))
|
h := make([]common.Hash, len(sc.Commitments))
|
||||||
for i := range sc.Blobs {
|
for i := range sc.Blobs {
|
||||||
h[i] = blobHash(&sc.Commitments[i])
|
h[i] = BlobHash(&sc.Commitments[i])
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
@ -190,6 +190,12 @@ func (tx *BlobTx) withoutSidecar() *BlobTx {
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tx *BlobTx) withSidecar(sidecar *BlobTxSidecar) *BlobTx {
|
||||||
|
cpy := *tx
|
||||||
|
tx.Sidecar = sidecar
|
||||||
|
return &cpy
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *BlobTx) encode(b *bytes.Buffer) error {
|
func (tx *BlobTx) encode(b *bytes.Buffer) error {
|
||||||
if tx.Sidecar == nil {
|
if tx.Sidecar == nil {
|
||||||
return rlp.Encode(b, tx)
|
return rlp.Encode(b, tx)
|
||||||
|
|
@ -236,7 +242,7 @@ func (tx *BlobTx) decode(input []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func blobHash(commit *kzg4844.Commitment) common.Hash {
|
func BlobHash(commit *kzg4844.Commitment) common.Hash {
|
||||||
hasher := sha256.New()
|
hasher := sha256.New()
|
||||||
hasher.Write(commit[:])
|
hasher.Write(commit[:])
|
||||||
var vhash common.Hash
|
var vhash common.Hash
|
||||||
|
|
|
||||||
|
|
@ -1839,7 +1839,7 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr
|
||||||
// FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields)
|
// FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields)
|
||||||
// on a given unsigned transaction, and returns it to the caller for further
|
// on a given unsigned transaction, and returns it to the caller for further
|
||||||
// processing (signing + broadcast).
|
// processing (signing + broadcast).
|
||||||
func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) {
|
func (s *TransactionAPI) FillTransaction(ctx context.Context, args BlobTransactionArgs) (*SignTransactionResult, error) {
|
||||||
// Set some sanity defaults and terminate on failure
|
// Set some sanity defaults and terminate on failure
|
||||||
if err := args.setDefaults(ctx, s.b); err != nil {
|
if err := args.setDefaults(ctx, s.b); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,107 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob
|
||||||
|
)
|
||||||
|
|
||||||
|
// BlobTransactionArgs represents the arguments to construct a new
|
||||||
|
// blob transaction. It includes the blob side-car.
|
||||||
|
type BlobTransactionArgs struct {
|
||||||
|
TransactionArgs
|
||||||
|
Blobs []kzg4844.Blob `json:"blobs"`
|
||||||
|
Commitments []kzg4844.Commitment `json:"commitments"`
|
||||||
|
Proofs []kzg4844.Proof `json:"proofs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (args *BlobTransactionArgs) setDefaults(ctx context.Context, b Backend) error {
|
||||||
|
// First validate and fill in other fields to avoid
|
||||||
|
// the expensive blob proof computation for an invalid transaction.
|
||||||
|
if err := args.TransactionArgs.setDefaults(ctx, b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// No blobs, we're done.
|
||||||
|
if args.Blobs == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
n := len(args.Blobs)
|
||||||
|
// Assume user provides either only blobs (w/o hashes), or
|
||||||
|
// blobs together with commitments and proofs.
|
||||||
|
if args.Commitments == nil && args.Proofs != nil {
|
||||||
|
return errors.New(`blob proofs provided while commitments were not`)
|
||||||
|
} else if args.Commitments != nil && args.Proofs == nil {
|
||||||
|
return errors.New(`blob commitments provided while proofs were not`)
|
||||||
|
}
|
||||||
|
// len(blobs) == len(commitments) == len(proofs) == len(hashes)
|
||||||
|
if args.Commitments != nil && len(args.Commitments) != n {
|
||||||
|
return fmt.Errorf("number of blobs and commitments mismatch (have=%d, want=%d)", len(args.Commitments), n)
|
||||||
|
}
|
||||||
|
if args.Proofs != nil && len(args.Proofs) != n {
|
||||||
|
return fmt.Errorf("number of blobs and proofs mismatch (have=%d, want=%d)", len(args.Proofs), n)
|
||||||
|
}
|
||||||
|
if args.BlobHashes != nil && len(args.BlobHashes) != n {
|
||||||
|
return fmt.Errorf("number of blobs and hashes mismatch (have=%d, want=%d)", len(args.BlobHashes), n)
|
||||||
|
}
|
||||||
|
if args.Commitments == nil {
|
||||||
|
// Generate commitment and proof.
|
||||||
|
commitments := make([]kzg4844.Commitment, n)
|
||||||
|
proofs := make([]kzg4844.Proof, n)
|
||||||
|
for i, b := range args.Blobs {
|
||||||
|
c, err := kzg4844.BlobToCommitment(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
commitments[i] = c
|
||||||
|
p, err := kzg4844.ComputeBlobProof(b, c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
proofs[i] = p
|
||||||
|
}
|
||||||
|
args.Commitments = commitments
|
||||||
|
args.Proofs = proofs
|
||||||
|
} else {
|
||||||
|
for i, b := range args.Blobs {
|
||||||
|
if err := kzg4844.VerifyBlobProof(b, args.Commitments[i], args.Proofs[i]); err != nil {
|
||||||
|
return fmt.Errorf("failed to verify blob proof: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hashes := make([]common.Hash, n)
|
||||||
|
for i, c := range args.Commitments {
|
||||||
|
hashes[i] = types.BlobHash(&c)
|
||||||
|
}
|
||||||
|
if args.BlobHashes != nil {
|
||||||
|
for i, h := range hashes {
|
||||||
|
if h != args.BlobHashes[i] {
|
||||||
|
return fmt.Errorf("blob hash verification failed (have=%s, want=%s)", args.BlobHashes[i], h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args.BlobHashes = hashes
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (args *BlobTransactionArgs) toTransaction() *types.Transaction {
|
||||||
|
tx := args.TransactionArgs.toTransaction()
|
||||||
|
if args.Blobs != nil && tx.Type() == types.BlobTxType {
|
||||||
|
return tx.WithBlobTxSidecar(&types.BlobTxSidecar{
|
||||||
|
Blobs: args.Blobs,
|
||||||
|
Commitments: args.Commitments,
|
||||||
|
Proofs: args.Proofs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
// TransactionArgs represents the arguments to construct a new transaction
|
// TransactionArgs represents the arguments to construct a new transaction
|
||||||
// or a message call.
|
// or a message call.
|
||||||
type TransactionArgs struct {
|
type TransactionArgs struct {
|
||||||
|
|
@ -104,6 +200,9 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
|
||||||
if args.BlobHashes != nil && len(args.BlobHashes) == 0 {
|
if args.BlobHashes != nil && len(args.BlobHashes) == 0 {
|
||||||
return errors.New(`need at least 1 blob for a blob transaction`)
|
return errors.New(`need at least 1 blob for a blob transaction`)
|
||||||
}
|
}
|
||||||
|
if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobsPerTransaction {
|
||||||
|
return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobsPerTransaction)
|
||||||
|
}
|
||||||
if args.To == nil && len(args.data()) == 0 {
|
if args.To == nil && len(args.data()) == 0 {
|
||||||
return errors.New(`contract creation without any data provided`)
|
return errors.New(`contract creation without any data provided`)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue