Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nitro 4844 devnet #249

Closed
wants to merge 11 commits into from
5 changes: 5 additions & 0 deletions arbitrum/apibackend.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
Expand Down Expand Up @@ -490,6 +491,10 @@ func (a *APIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) er
return a.b.EnqueueL2Message(ctx, signedTx, nil)
}

func (a *APIBackend) SendBlobTx(ctx context.Context, signedTx *types.Transaction, blobTxBlobs []kzg4844.Blob, blobTxCommits []kzg4844.Commitment, blobTxProofs []kzg4844.Proof) error {
panic("nitro currently doesn't support eip-4844 blob transactions")
}

func (a *APIBackend) SendConditionalTx(ctx context.Context, signedTx *types.Transaction, options *arbitrum_types.ConditionalOptions) error {
return a.b.EnqueueL2Message(ctx, signedTx, options)
}
Expand Down
8 changes: 8 additions & 0 deletions consensus/beacon/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,14 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
return nil, errors.New("withdrawals set before Shanghai activation")
}
}
if chain.Config().IsCancun(header.Number, header.Time) {
var blobs int
for _, tx := range txs {
blobs += len(tx.BlobHashes())
}
blobGasUsed := uint64(blobs * params.BlobTxBlobGasPerBlob)
header.BlobGasUsed = &blobGasUsed
}
// Finalize and assemble the block.
beacon.Finalize(chain, header, state, txs, uncles, withdrawals)

Expand Down
9 changes: 5 additions & 4 deletions consensus/misc/eip4844/eip4844_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ func TestCalcExcessBlobGas(t *testing.T) {
// The excess blob gas should decrease by however much the target was
// under-shot, capped at zero.
{params.BlobTxTargetBlobGasPerBlock, params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob, params.BlobTxTargetBlobGasPerBlock},
{params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, params.BlobTxBlobGasPerBlob},
{params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 2, 0},
{params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, 2 * params.BlobTxBlobGasPerBlob},
{params.BlobTxTargetBlobGasPerBlock, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 2, params.BlobTxBlobGasPerBlob},
{params.BlobTxBlobGasPerBlob - 1, (params.BlobTxTargetBlobGasPerBlock / params.BlobTxBlobGasPerBlob) - 1, 0},
}
for _, tt := range tests {
Expand All @@ -64,8 +64,9 @@ func TestCalcBlobFee(t *testing.T) {
}{
{0, 1},
{1542706, 1},
{1542707, 2},
{10 * 1024 * 1024, 111},
{1542707, 1},
{3085414, 2},
{10 * 1024 * 1024, 23},
}
for i, tt := range tests {
have := CalcBlobFee(tt.excessBlobGas)
Expand Down
8 changes: 8 additions & 0 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,14 @@ func (g *Genesis) ToBlock() *types.Block {
}
}
}
if g.Config != nil && g.Config.IsCancun(big.NewInt(int64(g.Number)), g.Timestamp) {
if g.ExcessBlobGas == nil {
var excessBlobGas uint64
head.ExcessBlobGas = &excessBlobGas
} else {
head.ExcessBlobGas = g.ExcessBlobGas
}
}
return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)).WithWithdrawals(withdrawals)
}

Expand Down
4 changes: 3 additions & 1 deletion core/txpool/blobpool/blobpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,8 @@ func (p *BlobPool) reinject(addr common.Address, tx *types.Transaction) {
}
p.lookup[meta.hash] = meta.id
p.stored += uint64(meta.size)

p.eventFeed.Send(core.NewTxsEvent{Txs: types.Transactions{tx}})
}

