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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (tx *Transaction) WithoutBlobTxSidecar() *Transaction {
|
||||
blobtx, ok := tx.inner.(*BlobTx)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ type BlobTxSidecar struct {
|
|||
func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
|
||||
h := make([]common.Hash, len(sc.Commitments))
|
||||
for i := range sc.Blobs {
|
||||
h[i] = blobHash(&sc.Commitments[i])
|
||||
h[i] = BlobHash(&sc.Commitments[i])
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
|
@ -190,6 +190,12 @@ func (tx *BlobTx) withoutSidecar() *BlobTx {
|
|||
return &cpy
|
||||
}
|
||||
|
||||
func (tx *BlobTx) withSidecar(sidecar *BlobTxSidecar) *BlobTx {
|
||||
cpy := *tx
|
||||
tx.Sidecar = sidecar
|
||||
return &cpy
|
||||
}
|
||||
|
||||
func (tx *BlobTx) encode(b *bytes.Buffer) error {
|
||||
if tx.Sidecar == nil {
|
||||
return rlp.Encode(b, tx)
|
||||
|
|
@ -236,7 +242,7 @@ func (tx *BlobTx) decode(input []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func blobHash(commit *kzg4844.Commitment) common.Hash {
|
||||
func BlobHash(commit *kzg4844.Commitment) common.Hash {
|
||||
hasher := sha256.New()
|
||||
hasher.Write(commit[:])
|
||||
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)
|
||||
// on a given unsigned transaction, and returns it to the caller for further
|
||||
// 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
|
||||
if err := args.setDefaults(ctx, s.b); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -29,11 +29,107 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"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/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"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
|
||||
// or a message call.
|
||||
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 {
|
||||
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 {
|
||||
return errors.New(`contract creation without any data provided`)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue