diff --git a/restricted/params/protocol_params.go b/restricted/params/protocol_params.go index 7abb244..3435e3c 100644 --- a/restricted/params/protocol_params.go +++ b/restricted/params/protocol_params.go @@ -152,6 +152,19 @@ const ( Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation Bls12381MapG2Gas uint64 = 110000 // Gas price for BLS12-381 mapping field element to G2 operation + BlobTxHashVersion = 0x01 // Version byte of the commitment hash + BlobTxMaxDataGasPerBlock = 1 << 19 // Maximum consumable data gas for data blobs per block + BlobTxTargetDataGasPerBlock = 1 << 18 // Target consumable data gas for data blobs per block (for 1559-like pricing) + BlobTxDataGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size) + BlobTxMinDataGasprice = 1 // Minimum gas price for data blobs + BlobTxDataGaspriceUpdateFraction = 2225652 // Controls the maximum rate of change for data gas price + BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile. + BlobTxTargetBlobGasPerBlock = 1 << 18 // Target consumable blob gas for data blobs per block (for 1559-like pricing) + + BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs + BlobTxBlobGaspriceUpdateFraction = 2225652 // Controls the maximum rate of change for blob gas price + + // The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529, // up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529 RefundQuotient uint64 = 2 diff --git a/restricted/types/access_list_tx.go b/restricted/types/access_list_tx.go index 1d5b0cd..3f624a8 100644 --- a/restricted/types/access_list_tx.go +++ b/restricted/types/access_list_tx.go @@ -105,6 +105,9 @@ func (tx *AccessListTx) gasFeeCap() *big.Int { return tx.GasPrice } func (tx *AccessListTx) value() *big.Int { return tx.Value } func (tx *AccessListTx) nonce() uint64 { return tx.Nonce } func (tx *AccessListTx) to() *core.Address { return tx.To } +func (tx *AccessListTx) blobGas() uint64 { return 0} +func (tx *AccessListTx) blobGasFeeCap() *big.Int { return nil } +func (tx *AccessListTx) blobHashes() []core.Hash { return nil } func (tx *AccessListTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { return dst.Set(tx.GasPrice) diff --git a/restricted/types/block.go b/restricted/types/block.go index 553246c..0e417ef 100644 --- a/restricted/types/block.go +++ b/restricted/types/block.go @@ -90,11 +90,14 @@ type Header struct { // WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers. WithdrawalsHash *core.Hash `json:"withdrawalsRoot" rlp:"optional"` - /* - TODO (MariusVanDerWijden) Add this field once needed - // Random was added during the merge and contains the BeaconState randomness - Random core.Hash `json:"random" rlp:"optional"` - */ + // BlobGasUsed was added by EIP-4844 and is ignored in legacy headers. + BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"` + + // ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers. + ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"` + + // ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers. + ParentBeaconRoot *core.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` } // field type overrides for gencodec @@ -283,6 +286,18 @@ func CopyHeader(h *Header) *Header { if h.WithdrawalsHash != nil { *cpy.WithdrawalsHash = *h.WithdrawalsHash } + if h.ExcessBlobGas != nil { + cpy.ExcessBlobGas = new(uint64) + *cpy.ExcessBlobGas = *h.ExcessBlobGas + } + if h.BlobGasUsed != nil { + cpy.BlobGasUsed = new(uint64) + *cpy.BlobGasUsed = *h.BlobGasUsed + } + if h.ParentBeaconRoot != nil { + cpy.ParentBeaconRoot = new(core.Hash) + *cpy.ParentBeaconRoot = *h.ParentBeaconRoot + } return &cpy } @@ -347,6 +362,26 @@ func (b *Block) BaseFee() *big.Int { return new(big.Int).Set(b.header.BaseFee) } +func (b *Block) BeaconRoot() *core.Hash { return b.header.ParentBeaconRoot } + +func (b *Block) ExcessBlobGas() *uint64 { + var excessBlobGas *uint64 + if b.header.ExcessBlobGas != nil { + excessBlobGas = new(uint64) + *excessBlobGas = *b.header.ExcessBlobGas + } + return excessBlobGas +} + +func (b *Block) BlobGasUsed() *uint64 { + var blobGasUsed *uint64 + if b.header.BlobGasUsed != nil { + blobGasUsed = new(uint64) + *blobGasUsed = *b.header.BlobGasUsed + } + return blobGasUsed +} + func (b *Block) Withdrawals() Withdrawals { return b.withdrawals } @@ -391,10 +426,8 @@ func CalcUncleHash(uncles []*Header) core.Hash { // WithSeal returns a new block with the data from b but the header replaced with // the sealed one. func (b *Block) WithSeal(header *Header) *Block { - cpy := *header - return &Block{ - header: &cpy, + header: CopyHeader(header), transactions: b.transactions, uncles: b.uncles, withdrawals: b.withdrawals, @@ -407,6 +440,7 @@ func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { header: CopyHeader(b.header), transactions: make([]*Transaction, len(transactions)), uncles: make([]*Header, len(uncles)), + withdrawals: b.withdrawals, } copy(block.transactions, transactions) for i := range uncles { @@ -417,11 +451,16 @@ func (b *Block) WithBody(transactions []*Transaction, uncles []*Header) *Block { // WithWithdrawals sets the withdrawal contents of a block, does not return a new block. func (b *Block) WithWithdrawals(withdrawals []*Withdrawal) *Block { - if withdrawals != nil { - b.withdrawals = make([]*Withdrawal, len(withdrawals)) - copy(b.withdrawals, withdrawals) + block := &Block{ + header: b.header, + transactions: b.transactions, + uncles: b.uncles, } - return b + if withdrawals != nil { + block.withdrawals = make([]*Withdrawal, len(withdrawals)) + copy(block.withdrawals, withdrawals) + } + return block } // Hash returns the keccak256 hash of b's header. diff --git a/restricted/types/dynamic_fee_tx.go b/restricted/types/dynamic_fee_tx.go index 70ef615..7546e9b 100644 --- a/restricted/types/dynamic_fee_tx.go +++ b/restricted/types/dynamic_fee_tx.go @@ -93,6 +93,9 @@ func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.GasFeeCap } func (tx *DynamicFeeTx) value() *big.Int { return tx.Value } func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce } func (tx *DynamicFeeTx) to() *core.Address { return tx.To } +func (tx *DynamicFeeTx) blobGas() uint64 { return 0} +func (tx *DynamicFeeTx) blobGasFeeCap() *big.Int { return nil } +func (tx *DynamicFeeTx) blobHashes() []core.Hash { return nil } func (tx *DynamicFeeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { if baseFee == nil { diff --git a/restricted/types/hashing_test.go b/restricted/types/hashing_test.go index c0556d1..d8b2cd0 100644 --- a/restricted/types/hashing_test.go +++ b/restricted/types/hashing_test.go @@ -136,10 +136,9 @@ func (d *hashToHumanReadable) Reset() { d.data = make([]byte, 0) } -func (d *hashToHumanReadable) Update(i []byte, i2 []byte) error { +func (d *hashToHumanReadable) Update(i []byte, i2 []byte) { l := fmt.Sprintf("%x %x\n", i, i2) d.data = append(d.data, []byte(l)...) - return nil } func (d *hashToHumanReadable) Hash() core.Hash { diff --git a/restricted/types/legacy_tx.go b/restricted/types/legacy_tx.go index 8318df0..3a4ab17 100644 --- a/restricted/types/legacy_tx.go +++ b/restricted/types/legacy_tx.go @@ -102,6 +102,9 @@ func (tx *LegacyTx) gasFeeCap() *big.Int { return tx.GasPrice } func (tx *LegacyTx) value() *big.Int { return tx.Value } func (tx *LegacyTx) nonce() uint64 { return tx.Nonce } func (tx *LegacyTx) to() *core.Address { return tx.To } +func (tx *LegacyTx) blobGas() uint64 { return 0} +func (tx *LegacyTx) blobGasFeeCap() *big.Int { return nil } +func (tx *LegacyTx) blobHashes() []core.Hash { return nil } func (tx *LegacyTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { return dst.Set(tx.GasPrice) diff --git a/restricted/types/transaction.go b/restricted/types/transaction.go index 2397e15..d40099c 100644 --- a/restricted/types/transaction.go +++ b/restricted/types/transaction.go @@ -44,6 +44,7 @@ const ( LegacyTxType = iota AccessListTxType DynamicFeeTxType + BlobTxType ) // Transaction is an Ethereum transaction. @@ -86,6 +87,9 @@ type TxData interface { value() *big.Int nonce() uint64 to() *core.Address + blobGas() uint64 + blobGasFeeCap() *big.Int + blobHashes() []core.Hash rawSignatureValues() (v, r, s *big.Int) setSignatureValues(chainID, v, r, s *big.Int) @@ -200,6 +204,10 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { var inner DynamicFeeTx err := rlp.DecodeBytes(b[1:], &inner) return &inner, err + case BlobTxType: + var inner BlobTx + err := rlp.DecodeBytes(b[1:], &inner) + return &inner, err default: return nil, ErrTxTypeNotSupported } @@ -295,15 +303,26 @@ func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value // Nonce returns the sender account nonce of the transaction. func (tx *Transaction) Nonce() uint64 { return tx.inner.nonce() } +// BlobGasFeeCap returns the fee cap per gas of the transaction. +func (tx *Transaction) BlobGasFeeCap() *big.Int { return new(big.Int).Set(tx.inner.blobGasFeeCap()) } + +// BlobGas returns the blob gas of the transaction. +func (tx *Transaction) BlobGas() uint64 { return tx.inner.blobGas() } + +func (tx *Transaction) BlobHashes() []core.Hash { return tx.inner.blobHashes() } + // To returns the recipient address of the transaction. // For contract-creation transactions, To returns nil. func (tx *Transaction) To() *core.Address { return copyAddressPtr(tx.inner.to()) } -// Cost returns gas * gasPrice + value. +// Cost returns (gas * gasPrice) + (blobGas * blobGasPrice) + value. func (tx *Transaction) Cost() *big.Int { total := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas())) + if tx.Type() == BlobTxType { + total.Add(total, new(big.Int).Mul(tx.BlobGasFeeCap(), new(big.Int).SetUint64(tx.BlobGas()))) + } total.Add(total, tx.Value()) return total }