// SetGasTip implements txpool.SubPool, allowing the blob pool's gas requirements
Expand Down Expand Up @@ -1038,7 +1040,6 @@ func (p *BlobPool) validateTx(tx *types.Transaction, blobs []kzg4844.Blob, commi
// Ensure the transaction adheres to the stateful pool filters (nonce, balance)
stateOpts := &txpool.ValidationOptionsWithState{
State: p.state,

FirstNonceGap: func(addr common.Address) uint64 {
// Nonce gaps are not permitted in the blob pool, the first gap will
// be the next nonce shifted by however many transactions we already
Expand Down Expand Up @@ -1304,6 +1305,7 @@ func (p *BlobPool) add(tx *types.Transaction, blobs []kzg4844.Blob, commits []kz
}
p.updateStorageMetrics()

p.eventFeed.Send(core.NewTxsEvent{Txs: types.Transactions{tx}})
return nil
}

Expand Down
10 changes: 10 additions & 0 deletions core/txpool/subpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ type Transaction struct {
BlobTxProofs []kzg4844.Proof // Proofs needed by the blob pool
}

func (t *Transaction) Size() uint64 {
size := t.Tx.Size()
if len(t.BlobTxBlobs) > 0 {
size += uint64(len(t.BlobTxBlobs) * len(t.BlobTxBlobs[0]))
size += uint64(len(t.BlobTxCommits) * len(t.BlobTxCommits[0]))
size += uint64(len(t.BlobTxProofs) * len(t.BlobTxProofs[0]))
}
return size
}

// LazyTransaction contains a small subset of the transaction properties that is
// enough for the miner and other APIs to handle large batches of transactions;
// and supports pulling up the entire transaction when really needed.
Expand Down
2 changes: 1 addition & 1 deletion core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ func (tx *Transaction) BlobGas() uint64 { return tx.inner.blobGas() }
// BlobGasFeeCap returns the blob gas fee cap per blob gas of the transaction for blob transactions, nil otherwise.
func (tx *Transaction) BlobGasFeeCap() *big.Int { return tx.inner.blobGasFeeCap() }

// BlobHashes returns the hases of the blob commitments for blob transactions, nil otherwise.
// BlobHashes returns the hashes of the blob commitments for blob transactions, nil otherwise.
func (tx *Transaction) BlobHashes() []common.Hash { return tx.inner.blobHashes() }

// Value returns the ether amount of the transaction.
Expand Down
116 changes: 116 additions & 0 deletions core/types/tx_blob_with_blob.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package types

import (
"bytes"
"io"

"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/rlp"
)

type BlobTxWithBlobs struct {
*Transaction
Blobs []kzg4844.Blob
Commitments []kzg4844.Commitment
Proofs []kzg4844.Proof
}

func NewBlobTxWithBlobs(tx *Transaction, blobs []kzg4844.Blob, commitments []kzg4844.Commitment, proofs []kzg4844.Proof) *BlobTxWithBlobs {
if tx == nil {
return nil
}
return &BlobTxWithBlobs{
Transaction: tx,
Blobs: blobs,
Commitments: commitments,
Proofs: proofs,
}
}

type innerType struct {
BlobTx *BlobTx
Blobs []kzg4844.Blob
Commitments []kzg4844.Commitment
Proofs []kzg4844.Proof
}

func (tx *BlobTxWithBlobs) DecodeRLP(s *rlp.Stream) error {
tx.Transaction = new(Transaction)
kind, _, err := s.Kind()
switch {
case err != nil:
return err
case kind == rlp.List:
return tx.Transaction.DecodeRLP(s)
default:
b, err := s.Bytes()
if err != nil {
return err
}
return tx.UnmarshalBinary(b)
}
}

func (tx *BlobTxWithBlobs) EncodeRLP(w io.Writer) error {
blobTx, ok := tx.Transaction.inner.(*BlobTx)
if !ok {
// For non-blob transactions, the encoding is just the transaction.
return tx.Transaction.EncodeRLP(w)
}

// For blob transactions, the encoding is the transaction together with the blobs.
// Use temporary buffer from pool.
buf := encodeBufferPool.Get().(*bytes.Buffer)
defer encodeBufferPool.Put(buf)
buf.Reset()

buf.WriteByte(BlobTxType)
innerValue := &innerType{
BlobTx: blobTx,
Blobs: tx.Blobs,
Commitments: tx.Commitments,
Proofs: tx.Proofs,
}
err := rlp.Encode(buf, innerValue)
if err != nil {
return err
}
return rlp.Encode(w, buf.Bytes())
}

func (tx *BlobTxWithBlobs) UnmarshalBinary(b []byte) error {
tx.Transaction = new(Transaction)
if len(b) < 1 {
return errShortTypedTx
}
if b[0] == BlobTxType {
var blobTypedTx innerType
if err := rlp.DecodeBytes(b[1:], &blobTypedTx); err != nil {
return err
}
tx.Transaction = NewTx(blobTypedTx.BlobTx)
tx.Blobs = blobTypedTx.Blobs
tx.Commitments = blobTypedTx.Commitments
tx.Proofs = blobTypedTx.Proofs
return nil
}
return tx.Transaction.UnmarshalBinary(b)
}

func (tx *BlobTxWithBlobs) MarshalBinary() ([]byte, error) {
blobTx, ok := tx.Transaction.inner.(*BlobTx)
if !ok {
// For non-blob transactions, the encoding is just the transaction.
return tx.Transaction.MarshalBinary()
}
var buf bytes.Buffer
buf.WriteByte(BlobTxType)
innerValue := &innerType{
BlobTx: blobTx,
Blobs: tx.Blobs,
Commitments: tx.Commitments,
Proofs: tx.Proofs,
}
err := rlp.Encode(&buf, innerValue)
return buf.Bytes(), err
}
58 changes: 57 additions & 1 deletion core/types/types_test.go

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,16 @@ var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{
// PrecompiledContractsCancun contains the default set of pre-compiled Ethereum
// contracts used in the Cancun release.
var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{20}): &kzgPointEvaluation{},
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{0x0A}): &kzgPointEvaluation{},
}

// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
Expand Down Expand Up @@ -1134,7 +1134,7 @@ func (b *kzgPointEvaluation) Run(input []byte) ([]byte, error) {
// input kzg point: next 48 bytes
var commitment kzg4844.Commitment
copy(commitment[:], input[96:])
if kZGToVersionedHash(commitment) != versionedHash {
if KZGToVersionedHash(commitment) != versionedHash {
return nil, errBlobVerifyMismatchedVersion
}

Expand All @@ -1149,8 +1149,8 @@ func (b *kzgPointEvaluation) Run(input []byte) ([]byte, error) {
return common.Hex2Bytes(blobPrecompileReturnValue), nil
}

// kZGToVersionedHash implements kzg_to_versioned_hash from EIP-4844
func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
// KZGToVersionedHash implements kzg_to_versioned_hash from EIP-4844
func KZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
h := sha256.Sum256(kzg[:])
h[0] = blobCommitmentVersionKZG

Expand Down
2 changes: 1 addition & 1 deletion core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{16}): &bls12381Pairing{},
common.BytesToAddress([]byte{17}): &bls12381MapG1{},
common.BytesToAddress([]byte{18}): &bls12381MapG2{},
common.BytesToAddress([]byte{20}): &kzgPointEvaluation{},
common.BytesToAddress([]byte{0x0A}): &kzgPointEvaluation{},
}

// EIP-152 test vectors
Expand Down
5 changes: 5 additions & 0 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/ethdb"
Expand Down Expand Up @@ -297,6 +298,10 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
return b.eth.txPool.Add([]*txpool.Transaction{{Tx: signedTx}}, true, false)[0]
}

func (b *EthAPIBackend) SendBlobTx(ctx context.Context, signedTx *types.Transaction, blobTxBlobs []kzg4844.Blob, blobTxCommits []kzg4844.Commitment, blobTxProofs []kzg4844.Proof) error {
return b.eth.txPool.Add([]*txpool.Transaction{&txpool.Transaction{Tx: signedTx, BlobTxBlobs: blobTxBlobs, BlobTxCommits: blobTxCommits, BlobTxProofs: blobTxProofs}}, true, false)[0]
}

func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
pending := b.eth.txPool.Pending(false)
var txs types.Transactions
Expand Down
4 changes: 2 additions & 2 deletions eth/fetcher/tx_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func (f *TxFetcher) Notify(peer string, hashes []common.Hash) error {
// and the fetcher. This method may be called by both transaction broadcasts and
// direct request replies. The differentiation is important so the fetcher can
// re-schedule missing transactions as soon as possible.
func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool) error {
func (f *TxFetcher) Enqueue(peer string, txs []*types.BlobTxWithBlobs, direct bool) error {
var (
inMeter = txReplyInMeter
knownMeter = txReplyKnownMeter
Expand Down Expand Up @@ -297,7 +297,7 @@ func (f *TxFetcher) Enqueue(peer string, txs []*types.Transaction, direct bool)

wrapped := make([]*txpool.Transaction, len(batch))
for j, tx := range batch {
wrapped[j] = &txpool.Transaction{Tx: tx}
wrapped[j] = &txpool.Transaction{Tx: tx.Transaction, BlobTxBlobs: tx.Blobs, BlobTxCommits: tx.Commitments, BlobTxProofs: tx.Proofs}
}
for j, err := range f.addTxs(wrapped) {
// Track the transaction hash if the price is too low for us.
Expand Down
6 changes: 5 additions & 1 deletion eth/fetcher/tx_fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,11 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) {
}

case doTxEnqueue:
if err := fetcher.Enqueue(step.peer, step.txs, step.direct); err != nil {
var txs []*types.BlobTxWithBlobs
for _, tx := range step.txs {
txs = append(txs, types.NewBlobTxWithBlobs(tx, nil, nil, nil))
}
if err := fetcher.Enqueue(step.peer, txs, step.direct); err != nil {
t.Errorf("step %d: %v", i, err)
}
<-wait // Fetcher needs to process this, wait until it's done
Expand Down
2 changes: 1 addition & 1 deletion eth/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ func (h *handler) BroadcastTransactions(txs types.Transactions) {
peers := h.peers.peersWithoutTransaction(tx.Hash())

var numDirect int
if tx.Size() <= txMaxBroadcastSize {
if tx.Size() <= txMaxBroadcastSize && tx.Type() != types.BlobTxType {
numDirect = int(math.Sqrt(float64(len(peers))))
}
// Send the tx unconditionally to a subset of our peers
Expand Down
6 changes: 5 additions & 1 deletion eth/handler_eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ func (h *ethHandler) Handle(peer *eth.Peer, packet eth.Packet) error {
return h.txFetcher.Notify(peer.ID(), packet.Hashes)

case *eth.TransactionsPacket:
return h.txFetcher.Enqueue(peer.ID(), *packet, false)
var txs []*types.BlobTxWithBlobs
for _, tx := range *packet {
txs = append(txs, types.NewBlobTxWithBlobs(tx, nil, nil, nil))
}
return h.txFetcher.Enqueue(peer.ID(), txs, false)

case *eth.PooledTransactionsPacket:
return h.txFetcher.Enqueue(peer.ID(), *packet, true)
Expand Down
Loading
Loading