mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
sync blob tx encoding/decoding fixes (#879)
* feat(transactions): support blob tx only in encoding/decoding (#626) * draft change * fix CI * remove CancunBlock params and change cancunSigner to londonSignerWithEIP4844 * support blob transactions in receipt * trigger ci * bump version * feat(ethclient & gethclient): support blob transaction (#661) * feat: support blob transaction * sync tx encoding/decoding * more fixes * add uint236 support in rlp encoding decoding * revert a format change * trigger ci --------- Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com>
This commit is contained in:
parent
9c7381669e
commit
0892822b8c
9 changed files with 78 additions and 21 deletions
|
|
@ -59,6 +59,7 @@ type Receipt struct {
|
||||||
Logs []*Log `json:"logs" gencodec:"required"`
|
Logs []*Log `json:"logs" gencodec:"required"`
|
||||||
|
|
||||||
// Implementation fields: These fields are added by geth when processing a transaction.
|
// Implementation fields: These fields are added by geth when processing a transaction.
|
||||||
|
// They are stored in the chain database.
|
||||||
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
|
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
|
||||||
ContractAddress common.Address `json:"contractAddress"`
|
ContractAddress common.Address `json:"contractAddress"`
|
||||||
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,9 @@ var (
|
||||||
ErrTxTypeNotSupported = errors.New("transaction type not supported")
|
ErrTxTypeNotSupported = errors.New("transaction type not supported")
|
||||||
ErrGasFeeCapTooLow = errors.New("fee cap less than base fee")
|
ErrGasFeeCapTooLow = errors.New("fee cap less than base fee")
|
||||||
errShortTypedTx = errors.New("typed transaction too short")
|
errShortTypedTx = errors.New("typed transaction too short")
|
||||||
|
errInvalidYParity = errors.New("'yParity' field must be 0 or 1")
|
||||||
|
errVYParityMismatch = errors.New("'v' and 'yParity' fields do not match")
|
||||||
|
errVYParityMissing = errors.New("missing 'yParity' or 'v' field in transaction")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Transaction types.
|
// Transaction types.
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -47,6 +48,11 @@ type txJSON struct {
|
||||||
S *hexutil.Big `json:"s"`
|
S *hexutil.Big `json:"s"`
|
||||||
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
|
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
|
||||||
|
|
||||||
|
// Blob transaction sidecar encoding:
|
||||||
|
Blobs []kzg4844.Blob `json:"blobs,omitempty"`
|
||||||
|
Commitments []kzg4844.Commitment `json:"commitments,omitempty"`
|
||||||
|
Proofs []kzg4844.Proof `json:"proofs,omitempty"`
|
||||||
|
|
||||||
// Only used for encoding:
|
// Only used for encoding:
|
||||||
Hash common.Hash `json:"hash"`
|
Hash common.Hash `json:"hash"`
|
||||||
|
|
||||||
|
|
@ -61,18 +67,18 @@ func (tx *txJSON) yParityValue() (*big.Int, error) {
|
||||||
if tx.YParity != nil {
|
if tx.YParity != nil {
|
||||||
val := uint64(*tx.YParity)
|
val := uint64(*tx.YParity)
|
||||||
if val != 0 && val != 1 {
|
if val != 0 && val != 1 {
|
||||||
return nil, errors.New("'yParity' field must be 0 or 1")
|
return nil, errInvalidYParity
|
||||||
}
|
}
|
||||||
bigval := new(big.Int).SetUint64(val)
|
bigval := new(big.Int).SetUint64(val)
|
||||||
if tx.V != nil && tx.V.ToInt().Cmp(bigval) != 0 {
|
if tx.V != nil && tx.V.ToInt().Cmp(bigval) != 0 {
|
||||||
return nil, errors.New("'v' and 'yParity' fields do not match")
|
return nil, errVYParityMismatch
|
||||||
}
|
}
|
||||||
return bigval, nil
|
return bigval, nil
|
||||||
}
|
}
|
||||||
if tx.V != nil {
|
if tx.V != nil {
|
||||||
return tx.V.ToInt(), nil
|
return tx.V.ToInt(), nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("missing 'yParity' or 'v' field in transaction")
|
return nil, errVYParityMissing
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON marshals as JSON with a hash.
|
// MarshalJSON marshals as JSON with a hash.
|
||||||
|
|
@ -146,6 +152,11 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
||||||
enc.S = (*hexutil.Big)(itx.S.ToBig())
|
enc.S = (*hexutil.Big)(itx.S.ToBig())
|
||||||
yparity := itx.V.Uint64()
|
yparity := itx.V.Uint64()
|
||||||
enc.YParity = (*hexutil.Uint64)(&yparity)
|
enc.YParity = (*hexutil.Uint64)(&yparity)
|
||||||
|
if sidecar := itx.Sidecar; sidecar != nil {
|
||||||
|
enc.Blobs = itx.Sidecar.Blobs
|
||||||
|
enc.Commitments = itx.Sidecar.Commitments
|
||||||
|
enc.Proofs = itx.Sidecar.Proofs
|
||||||
|
}
|
||||||
|
|
||||||
case *L1MessageTx:
|
case *L1MessageTx:
|
||||||
enc.QueueIndex = (*hexutil.Uint64)(&itx.QueueIndex)
|
enc.QueueIndex = (*hexutil.Uint64)(&itx.QueueIndex)
|
||||||
|
|
@ -306,9 +317,6 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
||||||
return errors.New("missing required field 'input' in transaction")
|
return errors.New("missing required field 'input' in transaction")
|
||||||
}
|
}
|
||||||
itx.Data = *dec.Input
|
itx.Data = *dec.Input
|
||||||
if dec.V == nil {
|
|
||||||
return errors.New("missing required field 'v' in transaction")
|
|
||||||
}
|
|
||||||
if dec.AccessList != nil {
|
if dec.AccessList != nil {
|
||||||
itx.AccessList = *dec.AccessList
|
itx.AccessList = *dec.AccessList
|
||||||
}
|
}
|
||||||
|
|
@ -373,9 +381,6 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
||||||
return errors.New("missing required field 'input' in transaction")
|
return errors.New("missing required field 'input' in transaction")
|
||||||
}
|
}
|
||||||
itx.Data = *dec.Input
|
itx.Data = *dec.Input
|
||||||
if dec.V == nil {
|
|
||||||
return errors.New("missing required field 'v' in transaction")
|
|
||||||
}
|
|
||||||
if dec.AccessList != nil {
|
if dec.AccessList != nil {
|
||||||
itx.AccessList = *dec.AccessList
|
itx.AccessList = *dec.AccessList
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,11 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint
|
||||||
// have the current block number available, use MakeSigner instead.
|
// have the current block number available, use MakeSigner instead.
|
||||||
func LatestSigner(config *params.ChainConfig) Signer {
|
func LatestSigner(config *params.ChainConfig) Signer {
|
||||||
if config.ChainID != nil {
|
if config.ChainID != nil {
|
||||||
|
if config.CurieBlock != nil {
|
||||||
|
return NewLondonSignerWithEIP4844(config.ChainID)
|
||||||
|
}
|
||||||
if config.CancunTime != nil {
|
if config.CancunTime != nil {
|
||||||
return NewCancunSigner(config.ChainID)
|
return NewLondonSignerWithEIP4844(config.ChainID)
|
||||||
}
|
}
|
||||||
if config.LondonBlock != nil {
|
if config.LondonBlock != nil {
|
||||||
return NewLondonSignerWithEIP4844(config.ChainID)
|
return NewLondonSignerWithEIP4844(config.ChainID)
|
||||||
|
|
@ -94,7 +97,7 @@ func LatestSignerForChainID(chainID *big.Int) Signer {
|
||||||
if chainID == nil {
|
if chainID == nil {
|
||||||
return HomesteadSigner{}
|
return HomesteadSigner{}
|
||||||
}
|
}
|
||||||
return NewCancunSigner(chainID)
|
return NewLondonSignerWithEIP4844(chainID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignTx signs the transaction using the given signer and private key.
|
// SignTx signs the transaction using the given signer and private key.
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,10 @@ type BlobTxSidecar struct {
|
||||||
|
|
||||||
// BlobHashes computes the blob hashes of the given blobs.
|
// BlobHashes computes the blob hashes of the given blobs.
|
||||||
func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
|
func (sc *BlobTxSidecar) BlobHashes() []common.Hash {
|
||||||
|
hasher := sha256.New()
|
||||||
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] = kzg4844.CalcBlobHashV1(hasher, &sc.Commitments[i])
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
@ -235,12 +236,3 @@ func (tx *BlobTx) decode(input []byte) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func blobHash(commit *kzg4844.Commitment) common.Hash {
|
|
||||||
hasher := sha256.New()
|
|
||||||
hasher.Write(commit[:])
|
|
||||||
var vhash common.Hash
|
|
||||||
hasher.Sum(vhash[:0])
|
|
||||||
vhash[0] = params.BlobTxHashVersion
|
|
||||||
return vhash
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ package kzg4844
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"errors"
|
"errors"
|
||||||
|
"hash"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -108,3 +109,21 @@ func VerifyBlobProof(blob Blob, commitment Commitment, proof Proof) error {
|
||||||
}
|
}
|
||||||
return gokzgVerifyBlobProof(blob, commitment, proof)
|
return gokzgVerifyBlobProof(blob, commitment, proof)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalcBlobHashV1 calculates the 'versioned blob hash' of a commitment.
|
||||||
|
// The given hasher must be a sha256 hash instance, otherwise the result will be invalid!
|
||||||
|
func CalcBlobHashV1(hasher hash.Hash, commit *Commitment) (vh [32]byte) {
|
||||||
|
if hasher.Size() != 32 {
|
||||||
|
panic("wrong hash size")
|
||||||
|
}
|
||||||
|
hasher.Reset()
|
||||||
|
hasher.Write(commit[:])
|
||||||
|
hasher.Sum(vh[:0])
|
||||||
|
vh[0] = 0x01 // version
|
||||||
|
return vh
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidVersionedHash checks that h is a structurally-valid versioned blob hash.
|
||||||
|
func IsValidVersionedHash(h []byte) bool {
|
||||||
|
return len(h) == 32 && h[0] == 0x01
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -677,6 +677,21 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
|
||||||
if msg.GasPrice != nil {
|
if msg.GasPrice != nil {
|
||||||
arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
|
arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
|
||||||
}
|
}
|
||||||
|
if msg.GasFeeCap != nil {
|
||||||
|
arg["maxFeePerGas"] = (*hexutil.Big)(msg.GasFeeCap)
|
||||||
|
}
|
||||||
|
if msg.GasTipCap != nil {
|
||||||
|
arg["maxPriorityFeePerGas"] = (*hexutil.Big)(msg.GasTipCap)
|
||||||
|
}
|
||||||
|
if msg.AccessList != nil {
|
||||||
|
arg["accessList"] = msg.AccessList
|
||||||
|
}
|
||||||
|
if msg.BlobGasFeeCap != nil {
|
||||||
|
arg["maxFeePerBlobGas"] = (*hexutil.Big)(msg.BlobGasFeeCap)
|
||||||
|
}
|
||||||
|
if msg.BlobHashes != nil {
|
||||||
|
arg["blobVersionedHashes"] = msg.BlobHashes
|
||||||
|
}
|
||||||
return arg
|
return arg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,21 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
|
||||||
if msg.GasPrice != nil {
|
if msg.GasPrice != nil {
|
||||||
arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
|
arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
|
||||||
}
|
}
|
||||||
|
if msg.GasFeeCap != nil {
|
||||||
|
arg["maxFeePerGas"] = (*hexutil.Big)(msg.GasFeeCap)
|
||||||
|
}
|
||||||
|
if msg.GasTipCap != nil {
|
||||||
|
arg["maxPriorityFeePerGas"] = (*hexutil.Big)(msg.GasTipCap)
|
||||||
|
}
|
||||||
|
if msg.AccessList != nil {
|
||||||
|
arg["accessList"] = msg.AccessList
|
||||||
|
}
|
||||||
|
if msg.BlobGasFeeCap != nil {
|
||||||
|
arg["maxFeePerBlobGas"] = (*hexutil.Big)(msg.BlobGasFeeCap)
|
||||||
|
}
|
||||||
|
if msg.BlobHashes != nil {
|
||||||
|
arg["blobVersionedHashes"] = msg.BlobHashes
|
||||||
|
}
|
||||||
return arg
|
return arg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,10 @@ type CallMsg struct {
|
||||||
|
|
||||||
AccessList types.AccessList // EIP-2930 access list.
|
AccessList types.AccessList // EIP-2930 access list.
|
||||||
|
|
||||||
|
// For BlobTxType
|
||||||
|
BlobGasFeeCap *big.Int
|
||||||
|
BlobHashes []common.Hash
|
||||||
|
|
||||||
// scroll-related:
|
// scroll-related:
|
||||||
// not need to have a `IsL1MessageTx` field, should always be false
|
// not need to have a `IsL1MessageTx` field, should always be false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue