op-erigon

+6356
-807

This is an overview of the changes in op-erigon, a fork of erigon, part of the Boba Network OP Stack.

There is one more fork of erigon dependencies:

The Bedrock upgrade introduces a Deposit transaction-type (0x7E) to enable both users and the rollup system itself to change the L2 state based on L1 events and system rules as specified.

diff --git ledgerwatch/erigon/core/types/deposit_tx.go bobanetwork/v3-erigon/core/types/deposit_tx.go new file mode 100644 index 0000000000000000000000000000000000000000..62b7bb3a06f4f37287e2ef869600d84349763870 --- /dev/null +++ bobanetwork/v3-erigon/core/types/deposit_tx.go @@ -0,0 +1,455 @@ +// Copyright 2021 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package types + +import ( + "fmt" + "io" + "math/big" + "math/bits" + "sync/atomic" + "time" + + "github.com/ledgerwatch/erigon-lib/chain" + libcommon "github.com/ledgerwatch/erigon-lib/common" + types2 "github.com/ledgerwatch/erigon-lib/types" + + "github.com/ledgerwatch/erigon/rlp" + + "github.com/holiman/uint256" +) + +type DepositTx struct { + time time.Time // Time first seen locally (spam avoidance) + // caches + hash atomic.Value //nolint:structcheck + size atomic.Value //nolint:structcheck + // SourceHash uniquely identifies the source of the deposit + SourceHash libcommon.Hash + // From is exposed through the types.Signer, not through TxData + From libcommon.Address + // nil means contract creation + To *libcommon.Address `rlp:"nil"` + // Mint is minted on L2, locked on L1, nil if no minting. + Mint *uint256.Int `rlp:"nil"` + // Value is transferred from L2 balance, executed after Mint (if any) + Value *uint256.Int + // gas limit + Gas uint64 + // Field indicating if this transaction is exempt from the L2 gas limit. + IsSystemTransaction bool + // Normal Tx data + Data []byte +} + +var _ Transaction = (*DepositTx)(nil) + +func (tx DepositTx) GetChainID() *uint256.Int { + panic("deposits are not signed and do not have a chain-ID") +} + +func (tx DepositTx) GetNonce() uint64 { + return 0 +} + +func (tx DepositTx) GetTo() *libcommon.Address { + return tx.To +} + +func (tx DepositTx) GetBlobGas() uint64 { + return 0 +} + +func (tx DepositTx) GetBlobHashes() []libcommon.Hash { + return []libcommon.Hash{} +} + +func (tx DepositTx) GetGas() uint64 { + return tx.Gas +} + +func (tx DepositTx) GetValue() *uint256.Int { + return tx.Value +} + +func (tx DepositTx) GetData() []byte { + return tx.Data +} + +func (tx DepositTx) GetSender() (libcommon.Address, bool) { + return tx.From, true +} + +func (tx *DepositTx) SetSender(addr libcommon.Address) { + tx.From = addr +} + +func (tx DepositTx) RawSignatureValues() (*uint256.Int, *uint256.Int, *uint256.Int) { + panic("deposit tx does not have a signature") +} + +func (tx DepositTx) SigningHash(chainID *big.Int) libcommon.Hash { + panic("deposit tx does not have a signing hash") +} + +// NOTE: Need to check this +func (tx DepositTx) EncodingSize() int { + payloadSize, _, _, _ := tx.payloadSize() + envelopeSize := payloadSize + // Add envelope size and type size + if payloadSize >= 56 { + envelopeSize += libcommon.BitLenToByteLen(bits.Len(uint(payloadSize))) + } + envelopeSize += 2 + return envelopeSize +} + +// MarshalBinary returns the canonical encoding of the transaction. +func (tx DepositTx) MarshalBinary(w io.Writer) error { + payloadSize, nonceLen, gasLen, accessListLen := tx.payloadSize() + var b [33]byte + // encode TxType + b[0] = DepositTxType + if _, err := w.Write(b[:1]); err != nil { + return err + } + if err := tx.encodePayload(w, b[:], payloadSize, nonceLen, gasLen, accessListLen); err != nil { + return err + } + return nil +} + +func (tx DepositTx) payloadSize() (payloadSize int, nonceLen, gasLen, accessListLen int) { + // size of SourceHash + payloadSize += 33 + // size of From + payloadSize += 21 + // size of To + payloadSize++ + if tx.To != nil { + payloadSize += 20 + } + // size of Mint + payloadSize++ + payloadSize += rlp.Uint256LenExcludingHead(tx.Mint) + // size of Value + payloadSize++ + payloadSize += rlp.Uint256LenExcludingHead(tx.Value) + // size of Gas + payloadSize++ + gasLen = rlp.IntLenExcludingHead(tx.Gas) + payloadSize += gasLen + // size of IsSystemTransaction + payloadSize++ + // size of Data + payloadSize++ + switch len(tx.Data) { + case 0: + case 1: + if tx.Data[0] >= 128 { + payloadSize++ + } + default: + if len(tx.Data) >= 56 { + payloadSize += (bits.Len(uint(len(tx.Data))) + 7) / 8 + } + payloadSize += len(tx.Data) + } + return payloadSize, 0, gasLen, 0 +} + +func (tx DepositTx) encodePayload(w io.Writer, b []byte, payloadSize, nonceLen, gasLen, accessListLen int) error { + // prefix + if err := EncodeStructSizePrefix(payloadSize, w, b); err != nil { + return err + } + // encode SourceHash + b[0] = 128 + 32 + if _, err := w.Write(b[:1]); err != nil { + return nil + } + if _, err := w.Write(tx.SourceHash.Bytes()); err != nil { + return nil + } + // encode From + b[0] = 128 + 20 + if _, err := w.Write(b[:1]); err != nil { + return nil + } + if _, err := w.Write(tx.From.Bytes()); err != nil { + return nil + } + // encode To + if tx.To == nil { + b[0] = 128 + } else { + b[0] = 128 + 20 + } + if _, err := w.Write(b[:1]); err != nil { + return err + } + if tx.To != nil { + if _, err := w.Write(tx.To.Bytes()); err != nil { + return err + } + } + // encode Mint + if err := tx.Mint.EncodeRLP(w); err != nil { + return err + } + // encode Value + if err := tx.Value.EncodeRLP(w); err != nil { + return err + } + // encode Gas + if err := rlp.EncodeInt(tx.Gas, w, b); err != nil { + return err + } + // encode IsSystemTransaction + if tx.IsSystemTransaction { + b[0] = 0x01 + } else { + b[0] = 0x80 + } + if _, err := w.Write(b[:1]); err != nil { + return nil + } + // encode Data + if err := rlp.EncodeString(tx.Data, w, b); err != nil { + return err + } + return nil +} + +func (tx DepositTx) EncodeRLP(w io.Writer) error { + payloadSize, nonceLen, gasLen, accessListLen := tx.payloadSize() + envelopeSize := payloadSize + if payloadSize >= 56 { + envelopeSize += (bits.Len(uint(payloadSize)) + 7) / 8 + } + // size of struct prefix and TxType + envelopeSize += 2 + var b [33]byte + // envelope + if err := rlp.EncodeStringSizePrefix(envelopeSize, w, b[:]); err != nil { + return err + } + // encode TxType + b[0] = DepositTxType + if _, err := w.Write(b[:1]); err != nil { + return err + } + if err := tx.encodePayload(w, b[:], payloadSize, nonceLen, gasLen, accessListLen); err != nil { + return err + } + return nil +} + +func (tx *DepositTx) DecodeRLP(s *rlp.Stream) error { + _, err := s.List() + if err != nil { + return err + } + var b []byte + // SourceHash + if b, err = s.Bytes(); err != nil { + return err + } + if len(b) != 32 { + return fmt.Errorf("wrong size for Source hash: %d", len(b)) + } + copy(tx.SourceHash[:], b) + // From + if b, err = s.Bytes(); err != nil { + return err + } + if len(b) != 20 { + return fmt.Errorf("wrong size for From hash: %d", len(b)) + } + copy(tx.From[:], b) + // To (optional) + if b, err = s.Bytes(); err != nil { + return err + } + if len(b) > 0 && len(b) != 20 { + return fmt.Errorf("wrong size for To: %d", len(b)) + } + if len(b) > 0 { + tx.To = &libcommon.Address{} + copy((*tx.To)[:], b) + } + // Mint + if b, err = s.Uint256Bytes(); err != nil { + return err + } + tx.Mint = new(uint256.Int).SetBytes(b) + // Value + if b, err = s.Uint256Bytes(); err != nil { + return err + } + tx.Value = new(uint256.Int).SetBytes(b) + // Gas + if tx.Gas, err = s.Uint(); err != nil { + return err + } + if tx.IsSystemTransaction, err = s.Bool(); err != nil { + return err + } + // Data + if tx.Data, err = s.Bytes(); err != nil { + return err + } + return s.ListEnd() +} + +func (tx *DepositTx) FakeSign(address libcommon.Address) (Transaction, error) { + cpy := tx.copy() + cpy.SetSender(address) + return cpy, nil +} + +func (tx *DepositTx) WithSignature(signer Signer, sig []byte) (Transaction, error) { + return tx.copy(), nil +} + +func (tx DepositTx) Time() time.Time { + return tx.time // TODO(jky) this is dead code and we are in the process of removing the interface req upstream +} + +func (tx DepositTx) Type() byte { return DepositTxType } + +func (tx *DepositTx) Hash() libcommon.Hash { + if hash := tx.hash.Load(); hash != nil { + return *hash.(*libcommon.Hash) + } + hash := prefixedRlpHash(DepositTxType, []interface{}{ + tx.SourceHash, + tx.From, + tx.To, + tx.Mint, + tx.Value, + tx.Gas, + tx.IsSystemTransaction, + tx.Data, + }) + tx.hash.Store(&hash) + return hash +} + +// Protected implies that the tx signature has the chainID +// since there is no signature, this is always false +func (tx DepositTx) Protected() bool { + return false +} + +func (tx DepositTx) IsContractDeploy() bool { + return false +} + +func (tx DepositTx) IsStarkNet() bool { + return false +} + +// All zero in the prototype +func (tx DepositTx) GetPrice() *uint256.Int { return uint256.NewInt(0) } +func (tx DepositTx) GetTip() *uint256.Int { return uint256.NewInt(0) } +func (tx DepositTx) GetFeeCap() *uint256.Int { return uint256.NewInt(0) } + +// Is this needed at all? +func (tx DepositTx) GetEffectiveGasTip(baseFee *uint256.Int) *uint256.Int { + return uint256.NewInt(0) +} + +func (tx DepositTx) Cost() *uint256.Int { + return tx.Value.Clone() // TODO(jky) this is dead code and we are in the process of removing the interface req upstream +} + +func (tx DepositTx) GetAccessList() types2.AccessList { + return nil +} + +// NewDepositTransaction creates a deposit transaction +func NewDepositTransaction( + sourceHash libcommon.Hash, + from libcommon.Address, + to libcommon.Address, + mint *uint256.Int, + value *uint256.Int, + gasLimit uint64, + isSystemTx bool, + data []byte) *DepositTx { + return &DepositTx{ + SourceHash: sourceHash, + From: from, + To: &to, + Mint: mint, + Value: value, + Gas: gasLimit, + IsSystemTransaction: isSystemTx, + Data: data, + } +} + +// copy creates a deep copy of the transaction data and initializes all fields. +func (tx DepositTx) copy() *DepositTx { + cpy := &DepositTx{ + SourceHash: tx.SourceHash, + From: tx.From, + To: tx.To, + Mint: nil, + Value: new(uint256.Int), + Gas: tx.Gas, + IsSystemTransaction: tx.IsSystemTransaction, + Data: libcommon.CopyBytes(tx.Data), + } + if tx.Mint != nil { + cpy.Mint = new(uint256.Int).Set(tx.Mint) + } + if tx.Value != nil { + cpy.Value.Set(tx.Value) + } + return cpy +} + +// AsMessage returns the transaction as a core.Message. +func (tx DepositTx) AsMessage(s Signer, _ *big.Int, rules *chain.Rules) (Message, error) { + msg := Message{ + gasLimit: tx.Gas, + from: tx.From, + to: tx.To, + amount: *tx.Value, + data: tx.Data, + accessList: nil, + checkNonce: true, + isSystemTx: tx.IsSystemTransaction, + txType: tx.Type(), + mint: tx.Mint, + } + return msg, nil +} + +func (tx *DepositTx) Sender(signer Signer) (libcommon.Address, error) { + return tx.From, nil +} + +func (tx DepositTx) RollupCostData() types2.RollupCostData { + return types2.RollupCostData{} +} + +func (tx *DepositTx) Unwrap() Transaction { + return tx +}
diff --git ledgerwatch/erigon/core/types/transaction_marshalling.go bobanetwork/v3-erigon/core/types/transaction_marshalling.go index b529e51798875d297735c5c7c8b715c7185575fb..7d316d1825c62ec240386be4ff92dabafc14e309 100644 --- ledgerwatch/erigon/core/types/transaction_marshalling.go +++ bobanetwork/v3-erigon/core/types/transaction_marshalling.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/ledgerwatch/erigon-lib/common/hexutil"   "github.com/holiman/uint256" @@ -30,6 +31,12 @@ V *hexutil.Big `json:"v"` R *hexutil.Big `json:"r"` S *hexutil.Big `json:"s"` To *libcommon.Address `json:"to"` + + // Deposit transaction fields + SourceHash *libcommon.Hash `json:"sourceHash,omitempty"` + From *libcommon.Address `json:"from,omitempty"` + Mint *hexutil.Big `json:"mint,omitempty"` + IsSystemTx *bool `json:"isSystemTx,omitempty"`   // Access list transaction fields: ChainID *hexutil.Big `json:"chainId,omitempty"` @@ -106,6 +113,26 @@ enc.S = (*hexutil.Big)(tx.S.ToBig()) return json.Marshal(&enc) }   +func (tx DepositTx) MarshalJSON() ([]byte, error) { + var enc txJSON + // These are set for all tx types. + enc.Hash = tx.Hash() + enc.Type = hexutil.Uint64(tx.Type()) + enc.ChainID = (*hexutil.Big)(libcommon.Big0) + enc.Gas = (*hexutil.Uint64)(&tx.Gas) + enc.Value = (*hexutil.Big)(tx.Value.ToBig()) + enc.Data = (*hexutility.Bytes)(&tx.Data) + enc.To = tx.To + enc.SourceHash = &tx.SourceHash + enc.From = &tx.From + if tx.Mint != nil { + enc.Mint = (*hexutil.Big)(tx.Mint.ToBig()) + } + enc.IsSystemTx = &tx.IsSystemTransaction + // other fields will show up as null. + return json.Marshal(&enc) +} + func toBlobTxJSON(tx *BlobTx) *txJSON { var enc txJSON // These are set for all tx types. @@ -171,6 +198,12 @@ } return tx, nil case DynamicFeeTxType: tx := &DynamicFeeTransaction{} + if err = tx.UnmarshalJSON(input); err != nil { + return nil, err + } + return tx, nil + case DepositTxType: + tx := &DepositTx{} if err = tx.UnmarshalJSON(input); err != nil { return nil, err } @@ -410,6 +443,59 @@ if err := sanityCheckSignature(&tx.V, &tx.R, &tx.S, false); err != nil { return err } } + return nil +} + +func (tx *DepositTx) UnmarshalJSON(input []byte) error { + var dec txJSON + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.AccessList != nil || dec.FeeCap != nil || dec.Tip != nil { + return errors.New("unexpected field(s) in deposit transaction") + } + if dec.GasPrice != nil && dec.GasPrice.ToInt().Cmp(libcommon.Big0) != 0 { + return errors.New("deposit transaction GasPrice must be 0") + } + if (dec.V != nil && dec.V.ToInt().Cmp(libcommon.Big0) != 0) || + (dec.R != nil && dec.R.ToInt().Cmp(libcommon.Big0) != 0) || + (dec.S != nil && dec.S.ToInt().Cmp(libcommon.Big0) != 0) { + return errors.New("deposit transaction signature must be 0 or unset") + } + if dec.To != nil { + tx.To = dec.To + } + tx.Gas = uint64(*dec.Gas) + if dec.Value == nil { + return errors.New("missing required field 'value' in transaction") + } + var overflow bool + tx.Value, overflow = uint256.FromBig(dec.Value.ToInt()) + if overflow { + return errors.New("'value' in transaction does not fit in 256 bits") + } + // mint may be omitted or nil if there is nothing to mint. + tx.Mint, overflow = uint256.FromBig(dec.Mint.ToInt()) + if overflow { + return errors.New("'mint' in transaction does not fit in 256 bits") + } + if dec.Data == nil { + return errors.New("missing required field 'input' in transaction") + } + tx.Data = *dec.Data + if dec.From == nil { + return errors.New("missing required field 'from' in transaction") + } + tx.From = *dec.From + if dec.SourceHash == nil { + return errors.New("missing required field 'sourceHash' in transaction") + } + tx.SourceHash = *dec.SourceHash + // IsSystemTx may be omitted. Defaults to false. + if dec.IsSystemTx != nil { + tx.IsSystemTransaction = *dec.IsSystemTx + } + // nonce is not checked becaues depositTx has no nonce field. return nil }
diff --git ledgerwatch/erigon/core/types/transaction_signing.go bobanetwork/v3-erigon/core/types/transaction_signing.go index 19695c6c93dd2c9cca884d81ede5c5c856e2440b..6e82843adab852de5ad4fde354cd1a50658781c7 100644 --- ledgerwatch/erigon/core/types/transaction_signing.go +++ bobanetwork/v3-erigon/core/types/transaction_signing.go @@ -45,7 +45,7 @@ } } signer.unprotected = true switch { - case config.IsCancun(blockTime): + case config.IsCancun(blockTime) && !config.IsOptimism(): // All transaction types are still supported signer.protected = true signer.accessList = true @@ -100,7 +100,7 @@ } signer.chainID.Set(chainId) signer.chainIDMul.Mul(chainId, u256.Num2) if config.ChainID != nil { - if config.CancunTime != nil { + if config.CancunTime != nil && !config.IsOptimism() { signer.blob = true } if config.LondonBlock != nil { @@ -205,6 +205,8 @@ var R, S *uint256.Int signChainID := sg.chainID.ToBig() // This is reset to nil if tx is unprotected // recoverPlain below will subract 27 from V switch t := tx.(type) { + case *DepositTx: + return t.From, nil case *LegacyTx: if !t.Protected() { if !sg.unprotected { @@ -300,6 +302,8 @@ if t.ChainID != nil && !t.ChainID.IsZero() && !t.ChainID.Eq(&sg.chainID) { return nil, nil, nil, ErrInvalidChainId } R, S, V = decodeSignature(sig) + case *DepositTx: + return nil, nil, nil, fmt.Errorf("deposits do not have a signature") case *BlobTx: // Check that chain ID of tx matches the signer. We also accept ID zero here, // because it indicates that the chain ID was not specified in the tx.
diff --git ledgerwatch/erigon/erigon-lib/types/txn.go bobanetwork/v3-erigon/erigon-lib/types/txn.go index d7f96d781465063f8d99e902b06c346bcec00231..6c6b11ede1e8804aaffa16eed7e58bfcd757dfde 100644 --- ledgerwatch/erigon/erigon-lib/types/txn.go +++ bobanetwork/v3-erigon/erigon-lib/types/txn.go @@ -38,6 +38,7 @@ "github.com/ledgerwatch/erigon-lib/common/u256" "github.com/ledgerwatch/erigon-lib/crypto" "github.com/ledgerwatch/erigon-lib/gointerfaces/types" "github.com/ledgerwatch/erigon-lib/rlp" + "github.com/ledgerwatch/log/v3" )   type TxParseConfig struct { @@ -108,6 +109,8 @@ BlobHashes []common.Hash Blobs [][]byte Commitments []gokzg4844.KZGCommitment Proofs []gokzg4844.KZGProof + + RollupCostData RollupCostData }   const ( @@ -115,6 +118,7 @@ LegacyTxType byte = 0 AccessListTxType byte = 1 // EIP-2930 DynamicFeeTxType byte = 2 // EIP-1559 BlobTxType byte = 3 // EIP-4844 + DepositTxType byte = 0x7e )   var ErrParseTxn = fmt.Errorf("%w transaction", rlp.ErrParse) @@ -122,6 +126,7 @@ var ErrRejected = errors.New("rejected") var ErrAlreadyKnown = errors.New("already known") var ErrRlpTooBig = errors.New("txn rlp too big") +var ErrTxTypeNotSupported = errors.New("transaction type not supported")   // Set the RLP validate function func (ctx *TxParseContext) ValidateRLP(f func(txnRlp []byte) error) { ctx.validateRlp = f } @@ -184,7 +189,7 @@ // If it is non-legacy transaction, the transaction type follows, and then the the list if !legacy { slot.Type = payload[p] - if slot.Type > BlobTxType { + if slot.Type > BlobTxType && slot.Type != DepositTxType { return 0, fmt.Errorf("%w: unknown transaction type: %d", ErrParseTxn, slot.Type) } p++ @@ -298,8 +303,10 @@ // Compute transaction hash ctx.Keccak1.Reset() ctx.Keccak2.Reset() + var txType byte if !legacy { typeByte := []byte{slot.Type} + txType = typeByte[0] if _, err = ctx.Keccak1.Write(typeByte); err != nil { return 0, fmt.Errorf("%w: computing IdHash (hashing type Prefix): %s", ErrParseTxn, err) //nolint } @@ -323,9 +330,84 @@ return p, err } }   + if slot.Type == DepositTxType { + // SourchHash + p, _, err = rlp.SkipString(payload, p) + if err != nil { + return 0, fmt.Errorf("%w: depostTx sourchHash: %s", ErrParseTxn, err) //nolint + } + // From + dataPos, dataLen, err := rlp.String(payload, p) + if err != nil { + return 0, fmt.Errorf("%w: depostTx from: %s", ErrParseTxn, err) //nolint + } + if ctx.withSender { + copy(sender, payload[dataPos:dataPos+dataLen]) + } + p = dataPos + dataLen + // To + p, dataLen, err = rlp.SkipString(payload, p) + if err != nil { + return 0, fmt.Errorf("%w: depostTx to: %s", ErrParseTxn, err) //nolint + } + slot.Creation = dataLen == 0 + // Mint + p, _, err = rlp.SkipString(payload, p) + if err != nil { + return 0, fmt.Errorf("%w: depostTx mint: %s", ErrParseTxn, err) //nolint + } + // Value + p, err = rlp.U256(payload, p, &slot.Value) + if err != nil { + return 0, fmt.Errorf("%w: depostTx value: %s", ErrParseTxn, err) //nolint + } + // Gas + p, slot.Gas, err = rlp.U64(payload, p) + if err != nil { + return 0, fmt.Errorf("%w: depositTx gas: %s", ErrParseTxn, err) //nolint + } + // Data + dataPos, dataLen, err = rlp.String(payload, p) + if err != nil { + return 0, fmt.Errorf("%w: depositTx data len: %s", ErrParseTxn, err) //nolint + } + slot.DataLen = dataLen + + // Zero and non-zero bytes are priced differently + slot.DataNonZeroLen = 0 + for _, byt := range payload[dataPos : dataPos+dataLen] { + if byt != 0 { + slot.DataNonZeroLen++ + } + } + { + // full tx contents count towards rollup data gas, not just tx data + var zeroes, ones uint64 + for _, byt := range payload { + if byt == 0 { + zeroes++ + } else { + ones++ + } + } + slot.RollupCostData = RollupCostData{Zeroes: zeroes, Ones: ones} + } + p = dataPos + dataLen + + // Set IDHash to slot + _, _ = ctx.Keccak1.(io.Reader).Read(slot.IDHash[:32]) + if validateHash != nil { + if err := validateHash(slot.IDHash[:32]); err != nil { + return p, err + } + } + return p, nil + } + // Remember where signing hash data begins (it will need to be wrapped in an RLP list) sigHashPos := p - if !legacy { + + if !legacy && txType != DepositTxType { p, err = rlp.U256(payload, p, &ctx.ChainID) if err != nil { return 0, fmt.Errorf("%w: chainId len: %s", ErrParseTxn, err) //nolint @@ -340,47 +422,87 @@ if !ctx.ChainID.Eq(&ctx.cfg.ChainID) { return 0, fmt.Errorf("%w: %s, %d (expected %d)", ErrParseTxn, "invalid chainID", ctx.ChainID.Uint64(), ctx.cfg.ChainID.Uint64()) } } - // Next follows the nonce, which we need to parse - p, slot.Nonce, err = rlp.U64(payload, p) - if err != nil { - return 0, fmt.Errorf("%w: nonce: %s", ErrParseTxn, err) //nolint - } - // Next follows gas price or tip - p, err = rlp.U256(payload, p, &slot.Tip) - if err != nil { - return 0, fmt.Errorf("%w: tip: %s", ErrParseTxn, err) //nolint - } - // Next follows feeCap, but only for dynamic fee transactions, for legacy transaction, it is - // equal to tip - if slot.Type < DynamicFeeTxType { - slot.FeeCap = slot.Tip + var dataPos, dataLen int + if txType == DepositTxType { + slot.FeeCap = uint256.Int{} + + dataPos, dataLen, err = rlp.String(payload, p) // SourceHash + if err != nil { + log.Warn("failed to parse source hash", "err", err) + } + p = dataPos + dataLen + dataPos, dataLen, err = rlp.String(payload, p) // From + if err != nil { + log.Warn("failed to parse from", "err", err) + } + p = dataPos + dataLen + dataPos, dataLen, err = rlp.String(payload, p) // To + if err != nil { + log.Warn("failed to parse to", "err", err) + } + p = dataPos + dataLen + dataPos, dataLen, err = rlp.String(payload, p) // Mint + if err != nil { + log.Warn("failed to parse mint", "err", err) + } + p = dataPos + dataLen + dataPos, dataLen, err = rlp.String(payload, p) // Value + if err != nil { + log.Warn("failed to parse value", "err", err) + } + p = dataPos + dataLen + + p, slot.Gas, err = rlp.U64(payload, p) + if err != nil { + return 0, fmt.Errorf("%w: d_gas: %s", ErrParseTxn, err) //nolint + } + + p += 1 // SystemTx } else { - p, err = rlp.U256(payload, p, &slot.FeeCap) + // Next follows the nonce, which we need to parse + p, slot.Nonce, err = rlp.U64(payload, p) + + if err != nil { + return 0, fmt.Errorf("%w: nonce: %s", ErrParseTxn, err) //nolint + } + // Next follows gas price or tip + // Although consensus rules specify that tip can be up to 256 bit long, we narrow it to 64 bit + p, err = rlp.U256(payload, p, &slot.Tip) + if err != nil { + return 0, fmt.Errorf("%w: tip: %s", ErrParseTxn, err) //nolint + } + // Next follows feeCap, but only for dynamic fee transactions, for legacy transaction, it is + // equal to tip + if slot.Type < DynamicFeeTxType { + slot.FeeCap = slot.Tip + } else { + // Although consensus rules specify that feeCap can be up to 256 bit long, we narrow it to 64 bit + p, err = rlp.U256(payload, p, &slot.FeeCap) + if err != nil { + return 0, fmt.Errorf("%w: feeCap: %s", ErrParseTxn, err) //nolint + } + } + // Next follows gas + p, slot.Gas, err = rlp.U64(payload, p) + if err != nil { + return 0, fmt.Errorf("%w: gas: %s", ErrParseTxn, err) //nolint + } + // Next follows the destination address (if present) + dataPos, dataLen, err = rlp.String(payload, p) if err != nil { - return 0, fmt.Errorf("%w: feeCap: %s", ErrParseTxn, err) //nolint + return 0, fmt.Errorf("%w: to len: %s", ErrParseTxn, err) //nolint } - } - // Next follows gas - p, slot.Gas, err = rlp.U64(payload, p) - if err != nil { - return 0, fmt.Errorf("%w: gas: %s", ErrParseTxn, err) //nolint - } - // Next follows the destination address (if present) - dataPos, dataLen, err := rlp.String(payload, p) - if err != nil { - return 0, fmt.Errorf("%w: to len: %s", ErrParseTxn, err) //nolint - } - if dataLen != 0 && dataLen != 20 { - return 0, fmt.Errorf("%w: unexpected length of to field: %d", ErrParseTxn, dataLen) - } - - // Only note if To field is empty or not - slot.Creation = dataLen == 0 - p = dataPos + dataLen - // Next follows value - p, err = rlp.U256(payload, p, &slot.Value) - if err != nil { - return 0, fmt.Errorf("%w: value: %s", ErrParseTxn, err) //nolint + if dataLen != 0 && dataLen != 20 { + return 0, fmt.Errorf("%w: unexpected length of to field: %d", ErrParseTxn, dataLen) + } + // Only note if To field is empty or not + slot.Creation = dataLen == 0 + p = dataPos + dataLen + // Next follows value + p, err = rlp.U256(payload, p, &slot.Value) + if err != nil { + return 0, fmt.Errorf("%w: value: %s", ErrParseTxn, err) //nolint + } } // Next goes data, but we are only interesting in its length dataPos, dataLen, err = rlp.String(payload, p) @@ -397,7 +519,24 @@ slot.DataNonZeroLen++ } }   + { + // full tx contents count towards rollup data gas, not just tx data + var zeroes, ones uint64 + for _, byt := range payload { + if byt == 0 { + zeroes++ + } else { + ones++ + } + } + slot.RollupCostData = RollupCostData{Zeroes: zeroes, Ones: ones} + } + p = dataPos + dataLen + + if txType == DepositTxType { + return p, nil + }   // Next follows access list for non-legacy transactions, we are only interesting in number of addresses and storage keys if !legacy { @@ -984,3 +1123,11 @@ sum += len(tuple.StorageKeys) } return sum } + +// RollupCostData is a transaction structure that caches data for quickly computing the data +// availablility costs for the transaction. +type RollupCostData struct { + Zeroes, Ones uint64 +} + +type L1CostFn func(tx *TxSlot) *uint256.Int
diff --git ledgerwatch/erigon/turbo/adapter/ethapi/api_test.go bobanetwork/v3-erigon/turbo/adapter/ethapi/api_test.go new file mode 100644 index 0000000000000000000000000000000000000000..918cbe4acb5450ce3de62afe93c781d9fa99c778 --- /dev/null +++ bobanetwork/v3-erigon/turbo/adapter/ethapi/api_test.go @@ -0,0 +1,175 @@ +package ethapi + +import ( + "encoding/json" + "math/big" + "testing" + + "github.com/holiman/uint256" + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutil" + "github.com/ledgerwatch/erigon/core/types" + "github.com/stretchr/testify/require" +) + +func TestNewRPCTransactionDepositTx(t *testing.T) { + tx := &types.DepositTx{ + SourceHash: libcommon.Hash{1}, + From: libcommon.Address{1}, + IsSystemTransaction: true, + Mint: uint256.NewInt(34), + Value: uint256.NewInt(1337), + } + nonce := uint64(7) + depositNonce := &nonce + receipt := &types.Receipt{DepositNonce: depositNonce} + got := newRPCTransaction(tx, libcommon.Hash{}, uint64(12), uint64(1), big.NewInt(0), receipt) + // Should provide zero values for unused fields that are required in other transactions + require.Equal(t, got.GasPrice, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().GasPrice = %v, want 0x0", got.GasPrice) + require.Equal(t, got.V, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().V = %v, want 0x0", got.V) + require.Equal(t, got.R, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().R = %v, want 0x0", got.R) + require.Equal(t, got.S, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().S = %v, want 0x0", got.S) + + // Should include deposit tx specific fields + require.Equal(t, *got.SourceHash, tx.SourceHash, "newRPCTransaction().SourceHash = %v, want %v", got.SourceHash, tx.SourceHash) + require.Equal(t, *got.IsSystemTx, tx.IsSystemTransaction, "newRPCTransaction().IsSystemTransaction = %v, want %v", got.IsSystemTx, tx.IsSystemTransaction) + require.Equal(t, got.Mint, (*hexutil.Big)(tx.Mint.ToBig()), "newRPCTransaction().Mint = %v, want %v", got.Mint, tx.Mint.ToBig()) + require.Equal(t, got.Nonce, (hexutil.Uint64)(nonce), "newRPCTransaction().Nonce = %v, want %v", got.Nonce, nonce) +} + +func TestNewRPCTransactionDepositTxWithVersion(t *testing.T) { + tx := &types.DepositTx{ + SourceHash: libcommon.HexToHash("0x1234"), + IsSystemTransaction: true, + Mint: uint256.NewInt(34), + Value: uint256.NewInt(1337), + } + nonce := uint64(7) + version := types.CanyonDepositReceiptVersion + receipt := &types.Receipt{ + DepositNonce: &nonce, + DepositReceiptVersion: &version, + } + got := newRPCTransaction(tx, libcommon.Hash{}, uint64(12), uint64(1), big.NewInt(0), receipt) + // Should provide zero values for unused fields that are required in other transactions + require.Equal(t, got.GasPrice, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().GasPrice = %v, want 0x0", got.GasPrice) + require.Equal(t, got.V, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().V = %v, want 0x0", got.V) + require.Equal(t, got.R, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().R = %v, want 0x0", got.R) + require.Equal(t, got.S, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().S = %v, want 0x0", got.S) + + // Should include versioned deposit tx specific fields + require.Equal(t, *got.SourceHash, tx.SourceHash, "newRPCTransaction().SourceHash = %v, want %v", got.SourceHash, tx.SourceHash) + require.Equal(t, *got.IsSystemTx, tx.IsSystemTransaction, "newRPCTransaction().IsSystemTx = %v, want %v", got.IsSystemTx, tx.IsSystemTransaction) + require.Equal(t, got.Mint, (*hexutil.Big)(tx.Mint.ToBig()), "newRPCTransaction().Mint = %v, want %v", got.Mint, tx.Mint.ToBig()) + require.Equal(t, got.Nonce, (hexutil.Uint64)(nonce), "newRPCTransaction().Nonce = %v, want %v", got.Nonce, nonce) + require.Equal(t, *got.DepositReceiptVersion, (hexutil.Uint64(version)), "newRPCTransaction().DepositReceiptVersion = %v, want %v", *got.DepositReceiptVersion, version) + + // Make sure json marshal/unmarshal of the rpc tx preserves the receipt version + b, err := json.Marshal(got) + require.NoError(t, err, "marshalling failed: %w", err) + parsed := make(map[string]interface{}) + err = json.Unmarshal(b, &parsed) + require.NoError(t, err, "unmarshalling failed: %w", err) + require.Equal(t, "0x1", parsed["depositReceiptVersion"]) +} + +func TestNewRPCTransactionOmitIsSystemTxFalse(t *testing.T) { + tx := &types.DepositTx{ + IsSystemTransaction: false, + Value: uint256.NewInt(1337), + } + got := newRPCTransaction(tx, libcommon.Hash{}, uint64(12), uint64(1), big.NewInt(0), nil) + + require.Nil(t, got.IsSystemTx, "should omit IsSystemTx when false") +} + +func TestUnmarshalRpcDepositTx(t *testing.T) { + version := hexutil.Uint64(types.CanyonDepositReceiptVersion) + tests := []struct { + name string + modifier func(tx *RPCTransaction) + valid bool + }{ + { + name: "Unmodified", + modifier: func(tx *RPCTransaction) {}, + valid: true, + }, + { + name: "Zero Values", + modifier: func(tx *RPCTransaction) { + tx.V = (*hexutil.Big)(libcommon.Big0) + tx.R = (*hexutil.Big)(libcommon.Big0) + tx.S = (*hexutil.Big)(libcommon.Big0) + tx.GasPrice = (*hexutil.Big)(libcommon.Big0) + }, + valid: true, + }, + { + name: "Nil Values", + modifier: func(tx *RPCTransaction) { + tx.V = nil + tx.R = nil + tx.S = nil + tx.GasPrice = nil + }, + valid: true, + }, + { + name: "Non-Zero GasPrice", + modifier: func(tx *RPCTransaction) { + tx.GasPrice = (*hexutil.Big)(big.NewInt(43)) + }, + valid: false, + }, + { + name: "Non-Zero V", + modifier: func(tx *RPCTransaction) { + tx.V = (*hexutil.Big)(big.NewInt(43)) + }, + valid: false, + }, + { + name: "Non-Zero R", + modifier: func(tx *RPCTransaction) { + tx.R = (*hexutil.Big)(big.NewInt(43)) + }, + valid: false, + }, + { + name: "Non-Zero S", + modifier: func(tx *RPCTransaction) { + tx.S = (*hexutil.Big)(big.NewInt(43)) + }, + valid: false, + }, + { + name: "Non-nil deposit receipt version", + modifier: func(tx *RPCTransaction) { + tx.DepositReceiptVersion = &version + }, + valid: true, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + tx := &types.DepositTx{ + SourceHash: libcommon.HexToHash("0x1234"), + IsSystemTransaction: true, + Mint: uint256.NewInt(34), + Value: uint256.NewInt(1337), + } + rpcTx := newRPCTransaction(tx, libcommon.Hash{}, uint64(12), uint64(1), big.NewInt(0), nil) + test.modifier(rpcTx) + json, err := json.Marshal(rpcTx) + require.NoError(t, err, "marshalling failed: %w", err) + parsed := &types.DepositTx{} + err = parsed.UnmarshalJSON(json) + if test.valid { + require.NoError(t, err, "unmarshal failed: %w", err) + } else { + require.Error(t, err, "unmarshal should have failed but did not") + } + }) + } +}

The Transaction type now exposes the deposit-transaction and L1-cost properties required for the rollup.

diff --git ledgerwatch/erigon/core/types/access_list_tx.go bobanetwork/v3-erigon/core/types/access_list_tx.go index 0f6131ea91e5d8092b5ea1803810e46c460f7094..f4410bd566c7e1c423413d9e4cdd082ec2e5ed0e 100644 --- ledgerwatch/erigon/core/types/access_list_tx.go +++ bobanetwork/v3-erigon/core/types/access_list_tx.go @@ -429,6 +429,7 @@ amount: *tx.Value, data: tx.Data, accessList: tx.AccessList, checkNonce: true, + l1CostGas: tx.RollupCostData(), }   if !rules.IsBerlin { @@ -517,3 +518,7 @@ } tx.from.Store(addr) return addr, nil } + +func (tx *AccessListTx) RollupCostData() types2.RollupCostData { + return tx.computeRollupGas(tx) +}
diff --git ledgerwatch/erigon/core/types/dynamic_fee_tx.go bobanetwork/v3-erigon/core/types/dynamic_fee_tx.go index 5ee0cf037d9f95d8d4cd863cd9565c063fef9c92..f06b941010b0c393abba86200b35baaf371a8038 100644 --- ledgerwatch/erigon/core/types/dynamic_fee_tx.go +++ bobanetwork/v3-erigon/core/types/dynamic_fee_tx.go @@ -367,6 +367,7 @@ amount: *tx.Value, data: tx.Data, accessList: tx.AccessList, checkNonce: true, + l1CostGas: tx.RollupCostData(), } if !rules.IsLondon { return msg, errors.New("eip-1559 transactions require London") @@ -462,3 +463,7 @@ Tip: gasTip, FeeCap: gasFeeCap, } } + +func (tx *DynamicFeeTransaction) RollupCostData() types2.RollupCostData { + return tx.computeRollupGas(tx) +}
diff --git ledgerwatch/erigon/core/types/legacy_tx.go bobanetwork/v3-erigon/core/types/legacy_tx.go index 7e183d6b6309a1c7792de2a5c45e3566969bc1e5..40965206a2f6e2ca8f97543d6283560f2f89785b 100644 --- ledgerwatch/erigon/core/types/legacy_tx.go +++ bobanetwork/v3-erigon/core/types/legacy_tx.go @@ -349,7 +349,7 @@ return nil }   // AsMessage returns the transaction as a core.Message. -func (tx LegacyTx) AsMessage(s Signer, _ *big.Int, _ *chain.Rules) (Message, error) { +func (tx LegacyTx) AsMessage(s Signer, _ *big.Int, rules *chain.Rules) (Message, error) { msg := Message{ nonce: tx.Nonce, gasLimit: tx.Gas, @@ -361,6 +361,7 @@ amount: *tx.Value, data: tx.Data, accessList: nil, checkNonce: true, + l1CostGas: tx.RollupCostData(), }   var err error @@ -450,3 +451,9 @@ } tx.from.Store(addr) return addr, nil } + +func (tx *LegacyTx) IsDepositTx() bool { return false } + +func (tx *LegacyTx) RollupCostData() types2.RollupCostData { + return tx.computeRollupGas(tx) +}

Transactions must pay an additional L1 cost based on the amount of rollup-data-gas they consume, estimated based on gas-price-oracle information and encoded tx size.

diff --git ledgerwatch/erigon/core/types/transaction.go bobanetwork/v3-erigon/core/types/transaction.go index 079b008791dbafbd86b0fb20d2f5d42f72c0e2e5..f8648a8d44e0a478b6fb641ea88626f8922d65c1 100644 --- ledgerwatch/erigon/core/types/transaction.go +++ bobanetwork/v3-erigon/core/types/transaction.go @@ -53,6 +53,7 @@ LegacyTxType = iota AccessListTxType DynamicFeeTxType BlobTxType + DepositTxType = 0x7e )   // Transaction is an Ethereum transaction. @@ -94,7 +95,8 @@ Sender(Signer) (libcommon.Address, error) GetSender() (libcommon.Address, bool) SetSender(libcommon.Address) IsContractDeploy() bool - Unwrap() Transaction // If this is a network wrapper, returns the unwrapped tx. Otherwise returns itself. + RollupCostData() types2.RollupCostData + Unwrap() Transaction // If this is a network wrapper, returns the unwrapped tx. Otherwiwes returns itself. }   // TransactionMisc is collection of miscelaneous fields for transaction that is supposed to be embedded into concrete @@ -105,6 +107,46 @@ // caches hash atomic.Value //nolint:structcheck from atomic.Value + + // cache how much gas the tx takes on L1 for its share of rollup data + rollupGas atomic.Value +} + +type rollupGasCounter struct { + zeroes uint64 + ones uint64 +} + +func (r *rollupGasCounter) Write(p []byte) (int, error) { + for _, byt := range p { + if byt == 0 { + r.zeroes++ + } else { + r.ones++ + } + } + return len(p), nil +} + +// computeRollupGas is a helper method to compute and cache the rollup gas cost for any tx type +func (tm *TransactionMisc) computeRollupGas(tx interface { + MarshalBinary(w io.Writer) error + Type() byte +}) types2.RollupCostData { + if tx.Type() == DepositTxType { + return types2.RollupCostData{} + } + if v := tm.rollupGas.Load(); v != nil { + return v.(types2.RollupCostData) + } + var c rollupGasCounter + err := tx.MarshalBinary(&c) + if err != nil { // Silent error, invalid txs will not be marshalled/unmarshalled for batch submission anyway. + log.Error("failed to encode tx for L1 cost computation", "err", err) + } + total := types2.RollupCostData{Zeroes: c.zeroes, Ones: c.ones} + tm.rollupGas.Store(total) + return total }   // RLP-marshalled legacy transactions and binary-marshalled (not wrapped into an RLP string) typed (EIP-2718) transactions @@ -195,6 +237,13 @@ return t, nil case DynamicFeeTxType: s := rlp.NewStream(bytes.NewReader(data[1:]), uint64(len(data)-1)) t := &DynamicFeeTransaction{} + if err := t.DecodeRLP(s); err != nil { + return nil, err + } + return t, nil + case DepositTxType: + s := rlp.NewStream(bytes.NewReader(data[1:]), uint64(len(data)-1)) + t := &DepositTx{} if err := t.DecodeRLP(s); err != nil { return nil, err } @@ -513,6 +562,7 @@ }   // Message is a fully derived transaction and implements core.Message type Message struct { + txType byte to *libcommon.Address from libcommon.Address nonce uint64 @@ -527,6 +577,10 @@ accessList types2.AccessList checkNonce bool isFree bool blobHashes []libcommon.Hash + + isSystemTx bool + mint *uint256.Int + l1CostGas types2.RollupCostData }   func NewMessage(from libcommon.Address, to *libcommon.Address, nonce uint64, amount *uint256.Int, gasLimit uint64, @@ -593,6 +647,11 @@ }   m.gasLimit = gas } + +func (m Message) IsSystemTx() bool { return m.isSystemTx } +func (m Message) IsDepositTx() bool { return m.txType == DepositTxType } +func (m Message) Mint() *uint256.Int { return m.mint } +func (m Message) RollupCostData() types2.RollupCostData { return m.l1CostGas }   func (m Message) BlobGas() uint64 { return fixedgas.BlobGasPerBlob * uint64(len(m.blobHashes)) }
diff --git ledgerwatch/erigon/core/vm/evmtypes/evmtypes.go bobanetwork/v3-erigon/core/vm/evmtypes/evmtypes.go index 4b919f6b3e369e38f3e891580cee94243e642359..8856e06b368741dac613d3a727ffae8db0772ab4 100644 --- ledgerwatch/erigon/core/vm/evmtypes/evmtypes.go +++ bobanetwork/v3-erigon/core/vm/evmtypes/evmtypes.go @@ -7,6 +7,7 @@ "github.com/holiman/uint256"   "github.com/ledgerwatch/erigon-lib/chain" "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/opstack" types2 "github.com/ledgerwatch/erigon-lib/types"   "github.com/ledgerwatch/erigon/core/types" @@ -33,6 +34,9 @@ Difficulty *big.Int // Provides information for DIFFICULTY BaseFee *uint256.Int // Provides information for BASEFEE PrevRanDao *common.Hash // Provides information for PREVRANDAO ExcessBlobGas *uint64 // Provides information for handling data blobs + + // L1CostFunc returns the L1 cost of the rollup message, the function may be nil, or return nil + L1CostFunc opstack.L1CostFunc }   // TxContext provides the EVM with information about a transaction.
diff --git ledgerwatch/erigon/turbo/jsonrpc/trace_adhoc.go bobanetwork/v3-erigon/turbo/jsonrpc/trace_adhoc.go index 472b0db1e826e0d60d9da2610a3dd5ca215d8bb4..256cac7892afc131b2e2a9ec1a6e2b4213209039 100644 --- ledgerwatch/erigon/turbo/jsonrpc/trace_adhoc.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/trace_adhoc.go @@ -5,7 +5,6 @@ "bytes" "context" "encoding/json" "fmt" - "github.com/ledgerwatch/erigon-lib/common/hexutil" "math" "strings"   @@ -13,8 +12,10 @@ "github.com/holiman/uint256" "github.com/ledgerwatch/log/v3"   libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutil" "github.com/ledgerwatch/erigon-lib/common/hexutility" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/opstack" types2 "github.com/ledgerwatch/erigon-lib/types"   math2 "github.com/ledgerwatch/erigon/common/math" @@ -967,6 +968,7 @@ txCtx := core.NewEVMTxContext(msg)   blockCtx.GasLimit = math.MaxUint64 blockCtx.MaxGasLimit = true + blockCtx.L1CostFunc = opstack.NewL1CostFunc(chainConfig, ibs)   evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vm.Config{Debug: traceTypeTrace, Tracer: &ot})   @@ -1147,6 +1149,7 @@ header = parentHeader useParent = true }   + l1CostFunc := opstack.NewL1CostFunc(chainConfig, ibs) for txIndex, msg := range msgs { if err := libcommon.Stopped(ctx.Done()); err != nil { return nil, nil, err @@ -1191,6 +1194,7 @@ blockCtx.GasLimit = math.MaxUint64 blockCtx.MaxGasLimit = true } ibs.Reset() + blockCtx.L1CostFunc = l1CostFunc // Create initial IntraBlockState, we will compare it with ibs (IntraBlockState after the transaction)   evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vmConfig)
diff --git ledgerwatch/erigon/turbo/jsonrpc/trace_filtering.go bobanetwork/v3-erigon/turbo/jsonrpc/trace_filtering.go index 795eb31b16ff8cbb2c3db28d86b68e3eb442e3f2..8504e04e3c745376b2d208235ccc46541f953fc0 100644 --- ledgerwatch/erigon/turbo/jsonrpc/trace_filtering.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/trace_filtering.go @@ -4,7 +4,9 @@ import ( "context" "errors" "fmt" + "github.com/ledgerwatch/erigon-lib/common/hexutil" + "github.com/ledgerwatch/erigon-lib/opstack"   "github.com/RoaringBitmap/roaring/roaring64" jsoniter "github.com/json-iterator/go" @@ -766,6 +768,7 @@ ibs := state.New(cachedReader)   blockCtx := transactions.NewEVMBlockContext(engine, lastHeader, true /* requireCanonical */, dbtx, api._blockReader) txCtx := core.NewEVMTxContext(msg) + blockCtx.L1CostFunc = opstack.NewL1CostFunc(chainConfig, ibs) evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vmConfig)   gp := new(core.GasPool).AddGas(msg.Gas()).AddBlobGas(msg.BlobGas())
diff --git ledgerwatch/erigon/turbo/jsonrpc/tracing.go bobanetwork/v3-erigon/turbo/jsonrpc/tracing.go index bdf129af64cc05f59f13186715f1645cb5de751d..860ce9d5e0a6e838ff5dc0ab233311803e071aad 100644 --- ledgerwatch/erigon/turbo/jsonrpc/tracing.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/tracing.go @@ -2,6 +2,8 @@ package jsonrpc   import ( "context" + "encoding/json" + "errors" "fmt" "math/big" "time" @@ -9,6 +11,7 @@ "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/hexutil" + "github.com/ledgerwatch/erigon-lib/opstack" "github.com/ledgerwatch/erigon/common/math" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" @@ -68,6 +71,30 @@ if numberOk { return fmt.Errorf("invalid arguments; block with number %d not found", number) } return fmt.Errorf("invalid arguments; block with hash %x not found", hash) + } + + chainConfig, err := api.chainConfig(tx) + if err != nil { + stream.WriteNil() + return err + } + + if chainConfig.IsOptimismPreBedrock(block.NumberU64()) { + if api.historicalRPCService == nil { + return rpc.ErrNoHistoricalFallback + } + var traceResult interface{} + // relay using block hash + if err := api.relayToHistoricalBackend(ctx, &traceResult, "debug_traceBlockByHash", block.Hash(), config); err != nil { + return fmt.Errorf("historical backend error: %w", err) + } + // stream out relayed response + result, err := json.Marshal(&traceResult) + if err != nil { + return err + } + stream.WriteRaw(string(result)) + return nil }   // if we've pruned this history away for this block then just return early @@ -86,11 +113,6 @@ if config.BorTraceEnabled == nil { config.BorTraceEnabled = newBoolPtr(false) }   - chainConfig, err := api.chainConfig(tx) - if err != nil { - stream.WriteNil() - return err - } engine := api.engine()   _, blockCtx, _, ibs, _, err := transactions.ComputeTxEnv(ctx, engine, block, chainConfig, api._blockReader, tx, 0, api.historyV3(tx)) @@ -193,6 +215,22 @@ stream.WriteNil() return nil }   + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return rpc.ErrNoHistoricalFallback + } + var traceResult interface{} + if err := api.relayToHistoricalBackend(ctx, &traceResult, "debug_traceTransaction", hash, config); err != nil { + return fmt.Errorf("historical backend error: %w", err) + } + result, err := json.Marshal(traceResult) + if err != nil { + return err + } + stream.WriteRaw(string(result)) + return nil + } + // check pruning to ensure we have history at this block level err = api.BaseAPI.checkPruneHistory(tx, blockNum) if err != nil { @@ -274,6 +312,10 @@ if err != nil { return fmt.Errorf("get block number: %v", err) }   + if chainConfig.IsOptimismPreBedrock(blockNumber) { + return errors.New("l2geth does not have a debug_traceCall method") + } + err = api.BaseAPI.checkPruneHistory(dbtx, blockNumber) if err != nil { return err @@ -318,6 +360,7 @@ }   blockCtx := transactions.NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, dbtx, api._blockReader) txCtx := core.NewEVMTxContext(msg) + blockCtx.L1CostFunc = opstack.NewL1CostFunc(chainConfig, ibs) // Trace the transaction and return return transactions.TraceTx(ctx, msg, blockCtx, txCtx, ibs, config, chainConfig, stream, api.evmCallTimeout) } @@ -439,6 +482,7 @@ Difficulty: new(big.Int).Set(parent.Difficulty), GasLimit: parent.GasLimit, BaseFee: &baseFee, } + blockCtx.L1CostFunc = opstack.NewL1CostFunc(chainConfig, st)   // Get a new instance of the EVM evm = vm.NewEVM(blockCtx, txCtx, st, chainConfig, vm.Config{Debug: false})
diff --git ledgerwatch/erigon/turbo/transactions/call.go bobanetwork/v3-erigon/turbo/transactions/call.go index 822f7505e4b65e3d41c9cf9d9f2978801369bbff..06190063331203f83dc37248e54bf27ce54a5a72 100644 --- ledgerwatch/erigon/turbo/transactions/call.go +++ bobanetwork/v3-erigon/turbo/transactions/call.go @@ -11,6 +11,7 @@ "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/opstack"   "github.com/ledgerwatch/erigon/consensus" "github.com/ledgerwatch/erigon/core" @@ -80,8 +81,10 @@ msg, err := args.ToMessage(gasCap, baseFee) if err != nil { return nil, err } + blockCtx := NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, tx, headerReader) txCtx := core.NewEVMTxContext(msg) + blockCtx.L1CostFunc = opstack.NewL1CostFunc(chainConfig, state)   evm := vm.NewEVM(blockCtx, txCtx, state, chainConfig, vm.Config{NoBaseFee: true})   @@ -213,6 +216,7 @@ return nil, err }   blockCtx := NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, tx, headerReader) + blockCtx.L1CostFunc = opstack.NewL1CostFunc(chainConfig, ibs) txCtx := core.NewEVMTxContext(msg)   evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vm.Config{NoBaseFee: true})
diff --git ledgerwatch/erigon/turbo/transactions/tracing.go bobanetwork/v3-erigon/turbo/transactions/tracing.go index 5f56a60714ab334140966e59f20d7ce031991a15..ff3fb7e060d86b3e893740323d83cf6de48be1e9 100644 --- ledgerwatch/erigon/turbo/transactions/tracing.go +++ bobanetwork/v3-erigon/turbo/transactions/tracing.go @@ -14,6 +14,7 @@ "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/opstack"   ethereum "github.com/ledgerwatch/erigon" "github.com/ledgerwatch/erigon/consensus" @@ -58,6 +59,7 @@ } header := block.HeaderNoCopy()   blockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil) + blockContext.L1CostFunc = opstack.NewL1CostFunc(cfg, statedb)   // Recompute transactions up to the target index. signer := types.MakeSigner(cfg, block.NumberU64(), block.Time())

Deposit transactions have special processing rules: gas is pre-paid on L1, and deposits with EVM-failure are included with rolled back changes (except mint). For regular transactions, at the end of the transition, the 1559 burn and L1 cost are routed to vaults.

diff --git ledgerwatch/erigon/core/state_transition.go bobanetwork/v3-erigon/core/state_transition.go index 3972dc21e1e71e009202f0675a61ce5fa3ae0d54..12f1528a3c401ca04eca356f3ea5f83844eb4f49 100644 --- ledgerwatch/erigon/core/state_transition.go +++ bobanetwork/v3-erigon/core/state_transition.go @@ -31,6 +31,7 @@ "github.com/ledgerwatch/erigon/core/vm" "github.com/ledgerwatch/erigon/core/vm/evmtypes" "github.com/ledgerwatch/erigon/crypto" "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/log/v3" )   var emptyCodeHash = crypto.Keccak256Hash(nil) @@ -87,13 +88,18 @@ BlobGas() uint64 MaxFeePerBlobGas() *uint256.Int Value() *uint256.Int   + // Mint is nil if there is no minting + Mint() *uint256.Int + IsSystemTx() bool + IsDepositTx() bool + IsFree() bool + RollupCostData() types2.RollupCostData + Nonce() uint64 CheckNonce() bool Data() []byte AccessList() types2.AccessList BlobHashes() []libcommon.Hash - - IsFree() bool }   // ExecutionResult includes all output after executing given evm @@ -199,6 +205,13 @@ gasVal, overflow := gasVal.MulOverflow(gasVal, st.gasPrice) if overflow { return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) } + var l1Cost *uint256.Int + if fn := st.evm.Context.L1CostFunc; fn != nil { + l1Cost = fn(st.msg.RollupCostData(), st.evm.Context.Time) + } + if l1Cost != nil { + gasVal = gasVal.Add(gasVal, l1Cost) + }   // compute blob fee for eip-4844 data blobs if any blobGasVal := new(uint256.Int) @@ -229,6 +242,12 @@ } balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, st.value) if overflow { return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) + } + if l1Cost != nil { + balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, l1Cost) // FIXME - combine with dgval below + if overflow { + return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) + } } balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, blobGasVal) if overflow { @@ -272,6 +291,36 @@ }   // DESCRIBED: docs/programmers_guide/guide.md#nonce func (st *StateTransition) preCheck(gasBailout bool) error { + if st.msg.IsDepositTx() { + // Check clause 6: caller has enough balance to cover asset transfer for **topmost** call + // buyGas method originally handled balance check, but deposit tx does not use it + // Therefore explicit check required for separating consensus error and evm internal error. + // If not check it here, it will trigger evm internal error and break consensus. + if have, want := st.state.GetBalance(st.msg.From()), st.msg.Value(); have.Cmp(want) < 0 { + if !gasBailout { + return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want) + } + } + + log.Debug("preCheck for Deposit txn", "from", st.msg.From(), "to", st.msg.To(), "mint", st.msg.Mint(), "value", st.msg.Mint()) + + // Following section copied from Optimism patchset + + // No fee fields to check, no nonce to check, and no need to check if EOA (L1 already verified it for us) + // Gas is free, but no refunds! + st.initialGas = st.msg.Gas() + st.gas += st.msg.Gas() // Add gas here in order to be able to execute calls. + // Don't touch the gas pool for system transactions + if st.msg.IsSystemTx() { + if st.evm.ChainRules().IsOptimismRegolith { + return fmt.Errorf("%w: address %v", ErrSystemTxNotSupported, + st.msg.From().Hex()) + } + return nil + } + return st.gp.SubGas(st.msg.Gas()) // gas used by deposits may not be used by other txs + } + // Make sure this transaction's nonce is correct. if st.msg.CheckNonce() { stNonce := st.state.GetNonce(st.msg.From()) @@ -324,6 +373,38 @@ return st.buyGas(gasBailout) }   +func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*ExecutionResult, error) { + if mint := st.msg.Mint(); mint != nil { + st.state.AddBalance(st.msg.From(), mint) + } + var snap int + if st.msg.IsDepositTx() { + snap = st.state.Snapshot() + } + + result, err := st.innerTransitionDb(refunds, gasBailout) + // Failed deposits must still be included. Unless we cannot produce the block at all due to the gas limit. + // On deposit failure, we rewind any state changes from after the minting, and increment the nonce. + if err != nil && err != ErrGasLimitReached && st.msg.IsDepositTx() { + st.state.RevertToSnapshot(snap) + // Even though we revert the state changes, always increment the nonce for the next deposit transaction + st.state.SetNonce(st.msg.From(), st.state.GetNonce(st.msg.From())+1) + // Record deposits as using all their gas (matches the gas pool) + // System Transactions are special & are not recorded as using any gas (anywhere) + gasUsed := st.msg.Gas() + if st.msg.IsSystemTx() && !st.evm.ChainConfig().IsOptimismRegolith(st.evm.Context.Time) { + gasUsed = 0 + } + result = &ExecutionResult{ + UsedGas: gasUsed, + Err: fmt.Errorf("failed deposit: %w", err), + ReturnData: nil, + } + err = nil + } + return result, err +} + // TransitionDb will transition the state by applying the current message and // returning the evm execution result with following fields. // @@ -337,7 +418,7 @@ // e.g. ErrOutOfGas, ErrExecutionReverted // // However if any consensus issue encountered, return the error directly with // nil evm execution result. -func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*ExecutionResult, error) { +func (st *StateTransition) innerTransitionDb(refunds bool, gasBailout bool) (*ExecutionResult, error) { coinbase := st.evm.Context.Coinbase   var input1 *uint256.Int @@ -418,6 +499,24 @@ // Increment the nonce for the next transaction st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value, bailout) } + // if deposit: skip refunds, skip tipping coinbase + // Regolith changes this behaviour to report the actual gasUsed instead of always reporting all gas used. + if st.msg.IsDepositTx() && !rules.IsOptimismRegolith { + // Record deposits as using all their gas (matches the gas pool) + // System Transactions are special & are not recorded as using any gas (anywhere) + gasUsed := st.msg.Gas() + if st.msg.IsSystemTx() { + gasUsed = 0 + } + return &ExecutionResult{ + UsedGas: gasUsed, + Err: vmerr, + ReturnData: ret, + }, nil + } + // Note for deposit tx there is no ETH refunded for unused gas, but that's taken care of by the fact that gasPrice + // is always 0 for deposit tx. So calling refundGas will ensure the gasUsed accounting is correct without actually + // changing the sender's balance if refunds { if rules.IsLondon { // After EIP-3529: refunds are capped to gasUsed / 5 @@ -427,6 +526,14 @@ // Before EIP-3529: refunds were capped to gasUsed / 2 st.refundGas(params.RefundQuotient) } } + if st.msg.IsDepositTx() && rules.IsOptimismRegolith { + // Skip coinbase payments for deposit tx in Regolith + return &ExecutionResult{ + UsedGas: st.gasUsed(), + Err: vmerr, + ReturnData: ret, + }, nil + } effectiveTip := st.gasPrice if rules.IsLondon { if st.gasFeeCap.Gt(st.evm.Context.BaseFee) { @@ -462,6 +569,17 @@ input2, output1.Sub(output1, amount), output2.Add(output2, amount), ) + } + + // Check that we are post bedrock to be able to create pseudo pre-bedrock blocks (these are pre-bedrock, but don't follow l2 geth rules) + if rules.IsOptimismBedrock { + st.state.AddBalance(params.OptimismBaseFeeRecipient, new(uint256.Int).Mul(uint256.NewInt(st.gasUsed()), st.evm.Context.BaseFee)) + if st.evm.Context.L1CostFunc == nil { // Erigon EVM context is used in many unexpected/hacky ways, let's panic if it's misconfigured + panic("missing L1 cost func in block context, please configure l1 cost when using optimism config to run EVM") + } + if cost := st.evm.Context.L1CostFunc(st.msg.RollupCostData(), st.evm.Context.Time); cost != nil { + st.state.AddBalance(params.OptimismL1FeeRecipient, cost) + } }   return &ExecutionResult{

Deposit transactions have special processing rules: gas is pre-paid on L1, and deposits with EVM-failure are included with rolled back changes (except mint). For regular transactions, at the end of the transition, the 1559 burn and L1 cost are routed to vaults.

diff --git ledgerwatch/erigon/consensus/misc/eip1559.go bobanetwork/v3-erigon/consensus/misc/eip1559.go index b2a53af3f53c69aa8641369e5026c4ce82da9db5..97a452fdd11835f801144551f737d30699b95695 100644 --- ledgerwatch/erigon/consensus/misc/eip1559.go +++ bobanetwork/v3-erigon/consensus/misc/eip1559.go @@ -22,7 +22,6 @@ "math/big"   "github.com/ledgerwatch/erigon-lib/chain" "github.com/ledgerwatch/erigon-lib/common" - libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon/polygon/bor/borcfg"   @@ -40,10 +39,13 @@ if !skipGasLimit { // Verify that the gas limit remains within allowed bounds parentGasLimit := parent.GasLimit if !config.IsLondon(parent.Number.Uint64()) { - parentGasLimit = parent.GasLimit * params.ElasticityMultiplier + parentGasLimit = parent.GasLimit * config.ElasticityMultiplier(params.ElasticityMultiplier) } - if err := VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil { - return err + + if config.Optimism == nil { // gasLimit can adjust instantly in optimism + if err := VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil { + return err + } } } // Verify the header is not malformed @@ -51,7 +53,7 @@ if header.BaseFee == nil { return fmt.Errorf("header is missing baseFee") } // Verify the baseFee is correct based on the parent header. - expectedBaseFee := CalcBaseFee(config, parent) + expectedBaseFee := CalcBaseFee(config, parent, header.Time) if header.BaseFee.Cmp(expectedBaseFee) != 0 { return fmt.Errorf("invalid baseFee: have %s, want %s, parentBaseFee %s, parentGasUsed %d", header.BaseFee, expectedBaseFee, parent.BaseFee, parent.GasUsed) @@ -66,7 +68,7 @@ func (f eip1559Calculator) CurrentFees(chainConfig *chain.Config, db kv.Getter) (baseFee uint64, blobFee uint64, minBlobGasPrice uint64, err error) { hash := rawdb.ReadHeadHeaderHash(db)   - if hash == (libcommon.Hash{}) { + if hash == (common.Hash{}) { return 0, 0, 0, fmt.Errorf("can't get head header hash") }   @@ -78,7 +80,7 @@ }   if chainConfig != nil { if currentHeader.BaseFee != nil { - baseFee = CalcBaseFee(chainConfig, currentHeader).Uint64() + baseFee = CalcBaseFee(chainConfig, currentHeader, currentHeader.Time).Uint64() }   if currentHeader.ExcessBlobGas != nil { @@ -96,16 +98,21 @@ return baseFee, blobFee, minBlobGasPrice, nil }   // CalcBaseFee calculates the basefee of the header. -func CalcBaseFee(config *chain.Config, parent *types.Header) *big.Int { +func CalcBaseFee(config *chain.Config, parent *types.Header, time uint64) *big.Int { + // If the current block is pre bedrock, return 0. + if config.IsOptimismPreBedrock(parent.Number.Uint64()) { + return common.Big0 + } + // If the current block is the first EIP-1559 block, return the InitialBaseFee. if !config.IsLondon(parent.Number.Uint64()) { return new(big.Int).SetUint64(params.InitialBaseFee) }   var ( - parentGasTarget = parent.GasLimit / params.ElasticityMultiplier + parentGasTarget = parent.GasLimit / config.ElasticityMultiplier(params.ElasticityMultiplier) parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget) - baseFeeChangeDenominator = new(big.Int).SetUint64(getBaseFeeChangeDenominator(config.Bor, parent.Number.Uint64())) + baseFeeChangeDenominator = new(big.Int).SetUint64(getBaseFeeChangeDenominator(config, parent.Number.Uint64(), time)) ) // If the parent gasUsed is the same as the target, the baseFee remains unchanged. if parent.GasUsed == parentGasTarget { @@ -136,12 +143,12 @@ ) } }   -func getBaseFeeChangeDenominator(borConfig chain.BorConfig, number uint64) uint64 { +func getBaseFeeChangeDenominator(config *chain.Config, number, time uint64) uint64 { // If we're running bor based chain post delhi hardfork, return the new value - if borConfig, ok := borConfig.(*borcfg.BorConfig); ok && borConfig.IsDelhi(number) { + if borConfig, ok := config.Bor.(*borcfg.BorConfig); ok && borConfig.IsDelhi(number) { return params.BaseFeeChangeDenominatorPostDelhi }   // Return the original once for other chains and pre-fork cases - return params.BaseFeeChangeDenominator + return config.BaseFeeChangeDenominator(params.BaseFeeChangeDenominator, time) }
diff --git ledgerwatch/erigon/core/state_processor.go bobanetwork/v3-erigon/core/state_processor.go index c5b81a4978603bae8e9db6eb3b101b5f297167db..a312ca709aa93114190da5c97830db8db9c25468 100644 --- ledgerwatch/erigon/core/state_processor.go +++ bobanetwork/v3-erigon/core/state_processor.go @@ -19,6 +19,8 @@ import ( "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/opstack" + "github.com/ledgerwatch/log/v3"   "github.com/ledgerwatch/erigon/consensus" "github.com/ledgerwatch/erigon/core/state" @@ -58,6 +60,11 @@ // Update the evm with the new transaction context. evm.Reset(txContext, ibs)   + nonce := tx.GetNonce() + if msg.IsDepositTx() && config.IsOptimismRegolith(evm.Context.Time) { + nonce = ibs.GetNonce(msg.From()) + } + result, err := ApplyMessage(evm, msg, gp, true /* refunds */, false /* gasBailout */) if err != nil { return nil, nil, err @@ -84,9 +91,21 @@ receipt.Status = types.ReceiptStatusSuccessful } receipt.TxHash = tx.Hash() receipt.GasUsed = result.UsedGas + + if msg.IsDepositTx() && config.IsOptimismRegolith(evm.Context.Time) { + // The actual nonce for deposit transactions is only recorded from Regolith onwards and + // otherwise must be nil. + receipt.DepositNonce = &nonce + + if config.IsOptimismCanyon(evm.Context.Time) { + receipt.DepositReceiptVersion = new(uint64) + *receipt.DepositReceiptVersion = types.CanyonDepositReceiptVersion + } + } + // if the transaction created a contract, store the creation address in the receipt. if msg.To() == nil { - receipt.ContractAddress = crypto.CreateAddress(evm.Origin, tx.GetNonce()) + receipt.ContractAddress = crypto.CreateAddress(evm.Origin, nonce) } // Set the receipt logs and create a bloom for filtering receipt.Logs = ibs.GetLogs(tx.Hash()) @@ -106,6 +125,7 @@ func ApplyTransaction(config *chain.Config, blockHashFunc func(n uint64) libcommon.Hash, engine consensus.EngineReader, author *libcommon.Address, gp *GasPool, ibs *state.IntraBlockState, stateWriter state.StateWriter, header *types.Header, tx types.Transaction, usedGas, usedBlobGas *uint64, cfg vm.Config, ) (*types.Receipt, []byte, error) { + log.Debug("ApplyTransaction called for", "txhash", tx.Hash(), "blockNum", header.Number.Uint64()) // Create a new context to be used in the EVM environment   // Add addresses to access list if applicable @@ -113,6 +133,7 @@ // about the transaction and calling mechanisms. cfg.SkipAnalysis = SkipAnalysis(config, header.Number.Uint64())   blockContext := NewEVMBlockContext(header, blockHashFunc, engine, author) + blockContext.L1CostFunc = opstack.NewL1CostFunc(config, ibs) vmenv := vm.NewEVM(blockContext, evmtypes.TxContext{}, ibs, config, cfg)   return applyTransaction(config, engine, gp, ibs, stateWriter, header, tx, usedGas, usedBlobGas, vmenv, cfg)
diff --git ledgerwatch/erigon/core/error.go bobanetwork/v3-erigon/core/error.go index 9cb7ade50008fa52256e7960efdcc57efa26e2d2..63c8ab15ec0a48c40c5d57f46aa838fb3435f6ea 100644 --- ledgerwatch/erigon/core/error.go +++ bobanetwork/v3-erigon/core/error.go @@ -107,4 +107,7 @@ // ErrSenderNoEOA is returned if the sender of a transaction is a contract. // See EIP-3607: Reject transactions from senders with deployed code. ErrSenderNoEOA = errors.New("sender not an eoa") + + // ErrSystemTxNotSupported is returned for any deposit tx with IsSystemTx=true after the Regolith fork + ErrSystemTxNotSupported = errors.New("system tx not supported") )

The rollup functionality is enabled with the optimism field in the chain config. The EIP-1559 parameters are configurable to adjust for faster more frequent and smaller blocks. The parameters can be overriden for testing.

diff --git ledgerwatch/erigon/params/protocol_params.go bobanetwork/v3-erigon/params/protocol_params.go index 8b8c37325aed9524806fbc55232e3d0f10c66348..a28c2c37dbcb2b10b38fe07d0f49ce7819d5bf7b 100644 --- ledgerwatch/erigon/params/protocol_params.go +++ bobanetwork/v3-erigon/params/protocol_params.go @@ -22,6 +22,13 @@ "github.com/ledgerwatch/erigon-lib/common" )   +var ( + // The base fee portion of the transaction fee accumulates at this predeploy + OptimismBaseFeeRecipient = common.HexToAddress("0x4200000000000000000000000000000000000019") + // The L1 portion of the transaction fee accumulates at this predeploy + OptimismL1FeeRecipient = common.HexToAddress("0x420000000000000000000000000000000000001A") +) + const ( GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations. MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be.
diff --git ledgerwatch/erigon/erigon-lib/chain/chain_config.go bobanetwork/v3-erigon/erigon-lib/chain/chain_config.go index 4d2069ee396e41c3d5448f9ad691e330ba808a36..dbbcc45e6bff2f9291d14a959b3ae45e7fca34f7 100644 --- ledgerwatch/erigon/erigon-lib/chain/chain_config.go +++ bobanetwork/v3-erigon/erigon-lib/chain/chain_config.go @@ -68,6 +68,12 @@ ShanghaiTime *big.Int `json:"shanghaiTime,omitempty"` CancunTime *big.Int `json:"cancunTime,omitempty"` PragueTime *big.Int `json:"pragueTime,omitempty"`   + BedrockBlock *big.Int `json:"bedrockBlock,omitempty"` // Bedrock switch block (nil = no fork, 0 = already on optimism bedrock) + RegolithTime *big.Int `json:"regolithTime,omitempty"` // Regolith switch time (nil = no fork, 0 = already on optimism regolith) + CanyonTime *big.Int `json:"canyonTime,omitempty"` // Canyon switch time (nil = no fork, 0 = already on optimism canyon) + // Delta: the Delta upgrade does not affect the execution-layer, and is thus not configurable in the chain config. + EcotoneTime *big.Int `json:"ecotoneTime,omitempty"` // Ecotone switch time (nil = no fork, 0 = already on optimism ecotone) + // Optional EIP-4844 parameters MinBlobGasPrice *uint64 `json:"minBlobGasPrice,omitempty"` MaxBlobGasPerBlock *uint64 `json:"maxBlobGasPerBlock,omitempty"` @@ -82,10 +88,25 @@ Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` Aura *AuRaConfig `json:"aura,omitempty"`   + // Optimism config + Optimism *OptimismConfig `json:"optimism,omitempty"` + Bor BorConfig `json:"-"` BorJSON json.RawMessage `json:"bor,omitempty"` }   +// OptimismConfig is the optimism config. +type OptimismConfig struct { + EIP1559Elasticity uint64 `json:"eip1559Elasticity"` + EIP1559Denominator uint64 `json:"eip1559Denominator"` + EIP1559DenominatorCanyon uint64 `json:"eip1559DenominatorCanyon"` +} + +// String implements the stringer interface, returning the optimism fee config details. +func (o *OptimismConfig) String() string { + return "optimism" +} + type BorConfig interface { fmt.Stringer IsAgra(num uint64) bool @@ -97,7 +118,7 @@ func (c *Config) String() string { engine := c.getEngine()   - return fmt.Sprintf("{ChainID: %v, Homestead: %v, DAO: %v, Tangerine Whistle: %v, Spurious Dragon: %v, Byzantium: %v, Constantinople: %v, Petersburg: %v, Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, Gray Glacier: %v, Terminal Total Difficulty: %v, Merge Netsplit: %v, Shanghai: %v, Cancun: %v, Prague: %v, Engine: %v}", + return fmt.Sprintf("{ChainID: %v, Homestead: %v, DAO: %v, Tangerine Whistle: %v, Spurious Dragon: %v, Byzantium: %v, Constantinople: %v, Petersburg: %v, Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, Gray Glacier: %v, Terminal Total Difficulty: %v, Merge Netsplit: %v, Shanghai: %v, Cancun: %v, Prague: %v, BedrockBlock: %v, RegolithTime: %v, CanyonTime: %v, EcotoneTime: %v, Engine: %v}", c.ChainID, c.HomesteadBlock, c.DAOForkBlock, @@ -117,6 +138,10 @@ c.MergeNetsplitBlock, c.ShanghaiTime, c.CancunTime, c.PragueTime, + c.BedrockBlock, + c.RegolithTime, + c.CanyonTime, + c.EcotoneTime, engine, ) } @@ -131,6 +156,8 @@ case c.Bor != nil: return c.Bor.String() case c.Aura != nil: return c.Aura.String() + case c.Optimism != nil: + return c.Optimism.String() default: return "unknown" } @@ -231,12 +258,74 @@ func (c *Config) IsPrague(time uint64) bool { return isForked(c.PragueTime, time) }   +func (c *Config) IsBedrock(num uint64) bool { + return isForked(c.BedrockBlock, num) +} + +func (c *Config) IsRegolith(time uint64) bool { + return isForked(c.RegolithTime, time) +} + +func (c *Config) IsCanyon(time uint64) bool { + return isForked(c.CanyonTime, time) +} + +func (c *Config) IsEcotone(time uint64) bool { + return isForked(c.EcotoneTime, time) +} + +// IsOptimism returns whether the node is an optimism node or not. +func (c *Config) IsOptimism() bool { + return c.Optimism != nil +} + +// IsOptimismBedrock returns true iff this is an optimism node & bedrock is active +func (c *Config) IsOptimismBedrock(num uint64) bool { + return c.IsOptimism() && c.IsBedrock(num) +} + +func (c *Config) IsOptimismRegolith(time uint64) bool { + return c.IsOptimism() && c.IsRegolith(time) +} + +func (c *Config) IsOptimismCanyon(time uint64) bool { + return c.IsOptimism() && c.IsCanyon(time) +} + +func (c *Config) IsOptimismEcotone(time uint64) bool { + return c.IsOptimism() && c.IsEcotone(time) +} + +// IsOptimismPreBedrock returns true iff this is an optimism node & bedrock is not yet active +func (c *Config) IsOptimismPreBedrock(num uint64) bool { + return c.IsOptimism() && !c.IsBedrock(num) +} + func (c *Config) GetBurntContract(num uint64) *common.Address { if len(c.BurntContract) == 0 { return nil } addr := borKeyValueConfigHelper(c.BurntContract, num) return &addr +} + +// BaseFeeChangeDenominator bounds the amount the base fee can change between blocks. +func (c *Config) BaseFeeChangeDenominator(defaultParam, time uint64) uint64 { + if c.IsOptimism() { + if c.IsCanyon(time) { + return c.Optimism.EIP1559DenominatorCanyon + } + return c.Optimism.EIP1559Denominator + } + return defaultParam +} + +// ElasticityMultiplier bounds the maximum gas limit an EIP-1559 block may have. +func (c *Config) ElasticityMultiplier(defaultParam int) uint64 { + if c.IsOptimism() { + return c.Optimism.EIP1559Elasticity + } + return uint64(defaultParam) }   func (c *Config) GetMinBlobGasPrice() uint64 { @@ -498,6 +587,7 @@ IsIstanbul, IsBerlin, IsLondon, IsShanghai bool IsCancun, IsNapoli bool IsPrague bool IsAura bool + IsOptimismBedrock, IsOptimismRegolith bool }   // Rules ensures c's ChainID is not nil and returns a new Rules instance @@ -523,6 +613,8 @@ IsCancun: c.IsCancun(time), IsNapoli: c.IsNapoli(num), IsPrague: c.IsPrague(time), IsAura: c.Aura != nil, + IsOptimismBedrock: c.IsOptimismBedrock(num), + IsOptimismRegolith: c.IsOptimismRegolith(time), } }

The Engine API is extended to insert transactions into the block and optionally exclude the tx-pool, to reproduce the exact block of the sequencer from just the inputs, as derived from L1 by the rollup-node. See L2 execution engine specs.

diff --git ledgerwatch/erigon/turbo/engineapi/engine_server.go bobanetwork/v3-erigon/turbo/engineapi/engine_server.go index c302139d91c0900bb17b58b8bc139997cf2cb881..8fde4da74d99c60d60a4db4cf1b40fccddcf196a 100644 --- ledgerwatch/erigon/turbo/engineapi/engine_server.go +++ bobanetwork/v3-erigon/turbo/engineapi/engine_server.go @@ -78,8 +78,10 @@ }   func (e *EngineServer) Start(httpConfig *httpcfg.HttpCfg, db kv.RoDB, blockReader services.FullBlockReader, filters *rpchelper.Filters, stateCache kvcache.Cache, agg *libstate.AggregatorV3, engineReader consensus.EngineReader, - eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient) { - base := jsonrpc.NewBaseApi(filters, stateCache, blockReader, agg, httpConfig.WithDatadir, httpConfig.EvmCallTimeout, engineReader, httpConfig.Dirs) + eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, + seqRPCService, historicalRPCService *rpc.Client, +) { + base := jsonrpc.NewBaseApi(filters, stateCache, blockReader, agg, httpConfig.WithDatadir, httpConfig.EvmCallTimeout, engineReader, httpConfig.Dirs, seqRPCService, historicalRPCService)   ethImpl := jsonrpc.NewEthAPI(base, db, eth, txPool, mining, httpConfig.Gascap, httpConfig.ReturnDataLimit, httpConfig.AllowUnprotectedTxs, httpConfig.MaxGetProofRewindBlockCount, e.logger)   @@ -415,24 +417,38 @@ } data := resp.Data   ts := data.ExecutionPayload.Timestamp - if (!s.config.IsCancun(ts) && version >= clparams.DenebVersion) || - (s.config.IsCancun(ts) && version < clparams.DenebVersion) { + if s.config.IsCancun(ts) && version < clparams.DenebVersion { return nil, &rpc.UnsupportedForkError{Message: "Unsupported fork"} }   - return &engine_types.GetPayloadResponse{ + response := engine_types.GetPayloadResponse{ ExecutionPayload: engine_types.ConvertPayloadFromRpc(data.ExecutionPayload), BlockValue: (*hexutil.Big)(gointerfaces.ConvertH256ToUint256Int(data.BlockValue).ToBig()), BlobsBundle: engine_types.ConvertBlobsFromRpc(data.BlobsBundle), - }, nil + } + if s.config.IsOptimism() && s.config.IsCancun(ts) && version >= clparams.DenebVersion { + if data.ParentBeaconBlockRoot == nil { + panic("missing ParentBeaconBlockRoot in Ecotone block") + } + parentBeaconBlockRoot := libcommon.Hash(gointerfaces.ConvertH256ToHash(data.ParentBeaconBlockRoot)) + response.ParentBeaconBlockRoot = &parentBeaconBlockRoot + } + + return &response, nil }   // engineForkChoiceUpdated either states new block head or request the assembling of a new block func (s *EngineServer) forkchoiceUpdated(ctx context.Context, forkchoiceState *engine_types.ForkChoiceState, payloadAttributes *engine_types.PayloadAttributes, version clparams.StateVersion, ) (*engine_types.ForkChoiceUpdatedResponse, error) { - status, err := s.getQuickPayloadStatusIfPossible(forkchoiceState.HeadHash, 0, libcommon.Hash{}, forkchoiceState, false) - if err != nil { - return nil, err + var status *engine_types.PayloadStatus + var err error + // In the Optimism case, we allow arbitrary rewinding of the safe block + // hash, so we skip the path which might short-circuit that + if s.config.Optimism == nil { + status, err = s.getQuickPayloadStatusIfPossible(forkchoiceState.HeadHash, 0, libcommon.Hash{}, forkchoiceState, false) + if err != nil { + return nil, err + } } s.lock.Lock() defer s.lock.Unlock() @@ -452,19 +468,17 @@ } }   if payloadAttributes != nil { - if version < clparams.DenebVersion && payloadAttributes.ParentBeaconBlockRoot != nil { - return nil, &engine_helpers.InvalidPayloadAttributesErr // Unexpected Beacon Root - } - if version >= clparams.DenebVersion && payloadAttributes.ParentBeaconBlockRoot == nil { - return nil, &engine_helpers.InvalidPayloadAttributesErr // Beacon Root missing - } - timestamp := uint64(payloadAttributes.Timestamp) - if !s.config.IsCancun(timestamp) && version >= clparams.DenebVersion { // V3 before cancun + if s.config.IsCancun(timestamp) && version < clparams.DenebVersion { // Not V3 after cancun + if payloadAttributes.ParentBeaconBlockRoot != nil { + return nil, &rpc.InvalidParamsError{Message: "Unexpected Beacon Root"} + } return nil, &rpc.UnsupportedForkError{Message: "Unsupported fork"} } - if s.config.IsCancun(timestamp) && version < clparams.DenebVersion { // Not V3 after cancun - return nil, &rpc.UnsupportedForkError{Message: "Unsupported fork"} + if s.config.IsCancun(timestamp) && version >= clparams.DenebVersion { + if payloadAttributes.ParentBeaconBlockRoot == nil { + return nil, &rpc.InvalidParamsError{Message: "Beacon Root missing"} + } } }   @@ -479,16 +493,42 @@ }   headHeader := s.chainRW.GetHeaderByHash(forkchoiceState.HeadHash)   + if headHeader.Hash() != forkchoiceState.HeadHash && s.config.Optimism == nil { + // Per Item 2 of https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.9/src/engine/specification.md#specification-1: + // Client software MAY skip an update of the forkchoice state and + // MUST NOT begin a payload build process if forkchoiceState.headBlockHash doesn't reference a leaf of the block tree. + // That is, the block referenced by forkchoiceState.headBlockHash is neither the head of the canonical chain nor a block at the tip of any other chain. + // In the case of such an event, client software MUST return + // {payloadStatus: {status: VALID, latestValidHash: forkchoiceState.headBlockHash, validationError: null}, payloadId: null}. + // We skip this check in the Optimism case as Optimism allows arbitrary + // depth re-orgs + + s.logger.Warn("Skipping payload building because forkchoiceState.headBlockHash is not the head of the canonical chain", + "forkChoice.HeadBlockHash", forkchoiceState.HeadHash, "headHeader.Hash", headHeader.Hash()) + return &engine_types.ForkChoiceUpdatedResponse{PayloadStatus: status}, nil + } + log.Debug("Continuing EngineForkChoiceUpdated", "headNumber", headHeader.Number, "headHash", headHeader.Hash(), "numDeposits", len(payloadAttributes.Transactions)) + timestamp := uint64(payloadAttributes.Timestamp) if headHeader.Time >= timestamp { return nil, &engine_helpers.InvalidPayloadAttributesErr } + txs := make([][]byte, len(payloadAttributes.Transactions)) + for i, tx := range payloadAttributes.Transactions { + txs[i] = tx + } + if s.config.Optimism != nil && payloadAttributes.GasLimit == nil { + return nil, &engine_helpers.InvalidPayloadAttributesErr + }   req := &execution.AssembleBlockRequest{ ParentHash: gointerfaces.ConvertHashToH256(forkchoiceState.HeadHash), Timestamp: timestamp, PrevRandao: gointerfaces.ConvertHashToH256(payloadAttributes.PrevRandao), SuggestedFeeRecipient: gointerfaces.ConvertAddressToH160(payloadAttributes.SuggestedFeeRecipient), + GasLimit: (*uint64)(payloadAttributes.GasLimit), + Transactions: txs, + NoTxPool: payloadAttributes.NoTxPool, }   if version >= clparams.CapellaVersion { @@ -506,6 +546,7 @@ } if resp.Busy { return nil, errors.New("[ForkChoiceUpdated]: execution service is busy, cannot assemble blocks") } + return &engine_types.ForkChoiceUpdatedResponse{ PayloadStatus: &engine_types.PayloadStatus{ Status: engine_types.ValidStatus,
diff --git ledgerwatch/erigon/turbo/engineapi/engine_types/jsonrpc.go bobanetwork/v3-erigon/turbo/engineapi/engine_types/jsonrpc.go index 3e3bbde23e8b415dd04a22bad226289819bf20f8..3032eaeb1046212532ba49a979b6c0ede5316346 100644 --- ledgerwatch/erigon/turbo/engineapi/engine_types/jsonrpc.go +++ bobanetwork/v3-erigon/turbo/engineapi/engine_types/jsonrpc.go @@ -50,6 +50,11 @@ PrevRandao common.Hash `json:"prevRandao" gencodec:"required"` SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"` Withdrawals []*types.Withdrawal `json:"withdrawals"` ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` + + // optimism + Transactions []hexutility.Bytes `json:"transactions,omitempty"` + NoTxPool bool `json:"noTxPool,omitempty"` + GasLimit *hexutil.Uint64 `json:"gasLimit,omitempty"` }   // TransitionConfiguration represents the correct configurations of the CL and the EL @@ -88,6 +93,9 @@ ExecutionPayload *ExecutionPayload `json:"executionPayload" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` ShouldOverrideBuilder bool `json:"shouldOverrideBuilder"` + + // OP-Stack: Ecotone specific fields + ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` }   type StringifiedError struct{ err error }

The block-building code (in the “mining” stages because of Proof-Of-Work legacy of ethereum) implements the changes to support the transaction-inclusion, tx-pool toggle and gaslimit parameters of the Engine API.

diff --git ledgerwatch/erigon/turbo/execution/eth1/block_building.go bobanetwork/v3-erigon/turbo/execution/eth1/block_building.go index 6e8174e782da45ba2166413d76e988e6c39ab97c..8b0692ad6eb4764b45014132c38c25a4fa98a7ee 100644 --- ledgerwatch/erigon/turbo/execution/eth1/block_building.go +++ bobanetwork/v3-erigon/turbo/execution/eth1/block_building.go @@ -54,6 +54,9 @@ Timestamp: req.Timestamp, PrevRandao: gointerfaces.ConvertH256ToHash(req.PrevRandao), SuggestedFeeRecipient: gointerfaces.ConvertH160toAddress(req.SuggestedFeeRecipient), Withdrawals: eth1_utils.ConvertWithdrawalsFromRpc(req.Withdrawals), + Transactions: req.Transactions, + NoTxPool: req.NoTxPool, + GasLimit: req.GasLimit, }   if err := e.checkWithdrawalsPresence(param.Timestamp, param.Withdrawals); err != nil { @@ -196,12 +199,18 @@ blobsBundle.Blobs = append(blobsBundle.Blobs, b[:]) } }   + data := execution.AssembledBlockData{ + ExecutionPayload: payload, + BlockValue: gointerfaces.ConvertUint256IntToH256(blockValue), + BlobsBundle: blobsBundle, + } + + if header.ParentBeaconBlockRoot != nil { + data.ParentBeaconBlockRoot = gointerfaces.ConvertHashToH256(*header.ParentBeaconBlockRoot) + } + return &execution.GetAssembledBlockResponse{ - Data: &execution.AssembledBlockData{ - ExecutionPayload: payload, - BlockValue: gointerfaces.ConvertUint256IntToH256(blockValue), - BlobsBundle: blobsBundle, - }, + Data: &data, Busy: false, }, nil }
diff --git ledgerwatch/erigon/turbo/execution/eth1/forkchoice.go bobanetwork/v3-erigon/turbo/execution/eth1/forkchoice.go index baaaf065b36ed1439310699f2b5bb143091a6437..ffc928de586e44daebbcecff5f71d31b3ccb23d5 100644 --- ledgerwatch/erigon/turbo/execution/eth1/forkchoice.go +++ bobanetwork/v3-erigon/turbo/execution/eth1/forkchoice.go @@ -2,6 +2,7 @@ package eth1   import ( "context" + "errors" "fmt" "time"   @@ -79,6 +80,11 @@ fcuTimer := time.NewTimer(time.Duration(req.Timeout) * time.Millisecond)   select { case <-fcuTimer.C: + if e.config.IsOptimism() { + // op-node does not handle SYNCING as asynchronous forkChoiceUpdated. + // return an error and make op-node retry + return nil, errors.New("forkChoiceUpdated timeout") + } e.logger.Debug("treating forkChoiceUpdated as asynchronous as it is taking too long") return &execution.ForkChoiceReceipt{ LatestValidHash: gointerfaces.ConvertHashToH256(libcommon.Hash{}), @@ -103,6 +109,12 @@ }   func (e *EthereumExecutionModule) updateForkChoice(ctx context.Context, blockHash, safeHash, finalizedHash libcommon.Hash, outcomeCh chan forkchoiceOutcome) { if !e.semaphore.TryAcquire(1) { + if e.config.IsOptimism() { + // op-node does not handle SYNCING as asynchronous forkChoiceUpdated. + // return an error and make op-node retry + sendForkchoiceErrorWithoutWaiting(outcomeCh, errors.New("cannot update forkchoice. execution service is busy")) + return + } sendForkchoiceReceiptWithoutWaiting(outcomeCh, &execution.ForkChoiceReceipt{ LatestValidHash: gointerfaces.ConvertHashToH256(libcommon.Hash{}), Status: execution.ExecutionStatus_Busy, @@ -139,6 +151,16 @@ sendForkchoiceErrorWithoutWaiting(outcomeCh, err) return }   + // Only Optimism allows unwinding to previously canonical hashes + unwindingToCanonical := false + if e.config.IsOptimism() { + headHash := rawdb.ReadHeadBlockHash(tx) + unwindingToCanonical = (blockHash != headHash) && (canonicalHash == blockHash) + if unwindingToCanonical { + e.logger.Info("Optimism ForkChoice is choosing to unwind to a previously canonical block", "blockHash", blockHash, "blockNumber", fcuHeader.Number.Uint64(), "headHash", headHash) + } + } + if canonicalHash == blockHash { // if block hash is part of the canonical chain treat it as no-op. writeForkChoiceHashes(tx, blockHash, safeHash, finalizedHash) @@ -154,11 +176,14 @@ Status: execution.ExecutionStatus_InvalidForkchoice, }) return } - sendForkchoiceReceiptWithoutWaiting(outcomeCh, &execution.ForkChoiceReceipt{ - LatestValidHash: gointerfaces.ConvertHashToH256(blockHash), - Status: execution.ExecutionStatus_Success, - }) - return + + if !unwindingToCanonical { + sendForkchoiceReceiptWithoutWaiting(outcomeCh, &execution.ForkChoiceReceipt{ + LatestValidHash: gointerfaces.ConvertHashToH256(blockHash), + Status: execution.ExecutionStatus_Success, + }) + return + } }   // If we don't have it, too bad @@ -178,11 +203,13 @@ return } // Find such point, and collect all hashes newCanonicals := make([]*canonicalEntry, 0, 64) - newCanonicals = append(newCanonicals, &canonicalEntry{ - hash: fcuHeader.Hash(), - number: fcuHeader.Number.Uint64(), - }) - for !isCanonicalHash { + if !unwindingToCanonical { + newCanonicals = append(newCanonicals, &canonicalEntry{ + hash: fcuHeader.Hash(), + number: fcuHeader.Number.Uint64(), + }) + } + for !isCanonicalHash && !unwindingToCanonical { newCanonicals = append(newCanonicals, &canonicalEntry{ hash: currentParentHash, number: currentParentNumber, @@ -207,10 +234,14 @@ sendForkchoiceErrorWithoutWaiting(outcomeCh, err) return } } + unwindToNumber := currentParentNumber + if unwindingToCanonical { + unwindToNumber = fcuHeader.Number.Uint64() + }   - e.executionPipeline.UnwindTo(currentParentNumber, stagedsync.ForkChoice) + e.executionPipeline.UnwindTo(unwindToNumber, stagedsync.ForkChoice) if e.historyV3 { - if err := rawdbv3.TxNums.Truncate(tx, currentParentNumber); err != nil { + if err := rawdbv3.TxNums.Truncate(tx, unwindToNumber); err != nil { sendForkchoiceErrorWithoutWaiting(outcomeCh, err) return } @@ -243,7 +274,7 @@ }   // Truncate tx nums if e.historyV3 { - if err := rawdbv3.TxNums.Truncate(tx, currentParentNumber); err != nil { + if err := rawdbv3.TxNums.Truncate(tx, unwindToNumber); err != nil { sendForkchoiceErrorWithoutWaiting(outcomeCh, err) return }
diff --git ledgerwatch/erigon/eth/stagedsync/stage_mining_create_block.go bobanetwork/v3-erigon/eth/stagedsync/stage_mining_create_block.go index 40b63680e1632323555806581b212262983efd61..c0fe927e54b577cbd50fdf886eeb196038e8636b 100644 --- ledgerwatch/erigon/eth/stagedsync/stage_mining_create_block.go +++ bobanetwork/v3-erigon/eth/stagedsync/stage_mining_create_block.go @@ -31,6 +31,9 @@ Txs types.Transactions Receipts types.Receipts Withdrawals []*types.Withdrawal PreparedTxs types.TransactionsStream + + Deposits [][]byte + NoTxPool bool }   type MiningState struct { @@ -91,7 +94,7 @@ // TODO: // - resubmitAdjustCh - variable is not implemented func SpawnMiningCreateBlockStage(s *StageState, tx kv.RwTx, cfg MiningCreateBlockCfg, quit <-chan struct{}, logger log.Logger) (err error) { current := cfg.miner.MiningBlock - txPoolLocals := []libcommon.Address{} //txPoolV2 has no concept of local addresses (yet?) + txPoolLocals := []libcommon.Address{} // txPoolV2 has no concept of local addresses (yet?) coinbase := cfg.miner.MiningConfig.Etherbase   const ( @@ -170,7 +173,11 @@ family: mapset.NewSet[libcommon.Hash](), uncles: mapset.NewSet[libcommon.Hash](), }   - header := core.MakeEmptyHeader(parent, &cfg.chainConfig, timestamp, &cfg.miner.MiningConfig.GasLimit) + targetGasLimit := &cfg.miner.MiningConfig.GasLimit + if cfg.chainConfig.IsOptimism() && cfg.blockBuilderParameters != nil && cfg.blockBuilderParameters.GasLimit != nil { + targetGasLimit = cfg.blockBuilderParameters.GasLimit + } + header := core.MakeEmptyHeader(parent, &cfg.chainConfig, timestamp, targetGasLimit) header.Coinbase = coinbase header.Extra = cfg.miner.MiningConfig.ExtraData   @@ -191,6 +198,7 @@ "callers", debug.Callers(10)) return err }   + log.Info("cfg.blockBuilderParamters", "params", cfg.blockBuilderParameters) if cfg.blockBuilderParameters != nil { header.MixDigest = cfg.blockBuilderParameters.PrevRandao header.ParentBeaconBlockRoot = cfg.blockBuilderParameters.ParentBeaconBlockRoot @@ -198,6 +206,9 @@ current.Header = header current.Uncles = nil current.Withdrawals = cfg.blockBuilderParameters.Withdrawals + + current.Deposits = cfg.blockBuilderParameters.Transactions + current.NoTxPool = cfg.blockBuilderParameters.NoTxPool return nil }   @@ -294,7 +305,6 @@ localUncles[u.Hash()] = u } else { remoteUncles[u.Hash()] = u } - } return }
diff --git ledgerwatch/erigon/eth/stagedsync/stage_mining_exec.go bobanetwork/v3-erigon/eth/stagedsync/stage_mining_exec.go index 7fae41332b307a03caa555f1ae5bd8e98cfd7cbe..90395618d3c41b0a398cb05d42d58d692bb6cb0c 100644 --- ledgerwatch/erigon/eth/stagedsync/stage_mining_exec.go +++ bobanetwork/v3-erigon/eth/stagedsync/stage_mining_exec.go @@ -19,6 +19,7 @@ "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/membatch" types2 "github.com/ledgerwatch/erigon-lib/types" "github.com/ledgerwatch/erigon/consensus" + "github.com/ledgerwatch/erigon/consensus/misc" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/state" @@ -91,6 +92,9 @@ chainReader := ChainReader{Cfg: cfg.chainConfig, Db: tx, BlockReader: cfg.blockReader, Logger: logger} core.InitializeBlockExecution(cfg.engine, chainReader, current.Header, &cfg.chainConfig, ibs, logger)   + // Optimism Canyon + misc.EnsureCreate2Deployer(&cfg.chainConfig, current.Header.Time, ibs) + // Create an empty block based on temporary copied state for // sealing in advance without waiting block execution finished. if !noempty { @@ -104,8 +108,33 @@ // Short circuit if there is no available pending transactions. // But if we disable empty precommit already, ignore it. Since // empty block is necessary to keep the liveness of the network. if noempty { + log.Debug("Starting SpawnMiningExecStage", "txs", txs, "numDeposits", len(current.Deposits), "NoTxPool", current.NoTxPool) + + if len(current.Deposits) > 0 { + var txs []types.Transaction + for i := range current.Deposits { + transaction, err := types.UnmarshalTransactionFromBinary(current.Deposits[i]) + log.Debug("Decoded Deposit transaction", "i", i, "err", err, "tx", transaction) + if err == io.EOF { + continue + } + if err != nil { + return err + } + txs = append(txs, transaction) + } + depTS := types.NewTransactionsFixedOrder(txs) + + logs, _, err := addTransactionsToMiningBlock(logPrefix, current, cfg.chainConfig, cfg.vmConfig, getHeader, cfg.engine, depTS, cfg.miningState.MiningConfig.Etherbase, ibs, quit, cfg.interrupt, cfg.payloadId, logger) + log.Debug("addTransactionsToMiningBlock (deposit) result", "err", err, "logs", logs) + if err != nil { + return err + } + } + if txs != nil && !txs.Empty() { logs, _, err := addTransactionsToMiningBlock(logPrefix, current, cfg.chainConfig, cfg.vmConfig, getHeader, cfg.engine, txs, cfg.miningState.MiningConfig.Etherbase, ibs, quit, cfg.interrupt, cfg.payloadId, logger) + log.Debug("addTransactionsToMiningBlock (txs) result", "err", err, "logs", logs) if err != nil { return err } @@ -124,6 +153,11 @@ return err }   for { + if current.NoTxPool { + // Only allow the Deposit transactions from op-node + log.Debug("Not adding transactions because NoTxPool is set") + break + } txs, y, err := getNextTransactions(cfg, chainID, current.Header, 50, executionAt, simulationTx, yielded, logger) if err != nil { return err @@ -131,6 +165,7 @@ }   if !txs.Empty() { logs, stop, err := addTransactionsToMiningBlock(logPrefix, current, cfg.chainConfig, cfg.vmConfig, getHeader, cfg.engine, txs, cfg.miningState.MiningConfig.Etherbase, ibs, quit, cfg.interrupt, cfg.payloadId, logger) + log.Debug("addTransactionsToMiningBlock (regular)", "err", err, "logs", logs, "stop", stop) if err != nil { return err } @@ -265,6 +300,13 @@ } if !ok { transactions = transactions[1:] noAccountCnt++ + continue + } + if int(transaction.Type()) == types.DepositTxType { + // FIXME - may need to include some of the later checks + log.Debug("Bypassing filterBadTransactions for Deposit tx", "transaction", transaction) + filtered = append(filtered, transaction) + transactions = transactions[1:] continue } // Check transaction nonce
diff --git ledgerwatch/erigon/core/block_builder_parameters.go bobanetwork/v3-erigon/core/block_builder_parameters.go index 936724c2624ce23b4f17b90017cdfb4acee7dae2..3f7b8837b853194a073c9cc2abb41eaa54a6cb5d 100644 --- ledgerwatch/erigon/core/block_builder_parameters.go +++ bobanetwork/v3-erigon/core/block_builder_parameters.go @@ -16,4 +16,7 @@ PrevRandao libcommon.Hash SuggestedFeeRecipient libcommon.Address Withdrawals []*types.Withdrawal // added in Shapella (EIP-4895) ParentBeaconBlockRoot *libcommon.Hash // added in Dencun (EIP-4788) + Transactions [][]byte + NoTxPool bool + GasLimit *uint64 }
diff --git ledgerwatch/erigon/core/chain_makers.go bobanetwork/v3-erigon/core/chain_makers.go index 25a96626be9b9635c2a13cc8051227c5e0468668..d1525a8d60cc8f6b1bbb995368a1972abf0eefd2 100644 --- ledgerwatch/erigon/core/chain_makers.go +++ bobanetwork/v3-erigon/core/chain_makers.go @@ -370,6 +370,10 @@ } if b.engine != nil { InitializeBlockExecution(b.engine, nil, b.header, config, ibs, logger) } + + // Optimism Canyon + misc.EnsureCreate2Deployer(config, b.header.Time, ibs) + // Execute any user modifications to the block if gen != nil { gen(i, b) @@ -589,13 +593,17 @@ parentGasLimit := parent.GasLimit // Set baseFee and GasLimit if we are on an EIP-1559 chain if chainConfig.IsLondon(header.Number.Uint64()) { - header.BaseFee = misc.CalcBaseFee(chainConfig, parent) + header.BaseFee = misc.CalcBaseFee(chainConfig, parent, timestamp) if !chainConfig.IsLondon(parent.Number.Uint64()) { - parentGasLimit = parent.GasLimit * params.ElasticityMultiplier + parentGasLimit = parent.GasLimit * chainConfig.ElasticityMultiplier(params.ElasticityMultiplier) } } if targetGasLimit != nil { - header.GasLimit = CalcGasLimit(parentGasLimit, *targetGasLimit) + if chainConfig.IsOptimism() { + header.GasLimit = *targetGasLimit + } else { + header.GasLimit = CalcGasLimit(parentGasLimit, *targetGasLimit) + } } else { header.GasLimit = parentGasLimit }

Transaction queueing and inclusion needs to account for the L1 cost component.

diff --git ledgerwatch/erigon/cmd/txpool/main.go bobanetwork/v3-erigon/cmd/txpool/main.go index 905ba3ef774c742fd3ef70da668387fc9171257c..421bf0c721653bc0c3c0ca9c7ad4ffba9f43e2b8 100644 --- ledgerwatch/erigon/cmd/txpool/main.go +++ bobanetwork/v3-erigon/cmd/txpool/main.go @@ -56,6 +56,7 @@ blobSlots uint64 priceBump uint64 blobPriceBump uint64   + optimism bool noTxGossip bool   commitEvery time.Duration @@ -83,6 +84,7 @@ rootCmd.PersistentFlags().Uint64Var(&blobSlots, "txpool.blobslots", txpoolcfg.DefaultConfig.BlobSlots, "Max allowed total number of blobs (within type-3 txs) per account") rootCmd.PersistentFlags().Uint64Var(&priceBump, "txpool.pricebump", txpoolcfg.DefaultConfig.PriceBump, "Price bump percentage to replace an already existing transaction") rootCmd.PersistentFlags().Uint64Var(&blobPriceBump, "txpool.blobpricebump", txpoolcfg.DefaultConfig.BlobPriceBump, "Price bump percentage to replace an existing blob (type-3) transaction") rootCmd.PersistentFlags().DurationVar(&commitEvery, utils.TxPoolCommitEveryFlag.Name, utils.TxPoolCommitEveryFlag.Value, utils.TxPoolCommitEveryFlag.Usage) + rootCmd.PersistentFlags().BoolVar(&optimism, "txpool.optimism", txpoolcfg.DefaultConfig.Optimism, "Enable Optimism Bedrock to make txpool account for L1 cost of transactions") rootCmd.PersistentFlags().BoolVar(&noTxGossip, utils.TxPoolGossipDisableFlag.Name, utils.TxPoolGossipDisableFlag.Value, utils.TxPoolGossipDisableFlag.Usage) rootCmd.Flags().StringSliceVar(&traceSenders, utils.TxPoolTraceSendersFlag.Name, []string{}, utils.TxPoolTraceSendersFlag.Usage) } @@ -151,6 +153,8 @@ cfg.BlobSlots = blobSlots cfg.PriceBump = priceBump cfg.BlobPriceBump = blobPriceBump cfg.NoGossip = noTxGossip + + cfg.Optimism = optimism   cacheConfig := kvcache.DefaultCoherentConfig cacheConfig.MetricsLabel = "txpool"

Changes to the node configuration and services.

Flag changes: - Transactions can be forwarded to an RPC for sequencing. - Historical calls can be forwarded to a legacy node. - The tx pool propagation can be enabled/disabled. - The Optimism bedrock fork activation can be changed for testing.

diff --git ledgerwatch/erigon/cmd/utils/flags.go bobanetwork/v3-erigon/cmd/utils/flags.go index 23bb4fa55c82a35e90ef46f395d861158e168868..c32768a9ed4ae100f7eb2b93d2238b3151a3e6f0 100644 --- ledgerwatch/erigon/cmd/utils/flags.go +++ bobanetwork/v3-erigon/cmd/utils/flags.go @@ -108,6 +108,10 @@ WhitelistFlag = cli.StringFlag{ Name: "whitelist", Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)", } + OverrideShanghaiTime = flags.BigFlag{ + Name: "override.shanghai", + Usage: "Manually specify the Shanghai fork time, overriding the bundled setting", + } OverrideCancunFlag = flags.BigFlag{ Name: "override.cancun", Usage: "Manually specify the Cancun fork time, overriding the bundled setting", @@ -115,6 +119,14 @@ } TrustedSetupFile = cli.StringFlag{ Name: "trusted-setup-file", Usage: "Absolute path to trusted_setup.json file", + } + OverrideOptimismCanyonFlag = flags.BigFlag{ + Name: "override.canyon", + Usage: "Manually specify the Optimism Canyon fork time, overriding the bundled setting", + } + OverrideOptimismEcotoneFlag = flags.BigFlag{ + Name: "override.ecotone", + Usage: "Manually specify the Optimism Ecotone fork time, overriding the bundled setting", } // Ethash settings EthashCachesInMemoryFlag = cli.IntFlag{ @@ -624,6 +636,33 @@ GpoMaxGasPriceFlag = cli.Int64Flag{ Name: "gpo.maxprice", Usage: "Maximum gas price will be recommended by gpo", Value: ethconfig.Defaults.GPO.MaxPrice.Int64(), + } + GpoIgnoreGasPriceFlag = cli.Int64Flag{ + Name: "gpo.ignoreprice", + Usage: "Gas price below which gpo will ignore transactions", + Value: ethconfig.Defaults.GPO.IgnorePrice.Int64(), + } + GpoMinSuggestedPriorityFeeFlag = cli.Int64Flag{ + Name: "gpo.minsuggestedpriorityfee", + Usage: "Minimum transaction priority fee to suggest. Used on OP chains when blocks are not full.", + Value: ethconfig.Defaults.GPO.MinSuggestedPriorityFee.Int64(), + } + + // Rollup Flags + RollupSequencerHTTPFlag = cli.StringFlag{ + Name: "rollup.sequencerhttp", + Usage: "HTTP endpoint for the sequencer mempool", + EnvVars: []string{"ROLLUP_SEQUENCER_HTTP_ENDPOINT"}, + } + RollupHistoricalRPCFlag = cli.StringFlag{ + Name: "rollup.historicalrpc", + Usage: "RPC endpoint for historical data.", + EnvVars: []string{"ROLLUP_HISTORICAL_RPC_ENDPOINT"}, + } + RollupHistoricalRPCTimeoutFlag = cli.StringFlag{ + Name: "rollup.historicalrpctimeout", + Usage: "Timeout for historical RPC requests.", + Value: "5s", }   // Metrics flags @@ -826,7 +865,6 @@ Name: "sentinel.port", Usage: "Port for sentinel", Value: 7777, } - OtsSearchMaxCapFlag = cli.Uint64Flag{ Name: "ots.search.max.pagesize", Usage: "Max allowed page size for search methods", @@ -1329,6 +1367,12 @@ } if ctx.IsSet(GpoMaxGasPriceFlag.Name) { cfg.MaxPrice = big.NewInt(ctx.Int64(GpoMaxGasPriceFlag.Name)) } + if ctx.IsSet(GpoIgnoreGasPriceFlag.Name) { + cfg.IgnorePrice = big.NewInt(ctx.Int64(GpoIgnoreGasPriceFlag.Name)) + } + if ctx.IsSet(GpoMinSuggestedPriorityFeeFlag.Name) { + cfg.MinSuggestedPriorityFee = big.NewInt(ctx.Int64(GpoMinSuggestedPriorityFeeFlag.Name)) + } }   // nolint @@ -1706,6 +1750,14 @@ } else { cfg.EthDiscoveryURLs = libcommon.CliString2Array(urls) } } + // Only configure sequencer http flag if we're running in verifier mode i.e. --mine is disabled. + if ctx.IsSet(RollupSequencerHTTPFlag.Name) && !ctx.IsSet(MiningEnabledFlag.Name) { + cfg.RollupSequencerHTTP = ctx.String(RollupSequencerHTTPFlag.Name) + } + if ctx.IsSet(RollupHistoricalRPCFlag.Name) { + cfg.RollupHistoricalRPC = ctx.String(RollupHistoricalRPCFlag.Name) + } + cfg.RollupHistoricalRPCTimeout = ctx.Duration(RollupHistoricalRPCTimeoutFlag.Name) // Override any default configs for hard coded networks. chain := ctx.String(ChainFlag.Name)   @@ -1744,13 +1796,47 @@ logger.Info("Using custom developer period", "seconds", cfg.Genesis.Config.Clique.Period) if !ctx.IsSet(MinerGasPriceFlag.Name) { cfg.Miner.GasPrice = big.NewInt(1) } + // TODO(jky) Review whether to add OpDevnetChainName }   if ctx.IsSet(OverrideCancunFlag.Name) { cfg.OverrideCancunTime = flags.GlobalBig(ctx, OverrideCancunFlag.Name) cfg.TxPool.OverrideCancunTime = cfg.OverrideCancunTime } + if ctx.IsSet(OverrideShanghaiTime.Name) { + cfg.OverrideShanghaiTime = flags.GlobalBig(ctx, OverrideShanghaiTime.Name) + cfg.TxPool.OverrideShanghaiTime = cfg.OverrideShanghaiTime + }   + if ctx.IsSet(OverrideOptimismCanyonFlag.Name) { + cfg.OverrideOptimismCanyonTime = flags.GlobalBig(ctx, OverrideOptimismCanyonFlag.Name) + cfg.TxPool.OverrideOptimismCanyonTime = cfg.OverrideOptimismCanyonTime + // Shanghai hardfork is included in canyon hardfork + cfg.OverrideShanghaiTime = flags.GlobalBig(ctx, OverrideOptimismCanyonFlag.Name) + cfg.TxPool.OverrideShanghaiTime = cfg.OverrideOptimismCanyonTime + } + if ctx.IsSet(OverrideShanghaiTime.Name) && ctx.IsSet(OverrideOptimismCanyonFlag.Name) { + overrideShanghaiTime := flags.GlobalBig(ctx, OverrideShanghaiTime.Name) + overrideOptimismCanyonTime := flags.GlobalBig(ctx, OverrideOptimismCanyonFlag.Name) + if overrideShanghaiTime.Cmp(overrideOptimismCanyonTime) != 0 { + logger.Warn("Shanghai hardfork time is overridden by optimism canyon hardfork time", + "shanghai", overrideShanghaiTime.String(), "canyon", overrideOptimismCanyonTime.String()) + } + } + if ctx.IsSet(OverrideOptimismEcotoneFlag.Name) { + cfg.OverrideOptimismEcotoneTime = flags.GlobalBig(ctx, OverrideOptimismEcotoneFlag.Name) + // Cancun hardfork is included in Ecotone hardfork + cfg.OverrideCancunTime = flags.GlobalBig(ctx, OverrideOptimismEcotoneFlag.Name) + cfg.TxPool.OverrideCancunTime = flags.GlobalBig(ctx, OverrideOptimismEcotoneFlag.Name) + } + if ctx.IsSet(OverrideCancunFlag.Name) && ctx.IsSet(OverrideOptimismEcotoneFlag.Name) { + overrideCancunTime := flags.GlobalBig(ctx, OverrideCancunFlag.Name) + overrideOptimismEcotoneTime := flags.GlobalBig(ctx, OverrideOptimismEcotoneFlag.Name) + if overrideCancunTime.Cmp(overrideOptimismEcotoneTime) != 0 { + logger.Warn("Cancun hardfork time is overridden by optimism Ecotone hardfork time", + "cancun", overrideCancunTime.String(), "ecotone", overrideOptimismEcotoneTime.String()) + } + } if ctx.IsSet(InternalConsensusFlag.Name) && clparams.EmbeddedSupported(cfg.NetworkID) { cfg.InternalCL = ctx.Bool(InternalConsensusFlag.Name) }
diff --git ledgerwatch/erigon/turbo/cli/default_flags.go bobanetwork/v3-erigon/turbo/cli/default_flags.go index 45a39a2a963e4bda91c248a70a414dbeaaea6f7b..c2421d4c474654aef3c5189f32fecba3dcb90e47 100644 --- ledgerwatch/erigon/turbo/cli/default_flags.go +++ bobanetwork/v3-erigon/turbo/cli/default_flags.go @@ -123,6 +123,8 @@ &utils.NetworkIdFlag, &utils.FakePoWFlag, &utils.GpoBlocksFlag, &utils.GpoPercentileFlag, + &utils.GpoIgnoreGasPriceFlag, + &utils.GpoMinSuggestedPriorityFeeFlag, &utils.InsecureUnlockAllowedFlag, &utils.HistoryV3Flag, &utils.IdentityFlag, @@ -154,6 +156,11 @@ &utils.BorBlockSizeFlag, &utils.WithHeimdallMilestones, &utils.EthStatsURLFlag, &utils.OverrideCancunFlag, + &utils.OverrideOptimismCanyonFlag, + &utils.OverrideOptimismEcotoneFlag, + &utils.RollupSequencerHTTPFlag, + &utils.RollupHistoricalRPCFlag, + &utils.RollupHistoricalRPCTimeoutFlag,   &utils.LightClientDiscoveryAddrFlag, &utils.LightClientDiscoveryPortFlag,

List the op-geth and upstream go-ethereum versions.

diff --git ledgerwatch/erigon/params/version.go bobanetwork/v3-erigon/params/version.go index a1b0c0ae15bd2cf0c2314344ca959d4760f0fac0..44e32fadd3c358586ed39357d9b5e5a46403dd23 100644 --- ledgerwatch/erigon/params/version.go +++ bobanetwork/v3-erigon/params/version.go @@ -39,14 +39,36 @@ VersionKeyCreated = "ErigonVersionCreated" VersionKeyFinished = "ErigonVersionFinished" )   +// OPVersion is the version of op-geth +var ( + OPVersionMajor = 1 // Major version component of the current release + OPVersionMinor = 0 // Minor version component of the current release + OPVersionMicro = 1 // Patch version component of the current release + OPVersionModifier = "unstable" // Version metadata to append to the version string +) + // Version holds the textual version string. var Version = func() string { - return fmt.Sprintf("%d.%02d.%d", VersionMajor, VersionMinor, VersionMicro) + return fmt.Sprintf("%d.%02d.%d", OPVersionMajor, OPVersionMinor, OPVersionMicro) }()   // VersionWithMeta holds the textual version string including the metadata. var VersionWithMeta = func() string { v := Version + if OPVersionModifier != "" { + v += "-" + OPVersionModifier + } + return v +}() + +// ErigonVersion holds the textual erigon version string. +var ErigonVersion = func() string { + return fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionMicro) +}() + +// ErigonVersionWithMeta holds the textual erigon version string including the metadata. +var ErigonVersionWithMeta = func() string { + v := ErigonVersion if VersionModifier != "" { v += "-" + VersionModifier }
diff --git ledgerwatch/erigon/eth/ethconfig/config.go bobanetwork/v3-erigon/eth/ethconfig/config.go index a66e54cf44f8459226b79c7616ed7e3b2501e74d..c83e8c45cf495f10b1d2144548dd0965fa3791d2 100644 --- ledgerwatch/erigon/eth/ethconfig/config.go +++ bobanetwork/v3-erigon/eth/ethconfig/config.go @@ -51,13 +51,14 @@ //const HistoryV3AggregationStep = 3_125_000 / 100 // use this to reduce step size for dev/debug   // FullNodeGPO contains default gasprice oracle settings for full node. var FullNodeGPO = gaspricecfg.Config{ - Blocks: 20, - Default: big.NewInt(0), - Percentile: 60, - MaxHeaderHistory: 0, - MaxBlockHistory: 0, - MaxPrice: gaspricecfg.DefaultMaxPrice, - IgnorePrice: gaspricecfg.DefaultIgnorePrice, + Blocks: 20, + Default: big.NewInt(0), + Percentile: 60, + MaxHeaderHistory: 0, + MaxBlockHistory: 0, + MaxPrice: gaspricecfg.DefaultMaxPrice, + IgnorePrice: gaspricecfg.DefaultIgnorePrice, + MinSuggestedPriorityFee: gaspricecfg.DefaultMinSuggestedPriorityFee, }   // LightClientGPO contains default gasprice oracle settings for light client. @@ -246,16 +247,24 @@ LightClientDiscoveryTCPPort uint64 SentinelAddr string SentinelPort uint64   - OverrideCancunTime *big.Int `toml:",omitempty"` - ForcePartialCommit bool   + OverrideCancunTime *big.Int `toml:",omitempty"` + OverrideShanghaiTime *big.Int `toml:",omitempty"` + + OverrideOptimismCanyonTime *big.Int `toml:",omitempty"` + OverrideOptimismEcotoneTime *big.Int `toml:",omitempty"` + // Embedded Silkworm support SilkwormExecution bool SilkwormRpcDaemon bool SilkwormSentry bool   DisableTxPoolGossip bool + + RollupSequencerHTTP string + RollupHistoricalRPC string + RollupHistoricalRPCTimeout time.Duration }   type Sync struct {
diff --git ledgerwatch/erigon/params/config.go bobanetwork/v3-erigon/params/config.go index dc0c2c8add654a2194d7a29366969dd9d0fdc17c..5699aada5d7a24b6bb3d4eefbcf92079b5c339ad 100644 --- ledgerwatch/erigon/params/config.go +++ bobanetwork/v3-erigon/params/config.go @@ -72,6 +72,12 @@ BorMainnetGenesisHash = libcommon.HexToHash("0xa9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b") BorDevnetGenesisHash = libcommon.HexToHash("0x5a06b25b0c6530708ea0b98a3409290e39dce6be7f558493aeb6e4b99a172a87") GnosisGenesisHash = libcommon.HexToHash("0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756") ChiadoGenesisHash = libcommon.HexToHash("0xada44fd8d2ecab8b08f256af07ad3e777f17fb434f8f8e678b312f576212ba9a") + + OPMainnetGenesisHash = libcommon.HexToHash("0x7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b") + OPGoerliGenesisHash = libcommon.HexToHash("0xc1fc15cd51159b1f1e5cbc4b82e85c1447ddfa33c52cf1d98d14fba0d6354be1") + OPSepoliaGenesisHash = libcommon.HexToHash("0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d") + + BobaSepoliaGenesisHash = libcommon.HexToHash("0xc6171953a6a376ece6e33149686044f24f58a387ce2636a54e391d330b2326b5") )   var ( @@ -179,7 +185,37 @@ LondonBlock: big.NewInt(0), Aura: &chain.AuRaConfig{}, }   + TestOptimismChainConfig = &chain.Config{ + ChainID: big.NewInt(1337), + Consensus: chain.EtHashConsensus, + HomesteadBlock: big.NewInt(0), + TangerineWhistleBlock: big.NewInt(0), + SpuriousDragonBlock: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(0), + MuirGlacierBlock: big.NewInt(0), + BerlinBlock: big.NewInt(0), + Ethash: new(chain.EthashConfig), + Optimism: &chain.OptimismConfig{ + EIP1559Elasticity: 8, + EIP1559Denominator: 1, + }, + BedrockBlock: big.NewInt(1000000000000000000), + } + TestRules = TestChainConfig.Rules(0, 0) + + // This is an Optimism chain config with bedrock starting a block 5, introduced for historical endpoint testing, largely based on the clique config + OptimismTestConfig = func() *chain.Config { + conf := *AllCliqueProtocolChanges // copy the config + conf.Clique = nil + conf.TerminalTotalDifficultyPassed = true + conf.BedrockBlock = big.NewInt(5) + conf.Optimism = &chain.OptimismConfig{EIP1559Elasticity: 50, EIP1559Denominator: 10} + return &conf + }() )   type ConsensusSnapshotConfig struct { @@ -257,12 +293,30 @@ case networkname.GnosisChainName: return &GnosisGenesisHash case networkname.ChiadoChainName: return &ChiadoGenesisHash + case networkname.OPMainnetChainName: + // cannot use genesis hash from superchain registry because of pre-bedrock blocks + return &OPMainnetGenesisHash + case networkname.OPGoerliChainName: + // cannot use genesis has from superchain registry because of pre-bedrock blocks + return &OPGoerliGenesisHash + case networkname.OPSepoliaChainName: + return &OPSepoliaGenesisHash + case networkname.BobaSepoliaChainName: + // cannot use genesis hash from superchain registry because of pre-bedrock blocks + return &BobaSepoliaGenesisHash default: + if opStackChainCfg := OPStackChainConfigByName(chain); opStackChainCfg != nil { + genesisHash := libcommon.Hash(opStackChainCfg.Genesis.L2.Hash) + return &genesisHash + } return nil } }   func ChainConfigByGenesisHash(genesisHash libcommon.Hash) *chain.Config { + if cfg := ChainConfigByOpStackGenesisHash(genesisHash); cfg != nil { + return cfg + } switch { case genesisHash == MainnetGenesisHash: return MainnetChainConfig @@ -290,6 +344,9 @@ } }   func NetworkIDByChainName(chain string) uint64 { + if opStackChainCfg := OPStackChainConfigByName(chain); opStackChainCfg != nil { + return opStackChainCfg.ChainID + } config := ChainConfigByChainName(chain) if config == nil { return 0

Encode the Deposit Tx properties, the L1 costs, and daisy-chain RPC-calls for pre-Bedrock historical data

Pre-Bedrock L1-cost receipt data is loaded from the database if available, and post-Bedrock the L1-cost metadata is hydrated on-the-fly based on the L1 fee information in the corresponding block.

diff --git ledgerwatch/erigon/core/types/receipt.go bobanetwork/v3-erigon/core/types/receipt.go index e5689de13f026639e0f884e89215c7d3851ae156..f4764f1ad6575c31681409134e85918081dba582 100644 --- ledgerwatch/erigon/core/types/receipt.go +++ bobanetwork/v3-erigon/core/types/receipt.go @@ -20,18 +20,20 @@ import ( "bytes" "errors" "fmt" - "github.com/ledgerwatch/erigon-lib/common/hexutil" "io" "math/big"   + "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutil" "github.com/ledgerwatch/erigon-lib/common/hexutility" + "github.com/ledgerwatch/erigon-lib/opstack"   "github.com/ledgerwatch/erigon/crypto" "github.com/ledgerwatch/erigon/rlp" )   -// go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go +//go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go //go:generate codecgen -o receipt_codecgen_gen.go -r "^Receipts$|^Receipt$|^Logs$|^Log$" -st "codec" -j=false -nx=true -ta=true -oe=false -d 2 receipt.go log.go   var ( @@ -45,6 +47,9 @@ ReceiptStatusFailed = uint64(0)   // ReceiptStatusSuccessful is the status code of a transaction if execution succeeded. ReceiptStatusSuccessful = uint64(1) + + // The version number for post-canyon deposit receipts. + CanyonDepositReceiptVersion = uint64(1) )   // Receipt represents the results of a transaction. @@ -64,11 +69,30 @@ TxHash libcommon.Hash `json:"transactionHash" gencodec:"required" codec:"-"` ContractAddress libcommon.Address `json:"contractAddress" codec:"-"` GasUsed uint64 `json:"gasUsed" gencodec:"required" codec:"-"`   + // DepositNonce was introduced in Regolith to store the actual nonce used by deposit transactions + // The state transition process ensures this is only set for Regolith deposit transactions. + DepositNonce *uint64 `json:"depositNonce,omitempty"` + // The position of DepositNonce variable must NOT be changed. If changed, cbor decoding will fail + // for the data following previous struct and leading to decoding error(triggering backward imcompatibility). + + // Further fields when added must be appended after the last variable. Watch out for cbor. + // Inclusion information: These fields provide information about the inclusion of the // transaction corresponding to this receipt. BlockHash libcommon.Hash `json:"blockHash,omitempty" codec:"-"` BlockNumber *big.Int `json:"blockNumber,omitempty" codec:"-"` TransactionIndex uint `json:"transactionIndex" codec:"-"` + + // OVM legacy: extend receipts with their L1 price (if a rollup tx) + L1GasPrice *big.Int `json:"l1GasPrice,omitempty"` + L1GasUsed *big.Int `json:"l1GasUsed,omitempty"` + L1Fee *big.Int `json:"l1Fee,omitempty"` + FeeScalar *big.Float `json:"l1FeeScalar,omitempty"` // always nil after Ecotone hardfork + + // DepositReceiptVersion was introduced in Canyon to indicate an update to how receipt hashes + // should be computed when set. The state transition process ensures this is only set for + // post-Canyon deposit transactions. + DepositReceiptVersion *uint64 `json:"depositReceiptVersion,omitempty"` }   type receiptMarshaling struct { @@ -79,6 +103,14 @@ CumulativeGasUsed hexutil.Uint64 GasUsed hexutil.Uint64 BlockNumber *hexutil.Big TransactionIndex hexutil.Uint + + // Optimism + L1GasPrice *hexutil.Big + L1GasUsed *hexutil.Big + L1Fee *hexutil.Big + FeeScalar *big.Float + DepositNonce *hexutil.Uint64 + DepositReceiptVersion *hexutil.Uint64 }   // receiptRLP is the consensus encoding of a receipt. @@ -89,11 +121,32 @@ Bloom Bloom Logs []*Log }   +type depositReceiptRlp struct { + PostStateOrStatus []byte + CumulativeGasUsed uint64 + Bloom Bloom + Logs []*Log + // DepositNonce was introduced in Regolith to store the actual nonce used by deposit transactions. + // Must be nil for any transactions prior to Regolith or that aren't deposit transactions. + DepositNonce *uint64 `rlp:"optional"` + // Receipt hash post-Regolith but pre-Canyon inadvertently did not include the above + // DepositNonce. Post Canyon, receipts will have a non-empty DepositReceiptVersion indicating + // which post-Canyon receipt hash function to invoke. + DepositReceiptVersion *uint64 `rlp:"optional"` +} + // storedReceiptRLP is the storage encoding of a receipt. type storedReceiptRLP struct { PostStateOrStatus []byte CumulativeGasUsed uint64 Logs []*LogForStorage + // DepositNonce was introduced in Regolith to store the actual nonce used by deposit transactions. + // Must be nil for any transactions prior to Regolith or that aren't deposit transactions. + DepositNonce *uint64 `rlp:"optional"` + // Receipt hash post-Regolith but pre-Canyon inadvertently did not include the above + // DepositNonce. Post Canyon, receipts will have a non-empty DepositReceiptVersion indicating + // which post-Canyon receipt hash function to invoke. + DepositReceiptVersion *uint64 `rlp:"optional"` }   // v4StoredReceiptRLP is the storage encoding of a receipt used in database version 4. @@ -141,12 +194,30 @@ return rlp.Encode(w, data) } buf := new(bytes.Buffer) buf.WriteByte(r.Type) - if err := rlp.Encode(buf, data); err != nil { - return err + if r.Type == DepositTxType { + withNonceAndReceiptVersion := &depositReceiptRlp{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs, r.DepositNonce, r.DepositReceiptVersion} + if err := rlp.Encode(buf, withNonceAndReceiptVersion); err != nil { + return err + } + } else { + if err := rlp.Encode(buf, data); err != nil { + return err + } } return rlp.Encode(w, buf.Bytes()) }   +// encodeTyped writes the canonical encoding of a typed receipt to w. +func (r *Receipt) encodeTyped(data *receiptRLP, w *bytes.Buffer) error { + w.WriteByte(r.Type) + switch r.Type { + case DepositTxType: + withNonceAndReceiptVersion := depositReceiptRlp{data.PostStateOrStatus, data.CumulativeGasUsed, data.Bloom, data.Logs, r.DepositNonce, r.DepositReceiptVersion} + return rlp.Encode(w, withNonceAndReceiptVersion) + default: + return rlp.Encode(w, data) + } +} func (r *Receipt) decodePayload(s *rlp.Stream) error { _, err := s.List() if err != nil { @@ -215,6 +286,26 @@ } if err = s.ListEnd(); err != nil { return fmt.Errorf("close Logs: %w", err) } + if r.Type == DepositTxType { + depositNonce, err := s.Uint() + if err != nil { + if !errors.Is(err, rlp.EOL) { + return fmt.Errorf("read DepositNonce: %w", err) + } + return nil + } else { + r.DepositNonce = &depositNonce + } + depositReceiptVersion, err := s.Uint() + if err != nil { + if !errors.Is(err, rlp.EOL) { + return fmt.Errorf("read DepositReceiptVersion: %w", err) + } + return nil + } else { + r.DepositReceiptVersion = &depositReceiptVersion + } + } if err := s.ListEnd(); err != nil { return fmt.Errorf("close receipt payload: %w", err) } @@ -247,7 +338,7 @@ return fmt.Errorf("%w, got %d bytes", rlp.ErrWrongTxTypePrefix, len(b)) } r.Type = b[0] switch r.Type { - case AccessListTxType, DynamicFeeTxType, BlobTxType: + case AccessListTxType, DynamicFeeTxType, DepositTxType, BlobTxType: if err := r.decodePayload(s); err != nil { return err } @@ -302,21 +393,26 @@ txHash := libcommon.BytesToHash(r.TxHash.Bytes()) contractAddress := libcommon.BytesToAddress(r.ContractAddress.Bytes()) blockHash := libcommon.BytesToHash(r.BlockHash.Bytes()) - blockNumber := big.NewInt(0).Set(r.BlockNumber) + var blockNumber *big.Int + if r.BlockNumber != nil { + blockNumber = big.NewInt(0).Set(r.BlockNumber) + }   return &Receipt{ - Type: r.Type, - PostState: postState, - Status: r.Status, - CumulativeGasUsed: r.CumulativeGasUsed, - Bloom: bloom, - Logs: logs, - TxHash: txHash, - ContractAddress: contractAddress, - GasUsed: r.GasUsed, - BlockHash: blockHash, - BlockNumber: blockNumber, - TransactionIndex: r.TransactionIndex, + Type: r.Type, + PostState: postState, + Status: r.Status, + CumulativeGasUsed: r.CumulativeGasUsed, + Bloom: bloom, + Logs: logs, + TxHash: txHash, + ContractAddress: contractAddress, + GasUsed: r.GasUsed, + BlockHash: blockHash, + BlockNumber: blockNumber, + TransactionIndex: r.TransactionIndex, + DepositNonce: r.DepositNonce, + DepositReceiptVersion: r.DepositReceiptVersion, } }   @@ -330,9 +426,11 @@ // EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt // into an RLP stream. func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { enc := &storedReceiptRLP{ - PostStateOrStatus: (*Receipt)(r).statusEncoding(), - CumulativeGasUsed: r.CumulativeGasUsed, - Logs: make([]*LogForStorage, len(r.Logs)), + PostStateOrStatus: (*Receipt)(r).statusEncoding(), + CumulativeGasUsed: r.CumulativeGasUsed, + Logs: make([]*LogForStorage, len(r.Logs)), + DepositNonce: r.DepositNonce, + DepositReceiptVersion: r.DepositReceiptVersion, } for i, log := range r.Logs { enc.Logs[i] = (*LogForStorage)(log) @@ -374,7 +472,13 @@ for i, log := range stored.Logs { r.Logs[i] = (*Log)(log) } //r.Bloom = CreateBloom(Receipts{(*Receipt)(r)}) + if stored.DepositNonce != nil { + r.DepositNonce = stored.DepositNonce + }   + if stored.DepositReceiptVersion != nil { + r.DepositReceiptVersion = stored.DepositReceiptVersion + } return nil }   @@ -424,6 +528,9 @@ // Len returns the number of receipts in this list. func (rs Receipts) Len() int { return len(rs) }   // EncodeIndex encodes the i'th receipt to w. +// During post-regolith and pre-Canyon, DepositNonce was not included when encoding for hashing. +// Canyon adds DepositReceiptVersion to preserve backwards compatibility for pre-Canyon, and +// for correct receipt-root hash computation. func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) { r := rs[i] data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs} @@ -443,6 +550,19 @@ w.WriteByte(DynamicFeeTxType) if err := rlp.Encode(w, data); err != nil { panic(err) } + case DepositTxType: + w.WriteByte(DepositTxType) + if r.DepositReceiptVersion != nil { + // post-canyon receipt hash computation update + depositData := &depositReceiptRlp{data.PostStateOrStatus, data.CumulativeGasUsed, r.Bloom, r.Logs, r.DepositNonce, r.DepositReceiptVersion} + if err := rlp.Encode(w, depositData); err != nil { + panic(err) + } + } else { + if err := rlp.Encode(w, data); err != nil { + panic(err) + } + } case BlobTxType: w.WriteByte(BlobTxType) if err := rlp.Encode(w, data); err != nil { @@ -457,7 +577,7 @@ }   // DeriveFields fills the receipts with their computed fields based on consensus // data and contextual infos like containing block and transactions. -func (r Receipts) DeriveFields(hash libcommon.Hash, number uint64, txs Transactions, senders []libcommon.Address) error { +func (r Receipts) DeriveFields(config *chain.Config, hash libcommon.Hash, number uint64, time uint64, txs Transactions, senders []libcommon.Address) error { logIndex := uint(0) // logIdx is unique within the block and starts from 0 if len(txs) != len(r) { return fmt.Errorf("transaction and receipt count mismatch, tx count = %d, receipts count = %d", len(txs), len(r)) @@ -482,7 +602,11 @@ if txs[i].GetTo() == nil { // If one wants to deploy a contract, one needs to send a transaction that does not have `To` field // and then the address of the contract one is creating this way will depend on the `tx.From` // and the nonce of the creating account (which is `tx.From`). - r[i].ContractAddress = crypto.CreateAddress(senders[i], txs[i].GetNonce()) + nonce := txs[i].GetNonce() + if r[i].DepositNonce != nil { + nonce = *r[i].DepositNonce + } + r[i].ContractAddress = crypto.CreateAddress(senders[i], nonce) } // The used gas can be calculated based on previous r if i == 0 { @@ -498,6 +622,24 @@ r[i].Logs[j].TxHash = r[i].TxHash r[i].Logs[j].TxIndex = uint(i) r[i].Logs[j].Index = logIndex logIndex++ + } + } + if config.IsOptimismBedrock(number) && len(txs) >= 2 { // need at least an info tx and a non-info tx + l1Basefee, costFunc, feeScalar, err := opstack.ExtractL1GasParams(config, time, txs[0].GetData()) + if err != nil { + return err + } + for i := 0; i < len(r); i++ { + if txs[i].Type() == DepositTxType { + continue + } + r[i].L1GasPrice = l1Basefee.ToBig() + l1Fee, l1GasUsed := costFunc(txs[i].RollupCostData()) + r[i].L1Fee = l1Fee.ToBig() + r[i].L1GasUsed = l1GasUsed.ToBig() + if feeScalar != nil { + r[i].FeeScalar = feeScalar + } } } return nil
diff --git ledgerwatch/erigon/core/types/receipt_test.go bobanetwork/v3-erigon/core/types/receipt_test.go index 4eb2f1a9d6713a93026f48c08b38932184664c40..a7d26387dc30782eabf0e32f4de8bab969146cff 100644 --- ledgerwatch/erigon/core/types/receipt_test.go +++ bobanetwork/v3-erigon/core/types/receipt_test.go @@ -19,13 +19,17 @@ import ( "bytes" "errors" + "fmt" "math" "math/big" "reflect" "testing" + + "github.com/ledgerwatch/erigon-lib/chain"   "github.com/holiman/uint256" libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/stretchr/testify/require"   "github.com/ledgerwatch/erigon/common" "github.com/ledgerwatch/erigon/common/u256" @@ -34,6 +38,136 @@ "github.com/ledgerwatch/erigon/params" "github.com/ledgerwatch/erigon/rlp" )   +var ( + ecotoneTestConfig = func() *chain.Config { + conf := *params.OptimismTestConfig // copy the config + conf.EcotoneTime = big.NewInt(0) + return &conf + }() + depNonce1 = uint64(7) + depNonce2 = uint64(8) + blockNumber = big.NewInt(5) + blockTime = uint64(10) + blockHash = libcommon.BytesToHash([]byte{0x03, 0x14}) + legacyReceipt = &Receipt{ + Status: ReceiptStatusFailed, + CumulativeGasUsed: 1, + Logs: []*Log{ + { + Address: libcommon.BytesToAddress([]byte{0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + { + Address: libcommon.BytesToAddress([]byte{0x01, 0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + }, + } + accessListReceipt = &Receipt{ + Status: ReceiptStatusFailed, + CumulativeGasUsed: 1, + Logs: []*Log{ + { + Address: libcommon.BytesToAddress([]byte{0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + { + Address: libcommon.BytesToAddress([]byte{0x01, 0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + }, + Type: AccessListTxType, + } + eip1559Receipt = &Receipt{ + Status: ReceiptStatusFailed, + CumulativeGasUsed: 1, + Logs: []*Log{ + { + Address: libcommon.BytesToAddress([]byte{0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + { + Address: libcommon.BytesToAddress([]byte{0x01, 0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + }, + Type: DynamicFeeTxType, + } + depositReceiptNoNonce = &Receipt{ + Status: ReceiptStatusFailed, + CumulativeGasUsed: 1, + Logs: []*Log{ + { + Address: libcommon.BytesToAddress([]byte{0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + { + Address: libcommon.BytesToAddress([]byte{0x01, 0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + }, + Type: DepositTxType, + } + nonce = uint64(1234) + depositReceiptWithNonce = &Receipt{ + Status: ReceiptStatusFailed, + CumulativeGasUsed: 1, + DepositNonce: &nonce, + DepositReceiptVersion: nil, + Logs: []*Log{ + { + Address: libcommon.BytesToAddress([]byte{0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + { + Address: libcommon.BytesToAddress([]byte{0x01, 0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + }, + Type: DepositTxType, + } + version = CanyonDepositReceiptVersion + depositReceiptWithNonceAndVersion = &Receipt{ + Status: ReceiptStatusFailed, + CumulativeGasUsed: 1, + DepositNonce: &nonce, + DepositReceiptVersion: &version, + Logs: []*Log{ + { + Address: libcommon.BytesToAddress([]byte{0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + { + Address: libcommon.BytesToAddress([]byte{0x01, 0x11}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + Data: []byte{0x01, 0x00, 0xff}, + }, + }, + Type: DepositTxType, + } + basefee = uint256.NewInt(1000 * 1e6) + scalar = uint256.NewInt(7 * 1e6) + + // below are the expected cost func outcomes for the above parameter settings on the emptyTx + // which is defined in transaction_test.go + bedrockFee = uint256.NewInt(11326000000000) + ecotoneFee = uint256.NewInt(960900) // (480/16)*(2*16*1000 + 3*10) == 960900 + + bedrockGas = uint256.NewInt(1618) + ecotoneGas = uint256.NewInt(480) +) + func TestDecodeEmptyTypedReceipt(t *testing.T) { t.Parallel() input := []byte{0x80} @@ -128,6 +262,54 @@ } return rlp.EncodeToBytes(stored) }   +func diffDerivedFields(t *testing.T, receipts Receipts, txs Transactions, blockHash libcommon.Hash, blockNumber *big.Int) { + logIndex := uint(0) + for i := range receipts { + if receipts[i].Type != txs[i].Type() { + t.Errorf("receipts[%d].Type = %d, want %d", i, receipts[i].Type, txs[i].Type()) + } + if receipts[i].TxHash != txs[i].Hash() { + t.Errorf("receipts[%d].TxHash = %s, want %s", i, receipts[i].TxHash.String(), txs[i].Hash().String()) + } + if receipts[i].BlockHash != blockHash { + t.Errorf("receipts[%d].BlockHash = %s, want %s", i, receipts[i].BlockHash.String(), blockHash.String()) + } + if receipts[i].BlockNumber.Cmp(blockNumber) != 0 { + t.Errorf("receipts[%c].BlockNumber = %s, want %s", i, receipts[i].BlockNumber.String(), blockNumber.String()) + } + if receipts[i].TransactionIndex != uint(i) { + t.Errorf("receipts[%d].TransactionIndex = %d, want %d", i, receipts[i].TransactionIndex, i) + } + if receipts[i].GasUsed != txs[i].GetGas() { + t.Errorf("receipts[%d].GasUsed = %d, want %d", i, receipts[i].GasUsed, txs[i].GetGas()) + } + if txs[i].GetTo() != nil && receipts[i].ContractAddress != (libcommon.Address{}) { + t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), (libcommon.Address{}).String()) + } + for j := range receipts[i].Logs { + if receipts[i].Logs[j].BlockNumber != blockNumber.Uint64() { + t.Errorf("receipts[%d].Logs[%d].BlockNumber = %d, want %d", i, j, receipts[i].Logs[j].BlockNumber, blockNumber.Uint64()) + } + if receipts[i].Logs[j].BlockHash != blockHash { + t.Errorf("receipts[%d].Logs[%d].BlockHash = %s, want %s", i, j, receipts[i].Logs[j].BlockHash.String(), blockHash.String()) + } + if receipts[i].Logs[j].TxHash != txs[i].Hash() { + t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String()) + } + if receipts[i].Logs[j].TxHash != txs[i].Hash() { + t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String()) + } + if receipts[i].Logs[j].TxIndex != uint(i) { + t.Errorf("receipts[%d].Logs[%d].TransactionIndex = %d, want %d", i, j, receipts[i].Logs[j].TxIndex, i) + } + if receipts[i].Logs[j].Index != logIndex { + t.Errorf("receipts[%d].Logs[%d].Index = %d, want %d", i, j, receipts[i].Logs[j].Index, logIndex) + } + logIndex++ + } + } +} + // Tests that receipt data can be correctly derived from the contextual infos func TestDeriveFields(t *testing.T) { t.Parallel() @@ -163,7 +345,21 @@ }, GasPrice: uint256.NewInt(3), }, }, + &DepositTx{ + Value: uint256.NewInt(3), + From: libcommon.Address{}, + Gas: 4, + }, + &DepositTx{ + From: libcommon.Address{}, + To: nil, // contract creation + Value: uint256.NewInt(6), + Gas: 5, + }, } + depNonce := uint64(7) + depNonce2 := uint64(8) + canyonDepositReceiptVersion := CanyonDepositReceiptVersion // Create the corresponding receipts receipts := Receipts{ &Receipt{ @@ -200,66 +396,86 @@ TxHash: txs[2].Hash(), ContractAddress: libcommon.BytesToAddress([]byte{0x03, 0x33, 0x33}), GasUsed: 3, }, + &Receipt{ + Type: DepositTxType, + PostState: libcommon.Hash{3}.Bytes(), + CumulativeGasUsed: 10, + Logs: []*Log{ + {Address: libcommon.BytesToAddress([]byte{0x33})}, + {Address: libcommon.BytesToAddress([]byte{0x03, 0x33})}, + }, + TxHash: txs[3].Hash(), + ContractAddress: libcommon.BytesToAddress([]byte{0x03, 0x33, 0x33}), + GasUsed: 4, + BlockHash: libcommon.BytesToHash([]byte{0x03, 0x14}), + BlockNumber: big.NewInt(1), + TransactionIndex: 7, + DepositNonce: &depNonce, + DepositReceiptVersion: nil, + }, + &Receipt{ + Type: DepositTxType, + PostState: libcommon.Hash{5}.Bytes(), + CumulativeGasUsed: 15, + Logs: []*Log{ + { + Address: libcommon.BytesToAddress([]byte{0x33}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + // derived fields: + BlockNumber: big.NewInt(1).Uint64(), + TxHash: txs[4].Hash(), + TxIndex: 4, + BlockHash: libcommon.BytesToHash([]byte{0x03, 0x14}), + Index: 4, + }, + { + Address: libcommon.BytesToAddress([]byte{0x03, 0x33}), + Topics: []libcommon.Hash{libcommon.HexToHash("dead"), libcommon.HexToHash("beef")}, + // derived fields: + BlockNumber: big.NewInt(1).Uint64(), + TxHash: txs[4].Hash(), + TxIndex: 4, + BlockHash: libcommon.BytesToHash([]byte{0x03, 0x14}), + Index: 5, + }, + }, + TxHash: txs[4].Hash(), + ContractAddress: libcommon.HexToAddress("0x3bb898b4bbe24f68a4e9be46cfe72d1787fd74f4"), + GasUsed: 5, + BlockHash: libcommon.BytesToHash([]byte{0x03, 0x14}), + BlockNumber: big.NewInt(1), + TransactionIndex: 4, + DepositNonce: &depNonce2, + DepositReceiptVersion: &canyonDepositReceiptVersion, + }, + } + + nonces := []uint64{ + txs[0].GetNonce(), + txs[1].GetNonce(), + txs[2].GetNonce(), + // Deposit tx should use deposit nonce + *receipts[3].DepositNonce, + *receipts[4].DepositNonce, } // Clear all the computed fields and re-derive them number := big.NewInt(1) hash := libcommon.BytesToHash([]byte{0x03, 0x14}) + time := uint64(0)   clearComputedFieldsOnReceipts(t, receipts) - if err := receipts.DeriveFields(hash, number.Uint64(), txs, []libcommon.Address{libcommon.BytesToAddress([]byte{0x0}), libcommon.BytesToAddress([]byte{0x0}), libcommon.BytesToAddress([]byte{0x0})}); err != nil { + if err := receipts.DeriveFields(params.TestChainConfig, hash, number.Uint64(), time, txs, []libcommon.Address{libcommon.BytesToAddress([]byte{0x0}), libcommon.BytesToAddress([]byte{0x0}), libcommon.BytesToAddress([]byte{0x0}), libcommon.BytesToAddress([]byte{0x0}), libcommon.BytesToAddress([]byte{0x0})}); err != nil { t.Fatalf("DeriveFields(...) = %v, want <nil>", err) } // Iterate over all the computed fields and check that they're correct signer := MakeSigner(params.TestChainConfig, number.Uint64(), 0)   - logIndex := uint(0) + diffDerivedFields(t, receipts, txs, hash, number) for i := range receipts { - if receipts[i].Type != txs[i].Type() { - t.Errorf("receipts[%d].Type = %d, want %d", i, receipts[i].Type, txs[i].Type()) - } - if receipts[i].TxHash != txs[i].Hash() { - t.Errorf("receipts[%d].TxHash = %s, want %s", i, receipts[i].TxHash.String(), txs[i].Hash().String()) - } - if receipts[i].BlockHash != hash { - t.Errorf("receipts[%d].BlockHash = %s, want %s", i, receipts[i].BlockHash.String(), hash.String()) - } - if receipts[i].BlockNumber.Cmp(number) != 0 { - t.Errorf("receipts[%c].BlockNumber = %s, want %s", i, receipts[i].BlockNumber.String(), number.String()) - } - if receipts[i].TransactionIndex != uint(i) { - t.Errorf("receipts[%d].TransactionIndex = %d, want %d", i, receipts[i].TransactionIndex, i) - } - if receipts[i].GasUsed != txs[i].GetGas() { - t.Errorf("receipts[%d].GasUsed = %d, want %d", i, receipts[i].GasUsed, txs[i].GetGas()) - } - if txs[i].GetTo() != nil && receipts[i].ContractAddress != (libcommon.Address{}) { - t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), (libcommon.Address{}).String()) - } from, _ := txs[i].Sender(*signer) - contractAddress := crypto.CreateAddress(from, txs[i].GetNonce()) + contractAddress := crypto.CreateAddress(from, nonces[i]) if txs[i].GetTo() == nil && receipts[i].ContractAddress != contractAddress { t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), contractAddress.String()) - } - for j := range receipts[i].Logs { - if receipts[i].Logs[j].BlockNumber != number.Uint64() { - t.Errorf("receipts[%d].Logs[%d].BlockNumber = %d, want %d", i, j, receipts[i].Logs[j].BlockNumber, number.Uint64()) - } - if receipts[i].Logs[j].BlockHash != hash { - t.Errorf("receipts[%d].Logs[%d].BlockHash = %s, want %s", i, j, receipts[i].Logs[j].BlockHash.String(), hash.String()) - } - if receipts[i].Logs[j].TxHash != txs[i].Hash() { - t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String()) - } - if receipts[i].Logs[j].TxHash != txs[i].Hash() { - t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String()) - } - if receipts[i].Logs[j].TxIndex != uint(i) { - t.Errorf("receipts[%d].Logs[%d].TransactionIndex = %d, want %d", i, j, receipts[i].Logs[j].TxIndex, i) - } - if receipts[i].Logs[j].Index != logIndex { - t.Errorf("receipts[%d].Logs[%d].Index = %d, want %d", i, j, receipts[i].Logs[j].Index, logIndex) - } - logIndex++ } } } @@ -333,3 +549,331 @@ log.TxHash = libcommon.Hash{} log.TxIndex = math.MaxUint32 log.Index = math.MaxUint32 } + +func TestBedrockDepositReceiptUnchanged(t *testing.T) { + expectedRlp := common.FromHex("B9015a7EF90156A003000000000000000000000000000000000000000000000000000000000000000AB9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F0D7940000000000000000000000000000000000000033C001D7940000000000000000000000000000000000000333C002") + // Deposit receipt with no nonce + receipt := &Receipt{ + Type: DepositTxType, + PostState: libcommon.Hash{3}.Bytes(), + CumulativeGasUsed: 10, + Logs: []*Log{ + {Address: libcommon.BytesToAddress([]byte{0x33}), Data: []byte{1}, Topics: nil}, + {Address: libcommon.BytesToAddress([]byte{0x03, 0x33}), Data: []byte{2}, Topics: nil}, + }, + TxHash: libcommon.Hash{}, + ContractAddress: libcommon.BytesToAddress([]byte{0x03, 0x33, 0x33}), + GasUsed: 4, + } + + encodedRlp, err := rlp.EncodeToBytes(receipt) + require.NoError(t, err) + require.Equal(t, expectedRlp, encodedRlp) + + // Consensus values should be unchanged after reparsing + parsed := new(Receipt) + err = rlp.DecodeBytes(encodedRlp, parsed) + require.NoError(t, err) + require.Equal(t, receipt.Status, parsed.Status) + require.Equal(t, receipt.CumulativeGasUsed, parsed.CumulativeGasUsed) + require.Equal(t, receipt.Bloom, parsed.Bloom) + require.Equal(t, len(receipt.Logs), len(parsed.Logs)) + for i := 0; i < len(receipt.Logs); i++ { + require.EqualValues(t, receipt.Logs[i], parsed.Logs[i]) + } + // And still shouldn't have a nonce + require.Nil(t, parsed.DepositNonce) + // ..or a deposit nonce + require.Nil(t, parsed.DepositReceiptVersion) +} + +// Regolith did not include deposit nonce during receipt root construction. +// TestReceiptEncodeIndexBugIsEnshrined makes sure this difference is preserved for backwards +// compatibility purposes, but also that there is no discrepancy for the post-Canyon encoding. +func TestReceiptEncodeIndexBugIsEnshrined(t *testing.T) { + // Check that a post-Regolith, pre-Canyon receipt produces no difference between + // receipts having different depositNonce + buf := new(bytes.Buffer) + receipts := Receipts{depositReceiptWithNonce.Copy()} + receipts.EncodeIndex(0, buf) + indexBytesBefore := buf.Bytes() + + buf2 := new(bytes.Buffer) + newDepositNonce := *receipts[0].DepositNonce + 1 + receipts[0].DepositNonce = &newDepositNonce + receipts.EncodeIndex(0, buf2) + indexBytesAfter := buf2.Bytes() + + require.Equal(t, indexBytesBefore, indexBytesAfter) + + // Confirm the buggy encoding is as expected, which means it should encode as if it had no + // nonce specified (like that of a non-deposit receipt, whose encoding would differ only in the + // type byte). + buf3 := new(bytes.Buffer) + receipts[0].Type = eip1559Receipt.Type + receipts.EncodeIndex(0, buf3) + indexBytesNoDeposit := buf3.Bytes() + + require.NotEqual(t, indexBytesBefore[0], indexBytesNoDeposit[0]) + require.Equal(t, indexBytesBefore[1:], indexBytesNoDeposit[1:]) + + // Check that post-canyon changes the hash compared to pre-Canyon + buf4 := new(bytes.Buffer) + receipts = Receipts{depositReceiptWithNonceAndVersion.Copy()} + receipts.EncodeIndex(0, buf4) + indexBytesCanyon := buf4.Bytes() + require.NotEqual(t, indexBytesBefore[1:], indexBytesCanyon[1:]) + + // Check that bumping the nonce post-canyon changes the hash + buf5 := new(bytes.Buffer) + bumpedNonce := *depositReceiptWithNonceAndVersion.DepositNonce + 1 + receipts[0].DepositNonce = &bumpedNonce + receipts.EncodeIndex(0, buf5) + indexBytesCanyonBump := buf5.Bytes() + require.NotEqual(t, indexBytesCanyon[1:], indexBytesCanyonBump[1:]) +} + +func TestRoundTripReceipt(t *testing.T) { + tests := []struct { + name string + rcpt *Receipt + }{ + {name: "Legacy", rcpt: legacyReceipt}, + {name: "AccessList", rcpt: accessListReceipt}, + {name: "EIP1559", rcpt: eip1559Receipt}, + {name: "DepositNoNonce", rcpt: depositReceiptNoNonce}, + {name: "DepositWithNonce", rcpt: depositReceiptWithNonce}, + {name: "DepositWithNonceAndVersion", rcpt: depositReceiptWithNonceAndVersion}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + data, err := rlp.EncodeToBytes(test.rcpt) + require.NoError(t, err) + + d := &Receipt{} + err = rlp.DecodeBytes(data, d) + require.NoError(t, err) + require.Equal(t, test.rcpt, d) + require.Equal(t, test.rcpt.DepositNonce, d.DepositNonce) + require.Equal(t, test.rcpt.DepositReceiptVersion, d.DepositReceiptVersion) + }) + + t.Run(fmt.Sprintf("%sRejectExtraData", test.name), func(t *testing.T) { + data, err := rlp.EncodeToBytes(test.rcpt) + require.NoError(t, err) + data = append(data, 1, 2, 3, 4) + d := &Receipt{} + err = rlp.DecodeBytes(data, d) + require.Error(t, err) + }) + } +} + +func TestRoundTripReceiptForStorage(t *testing.T) { + tests := []struct { + name string + rcpt *Receipt + }{ + {name: "Legacy", rcpt: legacyReceipt}, + {name: "AccessList", rcpt: accessListReceipt}, + {name: "EIP1559", rcpt: eip1559Receipt}, + {name: "DepositNoNonce", rcpt: depositReceiptNoNonce}, + {name: "DepositWithNonce", rcpt: depositReceiptWithNonce}, + {name: "DepositWithNonceAndVersion", rcpt: depositReceiptWithNonceAndVersion}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + data, err := rlp.EncodeToBytes((*ReceiptForStorage)(test.rcpt)) + require.NoError(t, err) + + d := &ReceiptForStorage{} + err = rlp.DecodeBytes(data, d) + require.NoError(t, err) + // Only check the stored fields - the others are derived later + require.Equal(t, test.rcpt.Status, d.Status) + require.Equal(t, test.rcpt.CumulativeGasUsed, d.CumulativeGasUsed) + require.Equal(t, test.rcpt.Logs, d.Logs) + require.Equal(t, test.rcpt.DepositNonce, d.DepositNonce) + require.Equal(t, test.rcpt.DepositReceiptVersion, d.DepositReceiptVersion) + }) + } +} + +func TestReceiptJSON(t *testing.T) { + tests := []struct { + name string + rcpt *Receipt + }{ + {name: "Legacy", rcpt: legacyReceipt}, + {name: "AccessList", rcpt: accessListReceipt}, + {name: "EIP1559", rcpt: eip1559Receipt}, + {name: "DepositNoNonce", rcpt: depositReceiptNoNonce}, + {name: "DepositWithNonce", rcpt: depositReceiptWithNonce}, + {name: "DepositWithNonceAndVersion", rcpt: depositReceiptWithNonceAndVersion}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + b, err := test.rcpt.MarshalJSON() + if err != nil { + t.Fatal("error marshaling receipt to json:", err) + } + r := Receipt{} + err = r.UnmarshalJSON(b) + if err != nil { + t.Fatal("error unmarshaling receipt from json:", err) + } + + // Make sure marshal/unmarshal doesn't affect receipt hash root computation by comparing + // the output of EncodeIndex + rsBefore := Receipts([]*Receipt{test.rcpt}) + rsAfter := Receipts([]*Receipt{&r}) + + encBefore, encAfter := bytes.Buffer{}, bytes.Buffer{} + rsBefore.EncodeIndex(0, &encBefore) + rsAfter.EncodeIndex(0, &encAfter) + if !bytes.Equal(encBefore.Bytes(), encAfter.Bytes()) { + t.Errorf("%v: EncodeIndex differs after JSON marshal/unmarshal", test.name) + } + }) + } +} + +// This method is based on op-geth +// https://github.com/ethereum-optimism/op-geth/commit/a290ca164a36c80a8d106d88bd482b6f82220bef +func getOptimismTxReceipts( + t *testing.T, l1AttributesPayload []byte, + l1GasPrice, l1GasUsed *uint256.Int, feeScalar *big.Float, l1Fee *uint256.Int) (Transactions, Receipts) { + //to4 := common.HexToAddress("0x4") + // Create a few transactions to have receipts for + txs := Transactions{ + &DepositTx{ + To: nil, // contract creation + Value: uint256.NewInt(6), + Gas: 50, + Data: l1AttributesPayload, + }, + emptyTx, + } + + // Create the corresponding receipts + receipts := Receipts{ + &Receipt{ + Type: DepositTxType, + PostState: libcommon.Hash{5}.Bytes(), + CumulativeGasUsed: 50, + Logs: []*Log{ + { + Address: libcommon.BytesToAddress([]byte{0x33}), + // derived fields: + BlockNumber: blockNumber.Uint64(), + TxHash: txs[0].Hash(), + TxIndex: 0, + BlockHash: blockHash, + Index: 0, + }, + { + Address: libcommon.BytesToAddress([]byte{0x03, 0x33}), + // derived fields: + BlockNumber: blockNumber.Uint64(), + TxHash: txs[0].Hash(), + TxIndex: 0, + BlockHash: blockHash, + Index: 1, + }, + }, + TxHash: txs[0].Hash(), + ContractAddress: libcommon.HexToAddress("0x3bb898b4bbe24f68a4e9be46cfe72d1787fd74f4"), + GasUsed: 50, + BlockHash: blockHash, + BlockNumber: blockNumber, + TransactionIndex: 0, + DepositNonce: &depNonce1, + }, + &Receipt{ + Type: LegacyTxType, + PostState: libcommon.Hash{4}.Bytes(), + CumulativeGasUsed: 50, + Logs: []*Log{}, + // derived fields: + TxHash: txs[1].Hash(), + GasUsed: 0, + BlockHash: blockHash, + BlockNumber: blockNumber, + TransactionIndex: 1, + L1GasPrice: l1GasPrice.ToBig(), + L1GasUsed: l1GasUsed.ToBig(), + L1Fee: l1Fee.ToBig(), + FeeScalar: feeScalar, + }, + } + return txs, receipts +} + +// This method is based on op-geth +// https://github.com/ethereum-optimism/op-geth/commit/a290ca164a36c80a8d106d88bd482b6f82220bef +func checkBedrockReceipts(t *testing.T, receipts Receipts, txs Transactions, blockHash libcommon.Hash, blockNumber *big.Int) { + diffDerivedFields(t, receipts, txs, blockHash, blockNumber) + + // Check that we preserved the invariant: l1Fee = l1GasPrice * l1GasUsed * l1FeeScalar + // but with more difficult int math... + l2Rcpt := receipts[1] + l1GasCost := new(big.Int).Mul(l2Rcpt.L1GasPrice, l2Rcpt.L1GasUsed) + l1Fee := new(big.Float).Mul(new(big.Float).SetInt(l1GasCost), l2Rcpt.FeeScalar) + require.Equal(t, new(big.Float).SetInt(l2Rcpt.L1Fee), l1Fee) +} + +// This test is based on op-geth +// https://github.com/ethereum-optimism/op-geth/commit/a290ca164a36c80a8d106d88bd482b6f82220bef +func TestDeriveOptimismBedrockTxReceipts(t *testing.T) { + // Bedrock style l1 attributes with L1Scalar=7_000_000 (becomes 7 after division), L1Overhead=50, L1BaseFee=1000*1e6 + payload := libcommon.Hex2Bytes("015d8eb900000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d2000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d2000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000006acfc0015d8eb900000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d2000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d2000000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000006acfc0") + l1GasPrice := basefee + l1GasUsed := bedrockGas + feeScalar := big.NewFloat(float64(scalar.Uint64() / 1e6)) + l1Fee := bedrockFee + txs, receipts := getOptimismTxReceipts(t, payload, l1GasPrice, l1GasUsed, feeScalar, l1Fee) + senders := []libcommon.Address{libcommon.HexToAddress("0x0"), libcommon.HexToAddress("0x0")} + + // Re-derive receipts. + clearComputedFieldsOnReceipts(t, receipts) + err := receipts.DeriveFields(params.OptimismTestConfig, blockHash, blockNumber.Uint64(), blockTime, txs, senders) + if err != nil { + t.Fatalf("DeriveFields(...) = %v, want <nil>", err) + } + checkBedrockReceipts(t, receipts, txs, blockHash, blockNumber) + + // Should get same result with the Ecotone config because it will assume this is "first ecotone block" + // if it sees the bedrock style L1 attributes. + clearComputedFieldsOnReceipts(t, receipts) + err = receipts.DeriveFields(ecotoneTestConfig, blockHash, blockNumber.Uint64(), blockTime, txs, senders) + if err != nil { + t.Fatalf("DeriveFields(...) = %v, want <nil>", err) + } + checkBedrockReceipts(t, receipts, txs, blockHash, blockNumber) +} + +// This test is based on op-geth +// https://github.com/ethereum-optimism/op-geth/commit/a290ca164a36c80a8d106d88bd482b6f82220bef +func TestDeriveOptimismEcotoneTxReceipts(t *testing.T) { + // Ecotone style l1 attributes with baseFeeScalar=2, blobBaseFeeScalar=3, baseFee=1000*1e6, blobBaseFee=10*1e6 + payload := libcommon.Hex2Bytes("440a5e20000000020000000300000000000004d200000000000004d200000000000004d2000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000000098968000000000000000000000000000000000000000000000000000000000000004d200000000000000000000000000000000000000000000000000000000000004d2") + l1GasPrice := basefee + l1GasUsed := ecotoneGas + l1Fee := ecotoneFee + txs, receipts := getOptimismTxReceipts(t, payload, l1GasPrice, l1GasUsed, nil /*feeScalar*/, l1Fee) + senders := []libcommon.Address{libcommon.HexToAddress("0x0"), libcommon.HexToAddress("0x0")} + + // Re-derive receipts. + clearComputedFieldsOnReceipts(t, receipts) + err := receipts.DeriveFields(params.OptimismTestConfig, blockHash, blockNumber.Uint64(), blockTime, txs, senders) + if err == nil { + t.Fatalf("expected error from deriving ecotone receipts with pre-ecotone config, got none") + } + + clearComputedFieldsOnReceipts(t, receipts) + err = receipts.DeriveFields(ecotoneTestConfig, blockHash, blockNumber.Uint64(), blockTime, txs, senders) + if err != nil { + t.Fatalf("DeriveFields(...) = %v, want <nil>", err) + } + diffDerivedFields(t, receipts, txs, blockHash, blockNumber) +}
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_receipts.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_receipts.go index 6567e6e3c82c1b05329326e3be7f0d2f9ed9fb2b..2835ac782248f81e9aac8b1ddd7c5e4926031592 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_receipts.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_receipts.go @@ -5,8 +5,10 @@ "bytes" "context" "encoding/binary" "fmt" - "github.com/ledgerwatch/erigon-lib/common/hexutil" "math/big" + + "github.com/ledgerwatch/erigon-lib/common/hexutil" + "github.com/ledgerwatch/erigon-lib/opstack"   "github.com/RoaringBitmap/roaring" "github.com/holiman/uint256" @@ -40,7 +42,7 @@ const PendingBlockNumber int64 = -2   func (api *BaseAPI) getReceipts(ctx context.Context, tx kv.Tx, chainConfig *chain.Config, block *types.Block, senders []common.Address) (types.Receipts, error) { - if cached := rawdb.ReadReceipts(tx, block, senders); cached != nil { + if cached := rawdb.ReadReceipts(chainConfig, tx, block, senders); cached != nil { return cached, nil } engine := api.engine() @@ -69,6 +71,7 @@ header := block.Header() for i, txn := range block.Transactions() { ibs.SetTxContext(txn.Hash(), block.Hash(), i) receipt, _, err := core.ApplyTransaction(chainConfig, core.GetHashFn(header, getHeader), engine, nil, gp, ibs, noopWriter, header, txn, usedGas, usedBlobGas, vm.Config{}) + log.Debug("Computed receipt for tx", "txhash", txn.Hash(), "l1Fee", receipt.L1Fee) if err != nil { return nil, err } @@ -533,6 +536,7 @@ func (e *intraBlockExec) changeBlock(header *types.Header) { e.blockNum = header.Number.Uint64() blockCtx := transactions.NewEVMBlockContext(e.engine, header, true /* requireCanonical */, e.tx, e.br) + blockCtx.L1CostFunc = opstack.NewL1CostFunc(e.chainConfig, e.ibs) e.blockCtx = &blockCtx e.blockHash = header.Hash() e.header = header @@ -743,6 +747,9 @@ case *types.LegacyTx: if t.Protected() { chainId = types.DeriveChainId(&t.V).ToBig() } + case *types.DepositTx: + // Deposit TX does not have chain ID + chainId = chainConfig.ChainID default: chainId = txn.GetChainID().ToBig() } @@ -767,7 +774,6 @@ "contractAddress": nil, "logs": receipt.Logs, "logsBloom": types.CreateBloom(types.Receipts{receipt}), } - if !chainConfig.IsLondon(header.Number.Uint64()) { fields["effectiveGasPrice"] = hexutil.Uint64(txn.GetPrice().Uint64()) } else { @@ -784,6 +790,25 @@ // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation if receipt.ContractAddress != (common.Address{}) { fields["contractAddress"] = receipt.ContractAddress } + + if chainConfig.IsOptimism() { + if txn.Type() != types.DepositTxType { + fields["l1GasPrice"] = hexutil.Big(*receipt.L1GasPrice) + fields["l1GasUsed"] = hexutil.Big(*receipt.L1GasUsed) + fields["l1Fee"] = hexutil.Big(*receipt.L1Fee) + if receipt.FeeScalar != nil { // removed in Ecotone + fields["l1FeeScalar"] = receipt.FeeScalar + } + } else { + if receipt.DepositNonce != nil { + fields["depositNonce"] = hexutil.Uint64(*receipt.DepositNonce) + } + if receipt.DepositReceiptVersion != nil { + fields["depositReceiptVersion"] = hexutil.Uint64(*receipt.DepositReceiptVersion) + } + } + } + // Set derived blob related fields numBlobs := len(txn.GetBlobHashes()) if numBlobs > 0 {
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_receipts_test.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_receipts_test.go new file mode 100644 index 0000000000000000000000000000000000000000..91b3a96f05459e8f77c0a152ddfda9f9d65823bc --- /dev/null +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_receipts_test.go @@ -0,0 +1,153 @@ +package jsonrpc + +import ( + "context" + "math/big" + "testing" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/common" + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" + "github.com/ledgerwatch/erigon-lib/kv/memdb" + "github.com/ledgerwatch/erigon-lib/opstack" + "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" + "github.com/ledgerwatch/erigon/common/u256" + "github.com/ledgerwatch/erigon/core/rawdb" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/rpc/rpccfg" + "github.com/ledgerwatch/erigon/turbo/rpchelper" + "github.com/ledgerwatch/erigon/turbo/stages/mock" + "github.com/ledgerwatch/log/v3" + "github.com/stretchr/testify/require" +) + +func TestGetReceipts(t *testing.T) { + m, _, _ := rpcdaemontest.CreateOptimismTestSentry(t) + agg := m.HistoryV3Components() + stateCache := kvcache.New(kvcache.DefaultCoherentConfig) + ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, mock.Mock(t)) + mining := txpool.NewMiningClient(conn) + ff := rpchelper.New(ctx, nil, nil, mining, func() {}, m.Log) + api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + + db := memdb.New("") + defer db.Close() + + tx, err := db.BeginRw(context.Background()) + require.NoError(t, err) + defer tx.Rollback() + + header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} + block := types.NewBlockWithHeader(header) + + require.NoError(t, rawdb.WriteBlock(tx, block)) + require.NoError(t, rawdb.WriteReceipts(tx, block.NumberU64(), nil)) + tx.Commit() + + rTx, err := db.BeginRo(context.Background()) + require.NoError(t, err) + defer rTx.Rollback() + + receipt, err := api.getReceipts(m.Ctx, rTx, m.ChainConfig, block, []libcommon.Address{}) + require.NoError(t, err) + require.Equal(t, 0, len(receipt)) + + tx, err = db.BeginRw(context.Background()) + require.NoError(t, err) + defer tx.Rollback() + + var ( + bedrockBlock = common.Big0.Add(m.ChainConfig.BedrockBlock, big.NewInt(1)) + + l1BaseFee = uint256.NewInt(1000).Bytes32() + overhead = uint256.NewInt(100).Bytes32() + scalar = uint256.NewInt(100).Bytes32() + fscalar = new(big.Float).SetInt(new(uint256.Int).SetBytes(scalar[:]).ToBig()) + fdivisor = new(big.Float).SetUint64(1_000_000) + feeScalar = new(big.Float).Quo(fscalar, fdivisor) + ) + + systemTx := buildSystemTx(l1BaseFee, overhead, scalar) + + tx1 := types.NewTransaction(1, libcommon.HexToAddress("0x1"), u256.Num1, 1, u256.Num1, systemTx) + tx2 := types.NewTransaction(2, libcommon.HexToAddress("0x2"), u256.Num2, 2, u256.Num2, nil) + + header = &types.Header{Number: bedrockBlock, Difficulty: big.NewInt(100)} + body := &types.Body{Transactions: types.Transactions{tx1, tx2}} + + receipt1 := &types.Receipt{ + Status: types.ReceiptStatusFailed, + CumulativeGasUsed: 1, + Logs: []*types.Log{ + {Address: libcommon.BytesToAddress([]byte{0x11})}, + {Address: libcommon.BytesToAddress([]byte{0x01, 0x11})}, + }, + TxHash: tx1.Hash(), + ContractAddress: libcommon.BytesToAddress([]byte{0x01, 0x11, 0x11}), + GasUsed: 111111, + L1Fee: big.NewInt(7), + } + receipt2 := &types.Receipt{ + PostState: libcommon.Hash{2}.Bytes(), + CumulativeGasUsed: 2, + Logs: []*types.Log{ + {Address: libcommon.BytesToAddress([]byte{0x22})}, + {Address: libcommon.BytesToAddress([]byte{0x02, 0x22})}, + }, + TxHash: tx2.Hash(), + ContractAddress: libcommon.BytesToAddress([]byte{0x02, 0x22, 0x22}), + GasUsed: 222222, + L1Fee: big.NewInt(1), + } + receipts := []*types.Receipt{receipt1, receipt2} + + rawdb.WriteCanonicalHash(tx, header.Hash(), header.Number.Uint64()) + rawdb.WriteHeader(tx, header) + require.NoError(t, rawdb.WriteBody(tx, header.Hash(), header.Number.Uint64(), body)) + require.NoError(t, rawdb.WriteSenders(tx, header.Hash(), header.Number.Uint64(), body.SendersFromTxs())) + + br := m.BlockReader + b, senders, err := br.BlockWithSenders(ctx, tx, header.Hash(), header.Number.Uint64()) + require.NoError(t, err) + + require.NoError(t, rawdb.WriteBlock(tx, b)) + require.NoError(t, rawdb.WriteReceipts(tx, b.NumberU64(), receipts)) + + tx.Commit() + + rTx, err = db.BeginRo(context.Background()) + require.NoError(t, err) + defer rTx.Rollback() + + receipts, err = api.getReceipts(m.Ctx, rTx, m.ChainConfig, b, senders) + require.NoError(t, err) + require.Equal(t, 2, len(receipts)) + + require.Equal(t, new(uint256.Int).SetBytes(l1BaseFee[:]).ToBig(), receipts[0].L1GasPrice) + rollupDataGas1 := uint64(2492) + require.Equal(t, new(big.Int).Add(new(big.Int).SetUint64(rollupDataGas1), new(uint256.Int).SetBytes(overhead[:]).ToBig()), receipts[0].L1GasUsed) + require.Equal(t, opstack.L1Cost(rollupDataGas1, new(uint256.Int).SetBytes(l1BaseFee[:]), new(uint256.Int).SetBytes(overhead[:]), new(uint256.Int).SetBytes(scalar[:])).ToBig(), receipts[0].L1Fee) + require.Equal(t, feeScalar, receipts[0].FeeScalar) + + require.Equal(t, new(uint256.Int).SetBytes(l1BaseFee[:]).ToBig(), receipts[1].L1GasPrice) + rollupDataGas2 := uint64(1340) + require.Equal(t, new(big.Int).Add(new(big.Int).SetUint64(rollupDataGas2), new(uint256.Int).SetBytes(overhead[:]).ToBig()), receipts[1].L1GasUsed) + require.Equal(t, opstack.L1Cost(rollupDataGas2, new(uint256.Int).SetBytes(l1BaseFee[:]), new(uint256.Int).SetBytes(overhead[:]), new(uint256.Int).SetBytes(scalar[:])).ToBig(), receipts[1].L1Fee) + require.Equal(t, feeScalar, receipts[1].FeeScalar) +} + +func buildSystemTx(l1BaseFee, overhead, scalar [32]byte) []byte { + systemInfo := []byte{0, 0, 0, 0} + zeroBytes := uint256.NewInt(0).Bytes32() + systemInfo = append(systemInfo, zeroBytes[:]...) // 4 - 4 + 32 + systemInfo = append(systemInfo, zeroBytes[:]...) // 4 + 1 * 32 - 4 + 2 * 32 + systemInfo = append(systemInfo, l1BaseFee[:]...) // 4 + 2 * 32 - 4 + 3 * 32 - l1Basefee + systemInfo = append(systemInfo, zeroBytes[:]...) // 4 + 3 * 32 - 4 + 4 * 32 + systemInfo = append(systemInfo, zeroBytes[:]...) // 4 + 4 * 32 - 4 + 5 * 32 + systemInfo = append(systemInfo, zeroBytes[:]...) // 4 + 5 * 32 - 4 + 6 * 32 + systemInfo = append(systemInfo, overhead[:]...) // 4 + 6 * 32 - 4 + 7 * 32 - overhead + systemInfo = append(systemInfo, scalar[:]...) // 4 + 7 * 32 - 4 + 8 * 32 - scalar + return systemInfo +}
diff --git ledgerwatch/erigon/accounts/abi/bind/backends/simulated.go bobanetwork/v3-erigon/accounts/abi/bind/backends/simulated.go index e1b8a639036f4bf1b665548057956498c3902c92..97d4571712ec1258532d9ca832f833e495c8ae98 100644 --- ledgerwatch/erigon/accounts/abi/bind/backends/simulated.go +++ bobanetwork/v3-erigon/accounts/abi/bind/backends/simulated.go @@ -36,6 +36,7 @@ state2 "github.com/ledgerwatch/erigon-lib/state" types2 "github.com/ledgerwatch/erigon-lib/types"   ethereum "github.com/ledgerwatch/erigon" + "github.com/ledgerwatch/erigon-lib/opstack" "github.com/ledgerwatch/erigon/accounts/abi" "github.com/ledgerwatch/erigon/accounts/abi/bind" "github.com/ledgerwatch/erigon/common/math" @@ -85,6 +86,8 @@ rmLogsFeed event.Feed chainFeed event.Feed logsFeed event.Feed + + chainConfig *chain.Config }   // NewSimulatedBackend creates a new binding backend using a simulated blockchain @@ -107,6 +110,7 @@ panic(err) } return h }, + chainConfig: config, } backend.emptyPendingBlock() return backend @@ -273,7 +277,7 @@ if err != nil { return nil, err } // Read all the receipts from the block and return the one with the matching hash - receipts := rawdb.ReadReceipts(tx, block, nil) + receipts := rawdb.ReadReceipts(b.chainConfig, tx, block, nil) for _, receipt := range receipts { if receipt.TxHash == txHash { return receipt, nil @@ -721,6 +725,7 @@ txContext := core.NewEVMTxContext(msg) header := block.Header() evmContext := core.NewEVMBlockContext(header, core.GetHashFn(header, b.getHeader), b.m.Engine, nil) + evmContext.L1CostFunc = opstack.NewL1CostFunc(b.m.ChainConfig, statedb) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmEnv := vm.NewEVM(evmContext, txContext, statedb, b.m.ChainConfig, vm.Config{}) @@ -823,18 +828,23 @@ type callMsg struct { ethereum.CallMsg }   -func (m callMsg) From() libcommon.Address { return m.CallMsg.From } -func (m callMsg) Nonce() uint64 { return 0 } -func (m callMsg) CheckNonce() bool { return false } -func (m callMsg) To() *libcommon.Address { return m.CallMsg.To } -func (m callMsg) GasPrice() *uint256.Int { return m.CallMsg.GasPrice } -func (m callMsg) FeeCap() *uint256.Int { return m.CallMsg.FeeCap } -func (m callMsg) Tip() *uint256.Int { return m.CallMsg.Tip } -func (m callMsg) Gas() uint64 { return m.CallMsg.Gas } -func (m callMsg) Value() *uint256.Int { return m.CallMsg.Value } -func (m callMsg) Data() []byte { return m.CallMsg.Data } -func (m callMsg) AccessList() types2.AccessList { return m.CallMsg.AccessList } -func (m callMsg) IsFree() bool { return false } +func (m callMsg) From() libcommon.Address { return m.CallMsg.From } +func (m callMsg) Nonce() uint64 { return 0 } +func (m callMsg) CheckNonce() bool { return false } +func (m callMsg) To() *libcommon.Address { return m.CallMsg.To } +func (m callMsg) GasPrice() *uint256.Int { return m.CallMsg.GasPrice } +func (m callMsg) FeeCap() *uint256.Int { return m.CallMsg.FeeCap } +func (m callMsg) Tip() *uint256.Int { return m.CallMsg.Tip } +func (m callMsg) Gas() uint64 { return m.CallMsg.Gas } +func (m callMsg) Value() *uint256.Int { return m.CallMsg.Value } +func (m callMsg) Data() []byte { return m.CallMsg.Data } +func (m callMsg) AccessList() types2.AccessList { return m.CallMsg.AccessList } +func (m callMsg) IsFree() bool { return false } +func (m callMsg) IsFake() bool { return true } +func (m callMsg) Mint() *uint256.Int { return nil } +func (m callMsg) RollupCostData() types2.RollupCostData { return types2.RollupCostData{} } +func (m callMsg) IsDepositTx() bool { return false } +func (m callMsg) IsSystemTx() bool { return false }   func (m callMsg) BlobGas() uint64 { return misc.GetBlobGasUsed(len(m.CallMsg.BlobHashes)) } func (m callMsg) MaxFeePerBlobGas() *uint256.Int { return m.CallMsg.MaxFeePerBlobGas }
diff --git ledgerwatch/erigon/core/rawdb/accessors_chain.go bobanetwork/v3-erigon/core/rawdb/accessors_chain.go index 905643429fe640f0d3a906c93b6d5b0e13d7842e..99d6ef752323d0b78f7a663d448a8deb9b42aacd 100644 --- ledgerwatch/erigon/core/rawdb/accessors_chain.go +++ bobanetwork/v3-erigon/core/rawdb/accessors_chain.go @@ -29,6 +29,7 @@ "github.com/ledgerwatch/erigon-lib/kv/dbutils"   "github.com/gballet/go-verkle" + "github.com/ledgerwatch/erigon-lib/chain" "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/cmp" "github.com/ledgerwatch/erigon-lib/common/dbg" @@ -829,7 +830,7 @@ // // The current implementation populates these metadata fields by reading the receipts' // corresponding block body, so if the block body is not found it will return nil even // if the receipt itself is stored. -func ReadReceipts(db kv.Tx, block *types.Block, senders []common.Address) types.Receipts { +func ReadReceipts(config *chain.Config, db kv.Tx, block *types.Block, senders []common.Address) types.Receipts { if block == nil { return nil } @@ -843,7 +844,7 @@ block.SendersToTxs(senders) } else { senders = block.Body().SendersFromTxs() } - if err := receipts.DeriveFields(block.Hash(), block.NumberU64(), block.Transactions(), senders); err != nil { + if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Time(), block.Transactions(), senders); err != nil { log.Error("Failed to derive block receipts fields", "hash", block.Hash(), "number", block.NumberU64(), "err", err, "stack", dbg.Stack()) return nil }
diff --git ledgerwatch/erigon/core/rawdb/accessors_chain_test.go bobanetwork/v3-erigon/core/rawdb/accessors_chain_test.go index 9b6e9a84e77ac8cea1e6b2b4bdebb807597d1774..f037548dbf780d7b98e5e8e7afdc3ee4ae9703af 100644 --- ledgerwatch/erigon/core/rawdb/accessors_chain_test.go +++ bobanetwork/v3-erigon/core/rawdb/accessors_chain_test.go @@ -478,6 +478,7 @@ }, TxHash: tx1.Hash(), ContractAddress: libcommon.BytesToAddress([]byte{0x01, 0x11, 0x11}), GasUsed: 111111, + L1Fee: big.NewInt(7), } //receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1})   @@ -511,7 +512,7 @@ b, senders, err := br.BlockWithSenders(ctx, tx, hash, 1) require.NoError(err) require.NotNil(b) - if rs := rawdb.ReadReceipts(tx, b, senders); len(rs) == 0 { + if rs := rawdb.ReadReceipts(params.TestChainConfig, tx, b, senders); len(rs) == 0 { t.Fatalf("no receipts returned") } else { if err := checkReceiptsRLP(rs, receipts); err != nil { @@ -524,7 +525,7 @@ rawdb.DeleteBody(tx, hash, 1) b, senders, err = br.BlockWithSenders(ctx, tx, hash, 1) require.NoError(err) require.Nil(b) - if rs := rawdb.ReadReceipts(tx, b, senders); rs != nil { + if rs := rawdb.ReadReceipts(params.TestChainConfig, tx, b, senders); rs != nil { t.Fatalf("receipts returned when body was deleted: %v", rs) } // Ensure that receipts without metadata can be returned without the block body too @@ -538,7 +539,7 @@ require.NoError(rawdb.TruncateReceipts(tx, 1)) b, senders, err = br.BlockWithSenders(ctx, tx, hash, 1) require.NoError(err) require.NotNil(b) - if rs := rawdb.ReadReceipts(tx, b, senders); len(rs) != 0 { + if rs := rawdb.ReadReceipts(params.TestChainAuraConfig, tx, b, senders); len(rs) != 0 { t.Fatalf("deleted receipts returned: %v", rs) } }

Forward transactions to the sequencer or historical node if configured.

diff --git ledgerwatch/erigon/cmd/rpcdaemon/main.go bobanetwork/v3-erigon/cmd/rpcdaemon/main.go index 8b90a3b56502011258115b89006000d77d813978..7a26fe2076e7a891c01eb35c16a5686695ff02d6 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/main.go +++ bobanetwork/v3-erigon/cmd/rpcdaemon/main.go @@ -5,6 +5,7 @@ "context" "errors" "fmt" "os" + "time"   "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli" @@ -30,7 +31,32 @@ } defer db.Close() defer engine.Close()   - apiList := jsonrpc.APIList(db, backend, txPool, mining, ff, stateCache, blockReader, agg, cfg, engine, logger) + var seqRPCService *rpc.Client + var historicalRPCService *rpc.Client + + // Setup sequencer and hsistorical RPC relay services + if cfg.RollupSequencerHTTP != "" { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + client, err := rpc.DialContext(ctx, cfg.RollupSequencerHTTP, logger) + cancel() + if err != nil { + logger.Error(err.Error()) + return nil + } + seqRPCService = client + } + if cfg.RollupHistoricalRPC != "" { + ctx, cancel := context.WithTimeout(context.Background(), cfg.RollupHistoricalRPCTimeout) + client, err := rpc.DialContext(ctx, cfg.RollupHistoricalRPC, logger) + cancel() + if err != nil { + logger.Error(err.Error()) + return nil + } + historicalRPCService = client + } + + apiList := jsonrpc.APIList(db, backend, txPool, mining, ff, stateCache, blockReader, agg, cfg, engine, seqRPCService, historicalRPCService, logger) rpc.PreAllocateRPCMetricLabels(apiList) if err := cli.StartRpcServer(ctx, cfg, apiList, logger); err != nil { logger.Error(err.Error())
diff --git ledgerwatch/erigon/cmd/rpcdaemon/cli/config.go bobanetwork/v3-erigon/cmd/rpcdaemon/cli/config.go index 9dbdc7c51ce95e30fdaad5d0e71074a3e9ae02ed..aa9ec6d0e5153b5f458bf874fba060fcea4a8e8a 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/cli/config.go +++ bobanetwork/v3-erigon/cmd/rpcdaemon/cli/config.go @@ -140,11 +140,15 @@ rootCmd.PersistentFlags().DurationVar(&cfg.HTTPTimeouts.IdleTimeout, "http.timeouts.idle", rpccfg.DefaultHTTPTimeouts.IdleTimeout, "Maximum amount of time to wait for the next request when keep-alives are enabled. If http.timeouts.idle is zero, the value of http.timeouts.read is used") rootCmd.PersistentFlags().DurationVar(&cfg.EvmCallTimeout, "rpc.evmtimeout", rpccfg.DefaultEvmCallTimeout, "Maximum amount of time to wait for the answer from EVM call.") rootCmd.PersistentFlags().IntVar(&cfg.BatchLimit, utils.RpcBatchLimit.Name, utils.RpcBatchLimit.Value, utils.RpcBatchLimit.Usage) rootCmd.PersistentFlags().IntVar(&cfg.ReturnDataLimit, utils.RpcReturnDataLimit.Name, utils.RpcReturnDataLimit.Value, utils.RpcReturnDataLimit.Usage) + + rootCmd.PersistentFlags().StringVar(&cfg.RollupSequencerHTTP, utils.RollupSequencerHTTPFlag.Name, "", "HTTP endpoint for the sequencer mempool") + rootCmd.PersistentFlags().StringVar(&cfg.RollupHistoricalRPC, utils.RollupHistoricalRPCFlag.Name, "", "RPC endpoint for historical data") + rootCmd.PersistentFlags().DurationVar(&cfg.RollupHistoricalRPCTimeout, utils.RollupHistoricalRPCTimeoutFlag.Name, rpccfg.DefaultHistoricalRPCTimeout, "Timeout for historical RPC requests") + rootCmd.PersistentFlags().BoolVar(&cfg.AllowUnprotectedTxs, utils.AllowUnprotectedTxs.Name, utils.AllowUnprotectedTxs.Value, utils.AllowUnprotectedTxs.Usage) rootCmd.PersistentFlags().IntVar(&cfg.MaxGetProofRewindBlockCount, utils.RpcMaxGetProofRewindBlockCount.Name, utils.RpcMaxGetProofRewindBlockCount.Value, utils.RpcMaxGetProofRewindBlockCount.Usage) rootCmd.PersistentFlags().Uint64Var(&cfg.OtsMaxPageSize, utils.OtsSearchMaxCapFlag.Name, utils.OtsSearchMaxCapFlag.Value, utils.OtsSearchMaxCapFlag.Usage) rootCmd.PersistentFlags().DurationVar(&cfg.RPCSlowLogThreshold, utils.RPCSlowFlag.Name, utils.RPCSlowFlag.Value, utils.RPCSlowFlag.Usage) - if err := rootCmd.MarkPersistentFlagFilename("rpc.accessList", "json"); err != nil { panic(err) }
diff --git ledgerwatch/erigon/cmd/rpcdaemon/cli/httpcfg/http_cfg.go bobanetwork/v3-erigon/cmd/rpcdaemon/cli/httpcfg/http_cfg.go index 7a0930750f293d38949ecd7a3323e8aeca6bcf24..6ac47b577ff1d33dde71a1f4e4f03f8a2de7b6cc 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/cli/httpcfg/http_cfg.go +++ bobanetwork/v3-erigon/cmd/rpcdaemon/cli/httpcfg/http_cfg.go @@ -78,6 +78,12 @@ BatchLimit int // Maximum number of requests in a batch ReturnDataLimit int // Maximum number of bytes returned from calls (like eth_call) AllowUnprotectedTxs bool // Whether to allow non EIP-155 protected transactions txs over RPC MaxGetProofRewindBlockCount int //Max GetProof rewind block count + + // Optimism + RollupSequencerHTTP string + RollupHistoricalRPC string + RollupHistoricalRPCTimeout time.Duration + // Ots API OtsMaxPageSize uint64
diff --git ledgerwatch/erigon/rpc/rpccfg/rpccfg.go bobanetwork/v3-erigon/rpc/rpccfg/rpccfg.go index d50a472cead9297ebda0c6630e2d80ae8bd81a8f..a1b963d7530f53f2aa9baa539737cccb6f188d23 100644 --- ledgerwatch/erigon/rpc/rpccfg/rpccfg.go +++ bobanetwork/v3-erigon/rpc/rpccfg/rpccfg.go @@ -38,6 +38,8 @@ }   const DefaultEvmCallTimeout = 5 * time.Minute   +const DefaultHistoricalRPCTimeout = 5 * time.Second + var SlowLogBlackList = []string{ "eth_getBlock", "eth_getBlockByNumber", "eth_getBlockByHash", "eth_blockNumber", "erigon_blockNumber", "erigon_getHeaderByNumber", "erigon_getHeaderByHash", "erigon_getBlockByTimestamp",
diff --git ledgerwatch/erigon/turbo/jsonrpc/daemon.go bobanetwork/v3-erigon/turbo/jsonrpc/daemon.go index ca89bcd0809ed18aa6b24638289bac4ba9b62337..f0023519af4a18c14c6e96b839ab7175271b0789 100644 --- ledgerwatch/erigon/turbo/jsonrpc/daemon.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/daemon.go @@ -19,9 +19,9 @@ // APIList describes the list of available RPC apis func APIList(db kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, filters *rpchelper.Filters, stateCache kvcache.Cache, blockReader services.FullBlockReader, agg *libstate.AggregatorV3, cfg *httpcfg.HttpCfg, engine consensus.EngineReader, - logger log.Logger, + seqRPCService, historicalRPCService *rpc.Client, logger log.Logger, ) (list []rpc.API) { - base := NewBaseApi(filters, stateCache, blockReader, agg, cfg.WithDatadir, cfg.EvmCallTimeout, engine, cfg.Dirs) + base := NewBaseApi(filters, stateCache, blockReader, agg, cfg.WithDatadir, cfg.EvmCallTimeout, engine, cfg.Dirs, seqRPCService, historicalRPCService) ethImpl := NewEthAPI(base, db, eth, txPool, mining, cfg.Gascap, cfg.ReturnDataLimit, cfg.AllowUnprotectedTxs, cfg.MaxGetProofRewindBlockCount, logger) erigonImpl := NewErigonAPI(base, db, eth) txpoolImpl := NewTxPoolAPI(base, db, txPool)
diff --git ledgerwatch/erigon/eth/backend.go bobanetwork/v3-erigon/eth/backend.go index 9d24aabaf21a6c867e674b4407d11c88803ed626..67c1c5a0b4660b7e838c6b0692bdfb1d8a1ad671 100644 --- ledgerwatch/erigon/eth/backend.go +++ bobanetwork/v3-erigon/eth/backend.go @@ -155,10 +155,12 @@ genesisHash libcommon.Hash   eth1ExecutionServer *eth1.EthereumExecutionModule   - ethBackendRPC *privateapi.EthBackendServer - engineBackendRPC *engineapi.EngineServer - miningRPC txpool_proto.MiningServer - stateChangesClient txpool.StateChangesClient + ethBackendRPC *privateapi.EthBackendServer + seqRPCService *rpc.Client + historicalRPCService *rpc.Client + engineBackendRPC *engineapi.EngineServer + miningRPC txpool_proto.MiningServer + stateChangesClient txpool.StateChangesClient   miningSealingQuit chan struct{} pendingBlocks chan *types.Block @@ -303,7 +305,7 @@ if h != (libcommon.Hash{}) { // fallback to db content genesisSpec = nil } var genesisErr error - chainConfig, genesis, genesisErr = core.WriteGenesisBlock(tx, genesisSpec, config.OverrideCancunTime, tmpdir, logger) + chainConfig, genesis, genesisErr = core.WriteGenesisBlock(tx, genesisSpec, config.OverrideCancunTime, config.OverrideShanghaiTime, config.OverrideOptimismCanyonTime, config.OverrideOptimismEcotoneTime, tmpdir, logger) if _, ok := genesisErr.(*chain.ConfigCompatError); genesisErr != nil && !ok { return genesisErr } @@ -318,6 +320,17 @@ backend.genesisHash = genesis.Hash()   logger.Info("Initialised chain configuration", "config", chainConfig, "genesis", genesis.Hash())   + if chainConfig.IsOptimism() { + if chainConfig.RegolithTime == nil { + log.Warn("Optimism RegolithTime has not been set") + } + if chainConfig.CanyonTime == nil { + log.Warn("Optimism CanyonTime has not been set") + } + if chainConfig.EcotoneTime == nil { + log.Warn("Optimism EcotoneTime has not been set") + } + } snapshotVersion := snapcfg.KnownCfg(chainConfig.ChainName, 0).Version   // Check if we have an already initialized chain and fall back to @@ -587,6 +600,25 @@ if err != nil { return nil, err }   + // Setup sequencer and hsistorical RPC relay services + if config.RollupSequencerHTTP != "" { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + client, err := rpc.DialContext(ctx, config.RollupSequencerHTTP, logger) + cancel() + if err != nil { + return nil, err + } + backend.seqRPCService = client + } + if config.RollupHistoricalRPC != "" { + ctx, cancel := context.WithTimeout(context.Background(), config.RollupHistoricalRPCTimeout) + client, err := rpc.DialContext(ctx, config.RollupHistoricalRPC, logger) + cancel() + if err != nil { + return nil, err + } + backend.historicalRPCService = client + } config.TxPool.NoGossip = config.DisableTxPoolGossip var miningRPC txpool_proto.MiningServer stateDiffClient := direct.NewStateDiffClientDirect(kvRPC) @@ -598,9 +630,13 @@ //cacheConfig.MetricsLabel = "txpool"   backend.newTxs = make(chan types2.Announcements, 1024) //defer close(newTxs) + config.TxPool.Optimism = chainConfig.Optimism != nil backend.txPoolDB, backend.txPool, backend.txPoolFetch, backend.txPoolSend, backend.txPoolGrpcServer, err = txpooluitl.AllComponents( ctx, config.TxPool, kvcache.NewDummy(), backend.newTxs, backend.chainDB, backend.sentriesClient.Sentries(), stateDiffClient, misc.Eip1559FeeCalculator, logger, ) + // TODO(jky) this is a bit of a hack, and should probably be passed as a + // parameter through the AllComponents call above + backend.txPool.SetInitialBlockGasLimit(config.Miner.GasLimit) if err != nil { return nil, err } @@ -658,9 +694,11 @@ stagedsync.StageMiningFinishCfg(backend.chainDB, *backend.chainConfig, backend.engine, miningStatePos, backend.miningSealingQuit, backend.blockReader, latestBlockBuiltStore), ), stagedsync.MiningUnwindOrder, stagedsync.MiningPruneOrder, logger) // We start the mining step + log.Debug("Starting assembleBlockPOS mining step", "payloadId", param.PayloadId) if err := stages2.MiningStep(ctx, backend.chainDB, proposingSync, tmpdir, logger); err != nil { return nil, err } + log.Debug("Finished assembleBlockPOS mining step", "payloadId", param.PayloadId) block := <-miningStatePos.MiningResultPOSCh return block, nil } @@ -915,7 +953,7 @@ if err != nil { return err }   - s.apiList = jsonrpc.APIList(chainKv, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, blockReader, s.agg, &httpRpcCfg, s.engine, s.logger) + s.apiList = jsonrpc.APIList(chainKv, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, blockReader, s.agg, &httpRpcCfg, s.engine, s.seqRPCService, s.historicalRPCService, s.logger)   if config.SilkwormRpcDaemon && httpRpcCfg.Enabled { silkwormRPCDaemonService := silkworm.NewRpcDaemonService(s.silkworm, chainKv) @@ -929,7 +967,7 @@ }() }   if config.Genesis.Config.Bor == nil { - go s.engineBackendRPC.Start(&httpRpcCfg, s.chainDB, s.blockReader, ff, stateCache, s.agg, s.engine, ethRpcClient, txPoolRpcClient, miningRpcClient) + go s.engineBackendRPC.Start(&httpRpcCfg, s.chainDB, s.blockReader, ff, stateCache, s.agg, s.engine, ethRpcClient, txPoolRpcClient, miningRpcClient, s.seqRPCService, s.historicalRPCService) }   // Register the backend on the node @@ -1462,6 +1500,13 @@ if s.silkworm != nil { if err := s.silkworm.Close(); err != nil { s.logger.Error("silkworm.Close error", "err", err) } + } + + if s.seqRPCService != nil { + s.seqRPCService.Close() + } + if s.historicalRPCService != nil { + s.historicalRPCService.Close() }   return nil
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_accounts.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_accounts.go index dc3c41f5fccf2f85fa9c0bb222f998af3b8c8923..325982015ced39d4cacc8d85761ba8ebe92736e1 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_accounts.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_accounts.go @@ -3,8 +3,9 @@ import ( "context" "fmt" + "math/big" + "github.com/ledgerwatch/erigon-lib/common/hexutil" - "math/big"   libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/hexutility" @@ -26,6 +27,27 @@ if err1 != nil { return nil, fmt.Errorf("getBalance cannot open tx: %w", err1) } defer tx.Rollback() + + // Handle pre-bedrock blocks + blockNum, err := api.blockNumberFromBlockNumberOrHash(tx, &blockNrOrHash) + if err != nil { + return nil, err + } + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, fmt.Errorf("read chain config: %v", err) + } + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return nil, rpc.ErrNoHistoricalFallback + } + var result hexutil.Big + if err := api.relayToHistoricalBackend(ctx, &result, "eth_getBalance", address, hexutil.EncodeUint64(blockNum)); err != nil { + return nil, fmt.Errorf("historical backend error: %w", err) + } + return &result, nil + } + reader, err := rpchelper.CreateStateReader(ctx, tx, blockNrOrHash, 0, api.filters, api.stateCache, api.historyV3(tx), "") if err != nil { return nil, err @@ -62,6 +84,27 @@ if err1 != nil { return nil, fmt.Errorf("getTransactionCount cannot open tx: %w", err1) } defer tx.Rollback() + + // Handle pre-bedrock blocks + blockNum, err := api.blockNumberFromBlockNumberOrHash(tx, &blockNrOrHash) + if err != nil { + return nil, err + } + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, fmt.Errorf("read chain config: %v", err) + } + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return nil, rpc.ErrNoHistoricalFallback + } + var result hexutil.Uint64 + if err := api.relayToHistoricalBackend(ctx, &result, "eth_getTransactionCount", address, hexutil.EncodeUint64(blockNum)); err != nil { + return nil, fmt.Errorf("historical backend error: %w", err) + } + return &result, nil + } + reader, err := rpchelper.CreateStateReader(ctx, tx, blockNrOrHash, 0, api.filters, api.stateCache, api.historyV3(tx), "") if err != nil { return nil, err @@ -81,10 +124,27 @@ if err1 != nil { return nil, fmt.Errorf("getCode cannot open tx: %w", err1) } defer tx.Rollback() + + // Handle pre-bedrock blocks + blockNum, err := api.blockNumberFromBlockNumberOrHash(tx, &blockNrOrHash) + if err != nil { + return nil, err + } chainConfig, err := api.chainConfig(tx) if err != nil { return nil, fmt.Errorf("read chain config: %v", err) } + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return nil, rpc.ErrNoHistoricalFallback + } + var result hexutility.Bytes + if err := api.relayToHistoricalBackend(ctx, &result, "eth_getCode", address, hexutil.EncodeUint64(blockNum)); err != nil { + return nil, fmt.Errorf("historical backend error: %w", err) + } + return result, nil + } + reader, err := rpchelper.CreateStateReader(ctx, tx, blockNrOrHash, 0, api.filters, api.stateCache, api.historyV3(tx), chainConfig.ChainName) if err != nil { return nil, err @@ -110,6 +170,26 @@ if err1 != nil { return hexutility.Encode(common.LeftPadBytes(empty, 32)), err1 } defer tx.Rollback() + + // Handle pre-bedrock blocks + blockNum, err := api.blockNumberFromBlockNumberOrHash(tx, &blockNrOrHash) + if err != nil { + return hexutility.Encode(common.LeftPadBytes(empty, 32)), err + } + chainConfig, err := api.chainConfig(tx) + if err != nil { + return hexutility.Encode(common.LeftPadBytes(empty, 32)), fmt.Errorf("read chain config: %v", err) + } + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return hexutility.Encode(common.LeftPadBytes(empty, 32)), rpc.ErrNoHistoricalFallback + } + var result hexutility.Bytes + if err := api.relayToHistoricalBackend(ctx, &result, "eth_getStorageAt", address, index, hexutil.EncodeUint64(blockNum)); err != nil { + return hexutility.Encode(common.LeftPadBytes(empty, 32)), fmt.Errorf("historical backend error: %w", err) + } + return hexutility.Encode(common.LeftPadBytes(result, 32)), nil + }   reader, err := rpchelper.CreateStateReader(ctx, tx, blockNrOrHash, 0, api.filters, api.stateCache, api.historyV3(tx), "") if err != nil {
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_call.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_call.go index 84871efc59476dfd7b9c9a443863181bb44f72d8..984a00150ccdf3b30a289263ee4e5be4fc8adc07 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_call.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_call.go @@ -6,18 +6,18 @@ "errors" "fmt" "math/big"   - "github.com/ledgerwatch/erigon-lib/common/hexutil" - "github.com/holiman/uint256" - "github.com/ledgerwatch/erigon-lib/kv/membatchwithdb" "github.com/ledgerwatch/log/v3" "google.golang.org/grpc"   libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutil" "github.com/ledgerwatch/erigon-lib/common/hexutility" "github.com/ledgerwatch/erigon-lib/gointerfaces" txpool_proto "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/kv/membatchwithdb" + "github.com/ledgerwatch/erigon-lib/opstack" types2 "github.com/ledgerwatch/erigon-lib/types"   "github.com/ledgerwatch/erigon/core" @@ -46,10 +46,26 @@ return nil, err } defer tx.Rollback()   - chainConfig, err := api.chainConfig(tx) + // Handle pre-bedrock blocks + blockNum, err := api.blockNumberFromBlockNumberOrHash(tx, &blockNrOrHash) if err != nil { return nil, err } + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, fmt.Errorf("read chain config: %v", err) + } + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return nil, rpc.ErrNoHistoricalFallback + } + var result hexutility.Bytes + if err := api.relayToHistoricalBackend(ctx, &result, "eth_call", args, hexutil.EncodeUint64(blockNum), overrides); err != nil { + return nil, fmt.Errorf("historical backend error: %w", err) + } + return result, nil + } + engine := api.engine()   if args.Gas == nil || uint64(*args.Gas) == 0 { @@ -141,6 +157,26 @@ bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash + } + + // Handle pre-bedrock blocks + blockNum, err := api.blockNumberFromBlockNumberOrHash(dbtx, &bNrOrHash) + if err != nil { + return 0, err + } + chainConfig, err := api.chainConfig(dbtx) + if err != nil { + return 0, fmt.Errorf("read chain config: %v", err) + } + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return 0, rpc.ErrNoHistoricalFallback + } + var result hexutil.Uint64 + if err := api.relayToHistoricalBackend(ctx, &result, "eth_estimateGas", args, hexutil.EncodeUint64(blockNum)); err != nil { + return 0, fmt.Errorf("historical backend error: %w", err) + } + return result, nil }   // Determine the highest gas limit can be used during the estimation. @@ -221,10 +257,6 @@ hi = api.GasCap } gasCap = hi   - chainConfig, err := api.chainConfig(dbtx) - if err != nil { - return 0, err - } engine := api.engine()   latestCanBlockNumber, latestCanHash, isLatest, err := rpchelper.GetCanonicalBlockNumber(latestNumOrHash, dbtx, api.filters) // DoCall cannot be executed on non-canonical blocks @@ -329,6 +361,26 @@ if api.historyV3(tx) { return nil, fmt.Errorf("not supported by Erigon3") }   + // Handle pre-bedrock blocks + blockNum, err := api.blockNumberFromBlockNumberOrHash(tx, &blockNrOrHash) + if err != nil { + return nil, err + } + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, fmt.Errorf("read chain config: %v", err) + } + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return nil, rpc.ErrNoHistoricalFallback + } + var result accounts.AccProofResult + if err := api.relayToHistoricalBackend(ctx, &result, "eth_getProof", address, storageKeys, hexutil.EncodeUint64(blockNum)); err != nil { + return nil, fmt.Errorf("historical backend error: %w", err) + } + return &result, nil + } + blockNr, _, _, err := rpchelper.GetBlockNumber(blockNrOrHash, tx, api.filters) if err != nil { return nil, err @@ -438,10 +490,26 @@ return nil, err } defer tx.Rollback()   + // Handle pre-bedrock blocks + blockNum, err := api.blockNumberFromBlockNumberOrHash(tx, blockNrOrHash) + if err != nil { + return nil, err + } chainConfig, err := api.chainConfig(tx) if err != nil { - return nil, err + return nil, fmt.Errorf("read chain config: %v", err) + } + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return nil, rpc.ErrNoHistoricalFallback + } + var result accessListResult + if err := api.relayToHistoricalBackend(ctx, &result, "eth_createAccessList", args, hexutil.EncodeUint64(blockNum)); err != nil { + return nil, fmt.Errorf("historical backend error: %w", err) + } + return &result, nil } + engine := api.engine()   blockNumber, hash, latest, err := rpchelper.GetCanonicalBlockNumber(bNrOrHash, tx, api.filters) // DoCall cannot be executed on non-canonical blocks @@ -551,6 +619,7 @@ tracer := logger.NewAccessListTracer(accessList, excl, state) config := vm.Config{Tracer: tracer, Debug: true, NoBaseFee: true} blockCtx := transactions.NewEVMBlockContext(engine, header, bNrOrHash.RequireCanonical, tx, api._blockReader) txCtx := core.NewEVMTxContext(msg) + blockCtx.L1CostFunc = opstack.NewL1CostFunc(chainConfig, state)   evm := vm.NewEVM(blockCtx, txCtx, state, chainConfig, config) gp := new(core.GasPool).AddGas(msg.Gas()).AddBlobGas(msg.BlobGas())
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_call_test.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_call_test.go index 8040af8593be9c22a092c6633dda90341d5724dc..11e574200b7bfcc9f0ebeb53024af1d33e8f23f6 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_call_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_call_test.go @@ -25,11 +25,13 @@ "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/state" "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/core/types/accounts" "github.com/ledgerwatch/erigon/crypto" "github.com/ledgerwatch/erigon/params" "github.com/ledgerwatch/erigon/rpc" "github.com/ledgerwatch/erigon/rpc/rpccfg" "github.com/ledgerwatch/erigon/turbo/adapter/ethapi" + ethapi2 "github.com/ledgerwatch/erigon/turbo/adapter/ethapi" "github.com/ledgerwatch/erigon/turbo/rpchelper" "github.com/ledgerwatch/erigon/turbo/stages/mock" "github.com/ledgerwatch/erigon/turbo/trie" @@ -43,7 +45,7 @@ stateCache := kvcache.New(kvcache.DefaultCoherentConfig) ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, mock.Mock(t)) mining := txpool.NewMiningClient(conn) ff := rpchelper.New(ctx, nil, nil, mining, func() {}, m.Log) - api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) var from = libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") var to = libcommon.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e") if _, err := api.EstimateGas(context.Background(), &ethapi.CallArgs{ @@ -54,11 +56,71 @@ t.Errorf("calling EstimateGas: %v", err) } }   +func TestEstimateGasHistoricalRPC(t *testing.T) { + m, _, _ := rpcdaemontest.CreateOptimismTestSentry(t) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + + table := []struct { + caseName string + payload string + appendAPI bool + isError bool + expected string + }{ + { + caseName: "missing api", + payload: "", + appendAPI: false, + isError: true, + expected: "no historical RPC is available for this historical (pre-bedrock) execution request", + }, + { + caseName: "success", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0x1\"}", + appendAPI: true, + isError: false, + expected: "0x1", + }, + { + caseName: "failuer", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"error\":{\"code\":-32000,\"message\":\"error\"}}", + appendAPI: true, + isError: true, + expected: "historical backend error: error", + }, + } + + for _, tt := range table { + t.Run(tt.caseName, func(t *testing.T) { + if tt.appendAPI { + s := MockServer{} + s.Start() + defer s.Stop() + historicalRPCService, err := s.GetRPC() + if err != nil { + t.Errorf("failed to start mock server: %v", err) + } + api.historicalRPCService = historicalRPCService + s.UpdatePayload(tt.payload) + } + bn := rpc.BlockNumberOrHashWithNumber(0) + val, err := api.EstimateGas(m.Ctx, &ethapi2.CallArgs{}, &bn) + if tt.isError { + require.Error(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", err), tt.caseName) + } else { + require.NoError(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", val), tt.caseName) + } + }) + } +} + func TestEthCallNonCanonical(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + api := NewEthAPI(NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) var from = libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") var to = libcommon.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e") if _, err := api.Call(context.Background(), ethapi.CallArgs{ @@ -216,6 +278,69 @@ }) } }   +func TestGetProofHistoricalRPC(t *testing.T) { + m, _, _ := rpcdaemontest.CreateOptimismTestSentry(t) + if m.HistoryV3 { + t.Skip("not supported by Erigon3") + } + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + + table := []struct { + caseName string + payload string + appendAPI bool + isError bool + expected string + }{ + { + caseName: "missing api", + payload: "", + appendAPI: false, + isError: true, + expected: "no historical RPC is available for this historical (pre-bedrock) execution request", + }, + { + caseName: "success", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{}}", + appendAPI: true, + isError: false, + expected: fmt.Sprintf("%v", &accounts.AccProofResult{}), + }, + { + caseName: "failuer", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"error\":{\"code\":-32000,\"message\":\"error\"}}", + appendAPI: true, + isError: true, + expected: "historical backend error: error", + }, + } + + for _, tt := range table { + t.Run(tt.caseName, func(t *testing.T) { + if tt.appendAPI { + s := MockServer{} + s.Start() + defer s.Stop() + historicalRPCService, err := s.GetRPC() + if err != nil { + t.Errorf("failed to start mock server: %v", err) + } + api.historicalRPCService = historicalRPCService + s.UpdatePayload(tt.payload) + } + bn := rpc.BlockNumberOrHashWithNumber(0) + val, err := api.GetProof(m.Ctx, libcommon.HexToAddress("0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead0"), []libcommon.Hash{libcommon.HexToHash("0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead")}, bn) + if tt.isError { + require.Error(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", err), tt.caseName) + } else { + require.NoError(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", val), tt.caseName) + } + }) + } +} + func TestGetBlockByTimestampLatestTime(t *testing.T) { ctx := context.Background() m, _, _ := rpcdaemontest.CreateTestSentry(t) @@ -228,7 +353,7 @@ api := NewErigonAPI(newBaseApiForTest(m), m.DB, nil)   latestBlock, err := m.BlockReader.CurrentBlock(tx) require.NoError(t, err) - response, err := ethapi.RPCMarshalBlockDeprecated(latestBlock, true, false) + response, err := ethapi.RPCMarshalBlockDeprecated(latestBlock, true, false, nil)   if err != nil { t.Error("couldn't get the rpc marshal block") @@ -266,7 +391,7 @@ if err != nil { t.Error("couldn't retrieve oldest block") }   - response, err := ethapi.RPCMarshalBlockDeprecated(oldestBlock, true, false) + response, err := ethapi.RPCMarshalBlockDeprecated(oldestBlock, true, false, nil)   if err != nil { t.Error("couldn't get the rpc marshal block") @@ -302,7 +427,7 @@ latestBlock, err := m.BlockReader.CurrentBlock(tx) require.NoError(t, err)   - response, err := ethapi.RPCMarshalBlockDeprecated(latestBlock, true, false) + response, err := ethapi.RPCMarshalBlockDeprecated(latestBlock, true, false, nil)   if err != nil { t.Error("couldn't get the rpc marshal block") @@ -350,7 +475,7 @@ if err != nil { t.Error("couldn't retrieve middle block") }   - response, err := ethapi.RPCMarshalBlockDeprecated(middleBlock, true, false) + response, err := ethapi.RPCMarshalBlockDeprecated(middleBlock, true, false, nil)   if err != nil { t.Error("couldn't get the rpc marshal block") @@ -391,7 +516,7 @@ if pickedBlock == nil { t.Error("couldn't retrieve picked block") } - response, err := ethapi.RPCMarshalBlockDeprecated(pickedBlock, true, false) + response, err := ethapi.RPCMarshalBlockDeprecated(pickedBlock, true, false, nil)   if err != nil { t.Error("couldn't get the rpc marshal block")
diff --git ledgerwatch/erigon/turbo/jsonrpc/send_transaction.go bobanetwork/v3-erigon/turbo/jsonrpc/send_transaction.go index 90dcaec332dc8eb0511514304c49ac7d171ee05a..879788b8f11dca16b9f582e2a51e937c4054126e 100644 --- ledgerwatch/erigon/turbo/jsonrpc/send_transaction.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/send_transaction.go @@ -22,15 +22,6 @@ if err != nil { return common.Hash{}, err }   - // If the transaction fee cap is already specified, ensure the - // fee of the given transaction is _reasonable_. - if err := checkTxFee(txn.GetPrice().ToBig(), txn.GetGas(), ethconfig.Defaults.RPCTxFeeCap); err != nil { - return common.Hash{}, err - } - if !txn.Protected() && !api.AllowUnprotectedTxs { - return common.Hash{}, errors.New("only replay-protected (EIP-155) transactions allowed over RPC") - } - // this has been moved to prior to adding of transactions to capture the // pre state of the db - which is used for logging in the messages below tx, err := api.db.BeginRo(ctx) @@ -45,6 +36,26 @@ if err != nil { return common.Hash{}, err }   + if cc.IsOptimism() && txn.Type() == types.BlobTxType { + return common.Hash{}, types.ErrTxTypeNotSupported + } + + if api.seqRPCService != nil { + if err := api.seqRPCService.CallContext(ctx, nil, "eth_sendRawTransaction", hexutility.Encode(encodedTx)); err != nil { + return common.Hash{}, err + } + return txn.Hash(), nil + } + + // If the transaction fee cap is already specified, ensure the + // fee of the given transaction is _reasonable_. + if err := checkTxFee(txn.GetPrice().ToBig(), txn.GetGas(), ethconfig.Defaults.RPCTxFeeCap); err != nil { + return common.Hash{}, err + } + if !txn.Protected() && !api.AllowUnprotectedTxs { + return common.Hash{}, errors.New("only replay-protected (EIP-155) transactions allowed over RPC") + } + if txn.Protected() { txnChainId := txn.GetChainID() chainId := cc.ChainID @@ -62,6 +73,7 @@ if res.Imported[0] != txPoolProto.ImportResult_SUCCESS { return hash, fmt.Errorf("%s: %s", txPoolProto.ImportResult_name[int32(res.Imported[0])], res.Errors[0]) } + api.logger.Debug("SendRawTransaction submitted", "hash", hash, "txn", txn)   return txn.Hash(), nil }
diff --git ledgerwatch/erigon/rpc/errors.go bobanetwork/v3-erigon/rpc/errors.go index 83f9c031309d3f46ed9b5ed4d63e3d4a36a894ba..0af99284535679a144eb5784f4e524415edf15fe 100644 --- ledgerwatch/erigon/rpc/errors.go +++ bobanetwork/v3-erigon/rpc/errors.go @@ -30,6 +30,16 @@ )   const defaultErrorCode = -32000   +var ErrNoHistoricalFallback = NoHistoricalFallbackError{} + +type NoHistoricalFallbackError struct{} + +func (e NoHistoricalFallbackError) ErrorCode() int { return -32801 } + +func (e NoHistoricalFallbackError) Error() string { + return "no historical RPC is available for this historical (pre-bedrock) execution request" +} + type methodNotFoundError struct{ method string }   func (e *methodNotFoundError) ErrorCode() int { return -32601 }
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_accounts_test.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_accounts_test.go new file mode 100644 index 0000000000000000000000000000000000000000..7368f02bdbca6213f96fc3bc741866ec4dc51f7c --- /dev/null +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_accounts_test.go @@ -0,0 +1,293 @@ +package jsonrpc + +import ( + "context" + "fmt" + "net/http" + "net/http/httptest" + "testing" + "time" + + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest" + "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/log/v3" + "github.com/stretchr/testify/require" +) + +type MockServer struct { + Server *httptest.Server + Payload string +} + +func (m *MockServer) Start() { + m.Server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(m.Payload)) + })) +} + +func (m *MockServer) Stop() { + m.Server.Close() +} + +func (m *MockServer) UpdatePayload(payload string) { + m.Payload = payload +} + +func (m *MockServer) GetRPC() (*rpc.Client, error) { + if m.Server == nil { + return nil, fmt.Errorf("server is not started") + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + client, err := rpc.DialContext(ctx, m.Server.URL, log.New()) + cancel() + if err != nil { + return nil, err + } + return client, nil +} + +func TestGetBalanceHistoricalRPC(t *testing.T) { + m, _, _ := rpcdaemontest.CreateOptimismTestSentry(t) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + addr := libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") + + table := []struct { + caseName string + payload string + appendAPI bool + isError bool + expected string + }{ + { + caseName: "missing api", + payload: "", + appendAPI: false, + isError: true, + expected: "no historical RPC is available for this historical (pre-bedrock) execution request", + }, + { + caseName: "success", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0x1\"}", + appendAPI: true, + isError: false, + expected: "0x1", + }, + { + caseName: "failure", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"error\":{\"code\":-32000,\"message\":\"error\"}}", + appendAPI: true, + isError: true, + expected: "historical backend error: error", + }, + } + + for _, tt := range table { + t.Run(tt.caseName, func(t *testing.T) { + if tt.appendAPI { + s := MockServer{} + s.Start() + defer s.Stop() + historicalRPCService, err := s.GetRPC() + if err != nil { + t.Errorf("failed to start mock server: %v", err) + } + api.historicalRPCService = historicalRPCService + s.UpdatePayload(tt.payload) + } + + bal, err := api.GetBalance(m.Ctx, addr, rpc.BlockNumberOrHashWithNumber(0)) + if tt.isError { + require.Error(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", err), tt.caseName) + } else { + require.NoError(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", bal), tt.caseName) + } + }) + } +} + +func TestGetTransactionCountHistoricalRPC(t *testing.T) { + m, _, _ := rpcdaemontest.CreateOptimismTestSentry(t) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + addr := libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") + + table := []struct { + caseName string + payload string + appendAPI bool + isError bool + expected string + }{ + { + caseName: "missing api", + payload: "", + appendAPI: false, + isError: true, + expected: "no historical RPC is available for this historical (pre-bedrock) execution request", + }, + { + caseName: "success", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0x1\"}", + appendAPI: true, + isError: false, + expected: "0x1", + }, + { + caseName: "failuer", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"error\":{\"code\":-32000,\"message\":\"error\"}}", + appendAPI: true, + isError: true, + expected: "historical backend error: error", + }, + } + + for _, tt := range table { + t.Run(tt.caseName, func(t *testing.T) { + if tt.appendAPI { + s := MockServer{} + s.Start() + defer s.Stop() + historicalRPCService, err := s.GetRPC() + if err != nil { + t.Errorf("failed to start mock server: %v", err) + } + api.historicalRPCService = historicalRPCService + s.UpdatePayload(tt.payload) + } + + val, err := api.GetTransactionCount(m.Ctx, addr, rpc.BlockNumberOrHashWithNumber(0)) + if tt.isError { + require.Error(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", err), tt.caseName) + } else { + require.NoError(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", val), tt.caseName) + } + }) + } +} + +func TestGetCodeHistoricalRPC(t *testing.T) { + m, _, _ := rpcdaemontest.CreateOptimismTestSentry(t) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + addr := libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") + + table := []struct { + caseName string + payload string + appendAPI bool + isError bool + expected string + }{ + { + caseName: "missing api", + payload: "", + appendAPI: false, + isError: true, + expected: "no historical RPC is available for this historical (pre-bedrock) execution request", + }, + { + caseName: "success", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0x4200000000000000000000000000000000000010\"}", + appendAPI: true, + isError: false, + expected: "0x4200000000000000000000000000000000000010", + }, + { + caseName: "failuer", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"error\":{\"code\":-32000,\"message\":\"error\"}}", + appendAPI: true, + isError: true, + expected: "historical backend error: error", + }, + } + + for _, tt := range table { + t.Run(tt.caseName, func(t *testing.T) { + if tt.appendAPI { + s := MockServer{} + s.Start() + defer s.Stop() + historicalRPCService, err := s.GetRPC() + if err != nil { + t.Errorf("failed to start mock server: %v", err) + } + api.historicalRPCService = historicalRPCService + s.UpdatePayload(tt.payload) + } + + val, err := api.GetCode(m.Ctx, addr, rpc.BlockNumberOrHashWithNumber(0)) + if tt.isError { + require.Error(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", err), tt.caseName) + } else { + require.NoError(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", val), tt.caseName) + } + }) + } +} + +func TestGetStorageAtHistoricalRPC(t *testing.T) { + m, _, _ := rpcdaemontest.CreateOptimismTestSentry(t) + api := NewEthAPI(newBaseApiForTest(m), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + addr := libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") + + table := []struct { + caseName string + payload string + appendAPI bool + isError bool + expected string + }{ + { + caseName: "missing api", + payload: "", + appendAPI: false, + isError: true, + expected: "no historical RPC is available for this historical (pre-bedrock) execution request", + }, + { + caseName: "success", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0x4200000000000000000000000000000000000010\"}", + appendAPI: true, + isError: false, + expected: "0x0000000000000000000000004200000000000000000000000000000000000010", + }, + { + caseName: "failuer", + payload: "{\"jsonrpc\":\"2.0\",\"id\":1,\"error\":{\"code\":-32000,\"message\":\"error\"}}", + appendAPI: true, + isError: true, + expected: "historical backend error: error", + }, + } + + for _, tt := range table { + t.Run(tt.caseName, func(t *testing.T) { + if tt.appendAPI { + s := MockServer{} + s.Start() + defer s.Stop() + historicalRPCService, err := s.GetRPC() + if err != nil { + t.Errorf("failed to start mock server: %v", err) + } + api.historicalRPCService = historicalRPCService + s.UpdatePayload(tt.payload) + } + + val, err := api.GetStorageAt(m.Ctx, addr, "1", rpc.BlockNumberOrHashWithNumber(0)) + if tt.isError { + require.Error(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", err), tt.caseName) + } else { + require.NoError(t, err, tt.caseName) + require.Equal(t, tt.expected, fmt.Sprintf("%v", val), tt.caseName) + } + }) + } +}

Format deposit and L1-cost data in transaction responses.

diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_api.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_api.go index c3f076c99e42047a3e6ec76865de055fa5dda602..e7d6334beb329f300d90c3e87657c5ea9979b8ce 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_api.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_api.go @@ -124,9 +124,17 @@ _engine consensus.EngineReader   evmCallTimeout time.Duration dirs datadir.Dirs + + // Optimism specific field + seqRPCService *rpc.Client + historicalRPCService *rpc.Client }   -func NewBaseApi(f *rpchelper.Filters, stateCache kvcache.Cache, blockReader services.FullBlockReader, agg *libstate.AggregatorV3, singleNodeMode bool, evmCallTimeout time.Duration, engine consensus.EngineReader, dirs datadir.Dirs) *BaseAPI { +func NewBaseApi( + f *rpchelper.Filters, stateCache kvcache.Cache, blockReader services.FullBlockReader, agg *libstate.AggregatorV3, + singleNodeMode bool, evmCallTimeout time.Duration, engine consensus.EngineReader, dirs datadir.Dirs, + seqRPCService *rpc.Client, historicalRPCService *rpc.Client, +) *BaseAPI { blocksLRUSize := 128 // ~32Mb if !singleNodeMode { blocksLRUSize = 512 @@ -136,7 +144,11 @@ if err != nil { panic(err) }   - return &BaseAPI{filters: f, stateCache: stateCache, blocksLRU: blocksLRU, _blockReader: blockReader, _txnReader: blockReader, _agg: agg, evmCallTimeout: evmCallTimeout, _engine: engine, dirs: dirs} + return &BaseAPI{ + filters: f, stateCache: stateCache, blocksLRU: blocksLRU, _blockReader: blockReader, _txnReader: blockReader, + _agg: agg, evmCallTimeout: evmCallTimeout, _engine: engine, dirs: dirs, + seqRPCService: seqRPCService, historicalRPCService: historicalRPCService, + } }   func (api *BaseAPI) chainConfig(tx kv.Tx) (*chain.Config, error) { @@ -178,6 +190,20 @@ return nil, nil }   return api.blockWithSenders(tx, hash, *number) +} + +func (api *BaseAPI) blockNumberFromBlockNumberOrHash(tx kv.Tx, bnh *rpc.BlockNumberOrHash) (uint64, error) { + if number, ok := bnh.Number(); ok { + return uint64(number.Int64()), nil + } + if hash, ok := bnh.Hash(); ok { + number := rawdb.ReadHeaderNumber(tx, hash) + if number == nil { + return 0, fmt.Errorf("block %x not found", hash) + } + return *number, nil + } + return 0, fmt.Errorf("invalid block number of hash") }   func (api *BaseAPI) blockWithSenders(tx kv.Tx, hash common.Hash, number uint64) (*types.Block, error) { @@ -352,6 +378,10 @@ logger: logger, } }   +func (api *APIImpl) relayToHistoricalBackend(ctx context.Context, result interface{}, method string, args ...interface{}) error { + return api.historicalRPCService.CallContext(ctx, result, method, args...) +} + // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction type RPCTransaction struct { BlockHash *common.Hash `json:"blockHash"` @@ -364,7 +394,7 @@ FeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` Hash common.Hash `json:"hash"` Input hexutility.Bytes `json:"input"` Nonce hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` + To *common.Address `json:"to,omitempty"` TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` Value *hexutil.Big `json:"value"` Type hexutil.Uint64 `json:"type"` @@ -372,14 +402,22 @@ Accesses *types2.AccessList `json:"accessList,omitempty"` ChainID *hexutil.Big `json:"chainId,omitempty"` MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` + V *hexutil.Big `json:"v,omitempty"` + R *hexutil.Big `json:"r,omitempty"` + S *hexutil.Big `json:"s,omitempty"` + + // deposit-tx only + SourceHash *common.Hash `json:"sourceHash,omitempty"` + Mint *hexutil.Big `json:"mint,omitempty"` + IsSystemTx *bool `json:"isSystemTx,omitempty"` + // deposit-tx post-Canyon only + DepositReceiptVersion *hexutil.Uint64 `json:"depositReceiptVersion,omitempty"` }   // NewRPCTransaction returns a transaction that will serialize to the RPC // representation, with the given location metadata set (if available). -func NewRPCTransaction(tx types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int) *RPCTransaction { +func NewRPCTransaction(tx types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int, + receipt *types.Receipt) *RPCTransaction { // Determine the signer. For replay-protected transactions, use the most permissive // signer, because we assume that signers are backwards-compatible with old // transactions. For non-protected transactions, the homestead signer signer is used @@ -396,10 +434,13 @@ Value: (*hexutil.Big)(tx.GetValue().ToBig()), } switch t := tx.(type) { case *types.LegacyTx: - chainId = types.DeriveChainId(&t.V) - // if a legacy transaction has an EIP-155 chain id, include it explicitly, otherwise chain id is not included - if !chainId.IsZero() { - result.ChainID = (*hexutil.Big)(chainId.ToBig()) + // avoid overflow by not calling DeriveChainId. chain id not included when v = 0 + if !t.V.IsZero() { + chainId = types.DeriveChainId(&t.V) + // if a legacy transaction has an EIP-155 chain id, include it explicitly, otherwise chain id is not included + if !chainId.IsZero() { + result.ChainID = (*hexutil.Big)(chainId.ToBig()) + } } result.GasPrice = (*hexutil.Big)(t.GasPrice.ToBig()) result.V = (*hexutil.Big)(t.V.ToBig()) @@ -423,6 +464,27 @@ result.R = (*hexutil.Big)(t.R.ToBig()) result.S = (*hexutil.Big)(t.S.ToBig()) result.Accesses = &t.AccessList result.GasPrice = computeGasPrice(tx, blockHash, baseFee) + case *types.DepositTx: + if t.Mint != nil { + result.Mint = (*hexutil.Big)(t.Mint.ToBig()) + } + result.ChainID = nil + result.SourceHash = &t.SourceHash + if t.IsSystemTransaction { + result.IsSystemTx = &t.IsSystemTransaction + } + if receipt != nil && receipt.DepositNonce != nil { + result.Nonce = hexutil.Uint64(*receipt.DepositNonce) + if receipt.DepositReceiptVersion != nil { + result.DepositReceiptVersion = new(hexutil.Uint64) + *result.DepositReceiptVersion = hexutil.Uint64(*receipt.DepositReceiptVersion) + } + } + result.GasPrice = (*hexutil.Big)(common.Big0) + // must contain v, r, s values for backwards compatibility. + result.V = (*hexutil.Big)(common.Big0) + result.R = (*hexutil.Big)(common.Big0) + result.S = (*hexutil.Big)(common.Big0) case *types.BlobTx: chainId.Set(t.ChainID) result.ChainID = (*hexutil.Big)(chainId.ToBig()) @@ -488,9 +550,9 @@ // newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation func newRPCPendingTransaction(tx types.Transaction, current *types.Header, config *chain.Config) *RPCTransaction { var baseFee *big.Int if current != nil { - baseFee = misc.CalcBaseFee(config, current) + baseFee = misc.CalcBaseFee(config, current, current.Time+1) } - return NewRPCTransaction(tx, common.Hash{}, 0, 0, baseFee) + return NewRPCTransaction(tx, common.Hash{}, 0, 0, baseFee, nil) }   // newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
diff --git ledgerwatch/erigon/turbo/adapter/ethapi/api.go bobanetwork/v3-erigon/turbo/adapter/ethapi/api.go index c8084e11622fba82c5a8a3cc728e758be1fc5079..d40b0c2e795fa595d49df66d9dc48fcb3996e71e 100644 --- ledgerwatch/erigon/turbo/adapter/ethapi/api.go +++ bobanetwork/v3-erigon/turbo/adapter/ethapi/api.go @@ -19,8 +19,9 @@ import ( "errors" "fmt" + "math/big" + "github.com/ledgerwatch/erigon-lib/common/hexutil" - "math/big"   "github.com/holiman/uint256" libcommon "github.com/ledgerwatch/erigon-lib/common" @@ -305,11 +306,11 @@ // RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // transaction hashes. -func RPCMarshalBlockDeprecated(block *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - return RPCMarshalBlockExDeprecated(block, inclTx, fullTx, nil, libcommon.Hash{}) +func RPCMarshalBlockDeprecated(block *types.Block, inclTx bool, fullTx bool, receipts types.Receipts) (map[string]interface{}, error) { + return RPCMarshalBlockExDeprecated(block, inclTx, fullTx, nil, libcommon.Hash{}, receipts) }   -func RPCMarshalBlockExDeprecated(block *types.Block, inclTx bool, fullTx bool, borTx types.Transaction, borTxHash libcommon.Hash) (map[string]interface{}, error) { +func RPCMarshalBlockExDeprecated(block *types.Block, inclTx bool, fullTx bool, borTx types.Transaction, borTxHash libcommon.Hash, receipts types.Receipts) (map[string]interface{}, error) { fields := RPCMarshalHeader(block.Header()) fields["size"] = hexutil.Uint64(block.Size()) if _, ok := fields["transactions"]; !ok { @@ -317,19 +318,31 @@ fields["transactions"] = make([]interface{}, 0) }   if inclTx { - formatTx := func(tx types.Transaction, index int) (interface{}, error) { + formatTx := func(tx types.Transaction, index int, dn *uint64) (interface{}, error) { return tx.Hash(), nil } if fullTx { - formatTx = func(tx types.Transaction, index int) (interface{}, error) { - return newRPCTransactionFromBlockAndTxGivenIndex(block, tx, uint64(index)), nil + formatTx = func(tx types.Transaction, index int, dn *uint64) (interface{}, error) { + rpcTx := newRPCTransactionFromBlockAndTxGivenIndex(block, tx, uint64(index), receipts[index]) + if dn != nil { + rpcTx.Nonce = hexutil.Uint64(*dn) + } + return rpcTx, nil } } txs := block.Transactions() transactions := make([]interface{}, len(txs), len(txs)+1) + if receipts == nil { + // ensure that depositNonces is always initialized for formatTx + receipts = make([]*types.Receipt, len(txs)) + } var err error for i, tx := range txs { - if transactions[i], err = formatTx(tx, i); err != nil { + var dn *uint64 + if tx.Type() == types.DepositTxType && receipts != nil { + dn = receipts[i].DepositNonce + } + if transactions[i], err = formatTx(tx, i, dn); err != nil { return nil, err } } @@ -395,22 +408,28 @@ MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` Hash libcommon.Hash `json:"hash"` Input hexutility.Bytes `json:"input"` Nonce hexutil.Uint64 `json:"nonce"` - To *libcommon.Address `json:"to"` + To *libcommon.Address `json:"to,omitempty"` TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` Value *hexutil.Big `json:"value"` Type hexutil.Uint64 `json:"type"` Accesses *types2.AccessList `json:"accessList,omitempty"` ChainID *hexutil.Big `json:"chainId,omitempty"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` + V *hexutil.Big `json:"v,omitempty"` + R *hexutil.Big `json:"r,omitempty"` + S *hexutil.Big `json:"s,omitempty"`   BlobVersionedHashes []libcommon.Hash `json:"blobVersionedHashes,omitempty"` + // deposit-tx only + SourceHash *libcommon.Hash `json:"sourceHash,omitempty"` + Mint *hexutil.Big `json:"mint,omitempty"` + IsSystemTx *bool `json:"isSystemTx,omitempty"` + // deposit-tx post-Canyon only + DepositReceiptVersion *hexutil.Uint64 `json:"depositReceiptVersion,omitempty"` }   // newRPCTransaction returns a transaction that will serialize to the RPC // representation, with the given location metadata set (if available). -func newRPCTransaction(tx types.Transaction, blockHash libcommon.Hash, blockNumber uint64, index uint64, baseFee *big.Int) *RPCTransaction { +func newRPCTransaction(tx types.Transaction, blockHash libcommon.Hash, blockNumber uint64, index uint64, baseFee *big.Int, receipt *types.Receipt) *RPCTransaction { // Determine the signer. For replay-protected transactions, use the most permissive // signer, because we assume that signers are backwards-compatible with old // transactions. For non-protected transactions, the homestead signer signer is used @@ -427,10 +446,13 @@ Value: (*hexutil.Big)(tx.GetValue().ToBig()), } switch t := tx.(type) { case *types.LegacyTx: - chainId = types.DeriveChainId(&t.V) - // if a legacy transaction has an EIP-155 chain id, include it explicitly, otherwise chain id is not included - if !chainId.IsZero() { - result.ChainID = (*hexutil.Big)(chainId.ToBig()) + // avoid overflow by not calling DeriveChainId. chain id not included when v = 0 + if !t.V.IsZero() { + chainId = types.DeriveChainId(&t.V) + // if a legacy transaction has an EIP-155 chain id, include it explicitly, otherwise chain id is not included + if !chainId.IsZero() { + result.ChainID = (*hexutil.Big)(chainId.ToBig()) + } } result.GasPrice = (*hexutil.Big)(t.GasPrice.ToBig()) result.V = (*hexutil.Big)(t.V.ToBig()) @@ -455,6 +477,26 @@ result.S = (*hexutil.Big)(t.S.ToBig()) result.Accesses = &t.AccessList // if the transaction has been mined, compute the effective gas price result.GasPrice = computeGasPrice(tx, blockHash, baseFee) + case *types.DepositTx: + if t.Mint != nil { + result.Mint = (*hexutil.Big)(t.Mint.ToBig()) + } + result.SourceHash = &t.SourceHash + if t.IsSystemTransaction { + result.IsSystemTx = &t.IsSystemTransaction + } + if receipt != nil && receipt.DepositNonce != nil { + result.Nonce = hexutil.Uint64(*receipt.DepositNonce) + if receipt.DepositReceiptVersion != nil { + result.DepositReceiptVersion = new(hexutil.Uint64) + *result.DepositReceiptVersion = hexutil.Uint64(*receipt.DepositReceiptVersion) + } + } + result.GasPrice = (*hexutil.Big)(libcommon.Big0) + // must contain v, r, s values for backwards compatibility. + result.V = (*hexutil.Big)(libcommon.Big0) + result.R = (*hexutil.Big)(libcommon.Big0) + result.S = (*hexutil.Big)(libcommon.Big0) case *types.BlobTx: chainId.Set(t.ChainID) result.ChainID = (*hexutil.Big)(chainId.ToBig()) @@ -538,8 +580,8 @@ } */   // newRPCTransactionFromBlockAndTxGivenIndex returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockAndTxGivenIndex(b *types.Block, tx types.Transaction, index uint64) *RPCTransaction { - return newRPCTransaction(tx, b.Hash(), b.NumberU64(), index, b.BaseFee()) +func newRPCTransactionFromBlockAndTxGivenIndex(b *types.Block, tx types.Transaction, index uint64, receipt *types.Receipt) *RPCTransaction { + return newRPCTransaction(tx, b.Hash(), b.NumberU64(), index, b.BaseFee(), receipt) }   /* @@ -736,6 +778,17 @@ "contractAddress": nil, "logs": receipt.Logs, "logsBloom": receipt.Bloom, "type": hexutil.Uint(tx.Type()), + "effectiveGasPrice": (*hexutil.Big)(receipt.EffectiveGasPrice), + } + + if s.b.ChainConfig().Optimism != nil && !tx.IsDepositTx() { + fields["l1GasPrice"] = (*hexutil.Big)(receipt.L1GasPrice) + fields["l1GasUsed"] = (*hexutil.Big)(receipt.L1GasUsed) + fields["l1Fee"] = (*hexutil.Big)(receipt.L1Fee) + fields["l1FeeScalar"] = receipt.FeeScalar.String() + } + if s.b.ChainConfig().Optimism != nil && tx.IsDepositTx() && receipt.DepositNonce != nil { + fields["depositNonce"] = hexutil.Uint64(*receipt.DepositNonce) }   // Assign receipt status or post state.
diff --git ledgerwatch/erigon/turbo/adapter/ethapi/internal.go bobanetwork/v3-erigon/turbo/adapter/ethapi/internal.go index 67e985ade1e19354de132fc6a6f962cd1ae8e0db..571c515e5e2640beae4971edc87b96047a7b637b 100644 --- ledgerwatch/erigon/turbo/adapter/ethapi/internal.go +++ bobanetwork/v3-erigon/turbo/adapter/ethapi/internal.go @@ -8,8 +8,8 @@ "github.com/ledgerwatch/erigon/core/types" )   // nolint -func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool, additional map[string]interface{}) (map[string]interface{}, error) { - fields, err := RPCMarshalBlockDeprecated(b, inclTx, fullTx) +func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool, additional map[string]interface{}, receipts types.Receipts) (map[string]interface{}, error) { + fields, err := RPCMarshalBlockDeprecated(b, inclTx, fullTx, receipts) if err != nil { return nil, err } @@ -22,8 +22,8 @@ return fields, err }   // nolint -func RPCMarshalBlockEx(b *types.Block, inclTx bool, fullTx bool, borTx types.Transaction, borTxHash libcommon.Hash, additional map[string]interface{}) (map[string]interface{}, error) { - fields, err := RPCMarshalBlockExDeprecated(b, inclTx, fullTx, borTx, borTxHash) +func RPCMarshalBlockEx(b *types.Block, inclTx bool, fullTx bool, borTx types.Transaction, borTxHash libcommon.Hash, additional map[string]interface{}, receipts types.Receipts) (map[string]interface{}, error) { + fields, err := RPCMarshalBlockExDeprecated(b, inclTx, fullTx, borTx, borTxHash, receipts) if err != nil { return nil, err }
diff --git ledgerwatch/erigon/turbo/jsonrpc/erigon_block.go bobanetwork/v3-erigon/turbo/jsonrpc/erigon_block.go index 879dbfd26fdd3f45fb50db5b2e2a0ad0e4fc5934..e1b5c015407f44a7cf4034979d101a702c1b8dce 100644 --- ledgerwatch/erigon/turbo/jsonrpc/erigon_block.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/erigon_block.go @@ -5,8 +5,9 @@ "bytes" "context" "errors" "fmt" + "sort" + "github.com/ledgerwatch/erigon-lib/common/hexutil" - "sort"   "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/common" @@ -190,7 +191,8 @@ if td != nil { additionalFields["totalDifficulty"] = (*hexutil.Big)(td) }   - response, err := ethapi.RPCMarshalBlockEx(block, true, fullTx, nil, common.Hash{}, additionalFields) + receipts := rawdb.ReadRawReceipts(db, blockNum) + response, err := ethapi.RPCMarshalBlockEx(block, true, fullTx, nil, common.Hash{}, additionalFields, receipts)   if err == nil && rpc.BlockNumber(block.NumberU64()) == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_block.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_block.go index e40cbff926a6cdcaaf829428afdb1f9433d1ca5a..88cd139c5ce1a03eaf13481e069ab8b86f024942 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_block.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_block.go @@ -6,16 +6,16 @@ "fmt" "math/big" "time"   - "github.com/ledgerwatch/erigon-lib/common/hexutil" - "github.com/ledgerwatch/erigon/cl/clparams" - "github.com/ledgerwatch/erigon/polygon/bor/borcfg" - "github.com/ledgerwatch/log/v3"   "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutil" "github.com/ledgerwatch/erigon-lib/common/hexutility" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/opstack" + "github.com/ledgerwatch/erigon/polygon/bor/borcfg"   + "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/common/math" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" @@ -124,6 +124,7 @@ }   blockCtx := transactions.NewEVMBlockContext(engine, header, stateBlockNumberOrHash.RequireCanonical, tx, api._blockReader) txCtx := core.NewEVMTxContext(firstMsg) + blockCtx.L1CostFunc = opstack.NewL1CostFunc(chainConfig, ibs) // Get a new instance of the EVM evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vm.Config{Debug: false})   @@ -204,6 +205,15 @@ if err != nil { return nil, err } defer tx.Rollback() + + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, err + } + if chainConfig.IsOptimism() && number == rpc.PendingBlockNumber { + number = rpc.LatestBlockNumber + } + b, err := api.blockByNumber(ctx, number, tx) if err != nil { return nil, err @@ -220,10 +230,6 @@ if td != nil { additionalFields["totalDifficulty"] = (*hexutil.Big)(td) }   - chainConfig, err := api.chainConfig(tx) - if err != nil { - return nil, err - } var borTx types.Transaction var borTxHash common.Hash if chainConfig.Bor != nil { @@ -233,8 +239,15 @@ borTxHash = types.ComputeBorTxHash(b.NumberU64(), b.Hash()) } }   - response, err := ethapi.RPCMarshalBlockEx(b, true, fullTx, borTx, borTxHash, additionalFields) - if err == nil && number == rpc.PendingBlockNumber { + // Optimism Deposit transactions need to access DepositNonce from their receipt. + // A possible optimization would be to filter by Tx type and only populate the entries for the Deposits + receipts, err := api.getReceipts(ctx, tx, chainConfig, b, b.Body().SendersFromTxs()) + if err != nil { + return nil, fmt.Errorf("getReceipts error: %w", err) + } + + response, err := ethapi.RPCMarshalBlockEx(b, true, fullTx, borTx, borTxHash, additionalFields, receipts) + if err == nil && number == rpc.PendingBlockNumber && chainConfig.Optimism == nil { // don't remove info if optimism // Pending blocks need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { response[field] = nil @@ -292,7 +305,14 @@ borTxHash = types.ComputeBorTxHash(number, block.Hash()) } }   - response, err := ethapi.RPCMarshalBlockEx(block, true, fullTx, borTx, borTxHash, additionalFields) + // Optimism Deposit transactions need to access DepositNonce from their receipt. + // A possible optimization would be to filter by Tx type and only populate the entries for the Deposits + receipts, err := api.getReceipts(ctx, tx, chainConfig, block, block.Body().SendersFromTxs()) + if err != nil { + return nil, fmt.Errorf("getReceipts error: %w", err) + } + + response, err := ethapi.RPCMarshalBlockEx(block, true, fullTx, borTx, borTxHash, additionalFields, receipts)   if chainConfig.Bor != nil { borConfig := chainConfig.Bor.(*borcfg.BorConfig)
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_txs.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_txs.go index f0756797bd6661df1bc6130cd398bcb4d0332626..b84f6c0491e644681e21ec8f3fdd3897c6168748 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_txs.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_txs.go @@ -3,11 +3,11 @@ import ( "bytes" "context" + "fmt" "math/big"   - "github.com/ledgerwatch/erigon-lib/common/hexutil" - "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutil" "github.com/ledgerwatch/erigon-lib/common/hexutility" "github.com/ledgerwatch/erigon-lib/gointerfaces" "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" @@ -77,7 +77,15 @@ borTx := types2.NewBorTransaction() return newRPCBorTransaction(borTx, txnHash, blockHash, blockNum, uint64(len(block.Transactions())), baseFee, chainConfig.ChainID), nil }   - return NewRPCTransaction(txn, blockHash, blockNum, txnIndex, baseFee), nil + if chainConfig.IsOptimism() { + receipts := rawdb.ReadRawReceipts(tx, block.NumberU64()) + if len(receipts) <= int(txnIndex) { + return nil, fmt.Errorf("block has less receipts than expected: %d <= %d, block: %d", len(receipts), int(txnIndex), blockNum) + } + return NewRPCTransaction(txn, blockHash, blockNum, txnIndex, baseFee, receipts[txnIndex]), nil + } + + return NewRPCTransaction(txn, blockHash, blockNum, txnIndex, baseFee, nil), nil }   curHeader := rawdb.ReadCurrentHeader(tx) @@ -192,7 +200,15 @@ derivedBorTxHash := types2.ComputeBorTxHash(block.NumberU64(), block.Hash()) return newRPCBorTransaction(borTx, derivedBorTxHash, block.Hash(), block.NumberU64(), uint64(txIndex), block.BaseFee(), chainConfig.ChainID), nil }   - return NewRPCTransaction(txs[txIndex], block.Hash(), block.NumberU64(), uint64(txIndex), block.BaseFee()), nil + if chainConfig.IsOptimism() { + receipts := rawdb.ReadRawReceipts(tx, block.NumberU64()) + if len(receipts) <= int(txIndex) { + return nil, fmt.Errorf("block has less receipts than expected: %d <= %d, block: %d", len(receipts), int(txIndex), block.NumberU64()) + } + return NewRPCTransaction(txs[txIndex], block.Hash(), block.NumberU64(), uint64(txIndex), block.BaseFee(), receipts[txIndex]), nil + } + + return NewRPCTransaction(txs[txIndex], block.Hash(), block.NumberU64(), uint64(txIndex), block.BaseFee(), nil), nil }   // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. @@ -255,8 +271,14 @@ } derivedBorTxHash := types2.ComputeBorTxHash(blockNum, hash) return newRPCBorTransaction(borTx, derivedBorTxHash, hash, blockNum, uint64(txIndex), block.BaseFee(), chainConfig.ChainID), nil } - - return NewRPCTransaction(txs[txIndex], hash, blockNum, uint64(txIndex), block.BaseFee()), nil + if chainConfig.IsOptimism() { + receipts := rawdb.ReadRawReceipts(tx, block.NumberU64()) + if len(receipts) <= int(txIndex) { + return nil, fmt.Errorf("block has less receipts than expected: %d <= %d, block: %d", len(receipts), int(txIndex), block.NumberU64()) + } + return NewRPCTransaction(txs[txIndex], block.Hash(), blockNum, uint64(txIndex), block.BaseFee(), receipts[txIndex]), nil + } + return NewRPCTransaction(txs[txIndex], hash, blockNum, uint64(txIndex), block.BaseFee(), nil), nil }   // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index.
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_uncles.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_uncles.go index 8d0acf589c94232708d24ed7c5362b21559ec10f..c58cbab628bc42ab4da757b149616937871bb725 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_uncles.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_uncles.go @@ -2,6 +2,7 @@ package jsonrpc   import ( "context" + "github.com/ledgerwatch/erigon-lib/common/hexutil"   "github.com/ledgerwatch/erigon-lib/common" @@ -46,7 +47,8 @@ log.Trace("Requested uncle not found", "number", block.Number(), "hash", hash, "index", index) return nil, nil } uncle := types.NewBlockWithHeader(uncles[index]) - return ethapi.RPCMarshalBlock(uncle, false, false, additionalFields) + receipts := rawdb.ReadRawReceipts(tx, blockNum) + return ethapi.RPCMarshalBlock(uncle, false, false, additionalFields, receipts) }   // GetUncleByBlockHashAndIndex implements eth_getUncleByBlockHashAndIndex. Returns information about an uncle given a block's hash and the index of the uncle. @@ -78,8 +80,8 @@ log.Trace("Requested uncle not found", "number", block.Number(), "hash", hash, "index", index) return nil, nil } uncle := types.NewBlockWithHeader(uncles[index]) - - return ethapi.RPCMarshalBlock(uncle, false, false, additionalFields) + receipts := rawdb.ReadRawReceipts(tx, number) + return ethapi.RPCMarshalBlock(uncle, false, false, additionalFields, receipts) }   // GetUncleCountByBlockNumber implements eth_getUncleCountByBlockNumber. Returns the number of uncles in the block, if any.
diff --git ledgerwatch/erigon/turbo/jsonrpc/otterscan_api.go bobanetwork/v3-erigon/turbo/jsonrpc/otterscan_api.go index 9b14b8588f2c0774cf07b30ab134a0ef3044a851..b893d6a8b7490e7967d9c4546b13bfe406606893 100644 --- ledgerwatch/erigon/turbo/jsonrpc/otterscan_api.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/otterscan_api.go @@ -6,8 +6,9 @@ "errors" "fmt" "math/big"   + "golang.org/x/sync/errgroup" + hexutil2 "github.com/ledgerwatch/erigon-lib/common/hexutil" - "golang.org/x/sync/errgroup"   "github.com/holiman/uint256" "github.com/ledgerwatch/log/v3" @@ -128,6 +129,7 @@ chainConfig, err := api.chainConfig(tx) if err != nil { return nil, err } + engine := api.engine()   msg, blockCtx, txCtx, ibs, _, err := transactions.ComputeTxEnv(ctx, engine, block, chainConfig, api._blockReader, tx, int(txIndex), api.historyV3(tx)) @@ -325,9 +327,20 @@ rawLogs, res, err := exec.execTx(txNum, txIndex, txn) if err != nil { return nil, err } - rpcTx := NewRPCTransaction(txn, blockHash, blockNum, uint64(txIndex), header.BaseFee) + var rpcTx *RPCTransaction + var receipt *types.Receipt + if chainConfig.IsOptimism() { + receipts := rawdb.ReadRawReceipts(tx, blockNum) + if len(receipts) <= txIndex { + return nil, fmt.Errorf("block has less receipts than expected: %d <= %d, block: %d", len(receipts), txIndex, blockNum) + } + receipt = receipts[txIndex] + rpcTx = NewRPCTransaction(txn, blockHash, blockNum, uint64(txIndex), header.BaseFee, receipt) + } else { + rpcTx = NewRPCTransaction(txn, blockHash, blockNum, uint64(txIndex), header.BaseFee, nil) + } txs = append(txs, rpcTx) - receipt := &types.Receipt{ + receipt = &types.Receipt{ Type: txn.Type(), CumulativeGasUsed: res.UsedGas, TransactionIndex: uint(txIndex), BlockNumber: header.Number, BlockHash: blockHash, Logs: rawLogs, @@ -482,7 +495,8 @@ if err != nil { return nil, err } additionalFields := make(map[string]interface{}) - response, err := ethapi.RPCMarshalBlock(b, inclTx, inclTx, additionalFields) + receipts := rawdb.ReadRawReceipts(tx, uint64(number.Int64())) + response, err := ethapi.RPCMarshalBlock(b, inclTx, inclTx, additionalFields, receipts) if !inclTx { delete(response, "transactions") // workaround for https://github.com/ledgerwatch/erigon/issues/4989#issuecomment-1218415666 }
diff --git ledgerwatch/erigon/turbo/jsonrpc/otterscan_generic_tracer.go bobanetwork/v3-erigon/turbo/jsonrpc/otterscan_generic_tracer.go index 182f07795a7eb109e6c32c44d3e5c0242d2ca552..b18896c70a11129099cc8c312553e629e06b2b77 100644 --- ledgerwatch/erigon/turbo/jsonrpc/otterscan_generic_tracer.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/otterscan_generic_tracer.go @@ -2,6 +2,7 @@ package jsonrpc   import ( "context" + "github.com/ledgerwatch/erigon-lib/opstack"   "github.com/ledgerwatch/erigon-lib/chain" "github.com/ledgerwatch/erigon-lib/common" @@ -95,6 +96,7 @@ msg, _ := tx.AsMessage(*signer, header.BaseFee, rules)   BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil) + BlockContext.L1CostFunc = opstack.NewL1CostFunc(chainConfig, ibs) TxContext := core.NewEVMTxContext(msg)   vmenv := vm.NewEVM(BlockContext, TxContext, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer})
diff --git ledgerwatch/erigon/turbo/jsonrpc/otterscan_search_trace.go bobanetwork/v3-erigon/turbo/jsonrpc/otterscan_search_trace.go index c4ed35a2530b5c04ad0d702a5a7a95698b6bbf21..7c501d627a90e7fdc12a534564eef9f8842c3ac6 100644 --- ledgerwatch/erigon/turbo/jsonrpc/otterscan_search_trace.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/otterscan_search_trace.go @@ -7,15 +7,16 @@ "github.com/ledgerwatch/erigon-lib/chain" "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" - "github.com/ledgerwatch/erigon/turbo/rpchelper" - "github.com/ledgerwatch/log/v3" + "github.com/ledgerwatch/erigon-lib/opstack"   "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/state" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/core/vm" + "github.com/ledgerwatch/erigon/turbo/rpchelper" "github.com/ledgerwatch/erigon/turbo/shards" + "github.com/ledgerwatch/log/v3" )   func (api *OtterscanAPIImpl) searchTraceBlock(ctx context.Context, addr common.Address, chainConfig *chain.Config, idx int, bNum uint64, results []*TransactionsWithReceipts) { @@ -73,10 +74,11 @@ return h } engine := api.engine()   - blockReceipts := rawdb.ReadReceipts(dbtx, block, senders) + blockReceipts := rawdb.ReadReceipts(chainConfig, dbtx, block, senders) header := block.Header() rules := chainConfig.Rules(block.NumberU64(), header.Time) found := false + for idx, tx := range block.Transactions() { select { case <-ctx.Done(): @@ -89,6 +91,7 @@ msg, _ := tx.AsMessage(*signer, header.BaseFee, rules)   tracer := NewTouchTracer(searchAddr) BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil) + BlockContext.L1CostFunc = opstack.NewL1CostFunc(chainConfig, ibs) TxContext := core.NewEVMTxContext(msg)   vmenv := vm.NewEVM(BlockContext, TxContext, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer}) @@ -98,6 +101,10 @@ } _ = ibs.FinalizeTx(rules, cachedWriter)   if tracer.Found { + var receipt *types.Receipt + if chainConfig.IsOptimism() && idx < len(block.Transactions()) { + receipt = blockReceipts[idx] + } if idx > len(blockReceipts) { select { // it may happen because request canceled, then return canelation error case <-ctx.Done(): @@ -106,7 +113,7 @@ default: } return false, nil, fmt.Errorf("requested receipt idx %d, but have only %d", idx, len(blockReceipts)) // otherwise return some error for debugging } - rpcTx := NewRPCTransaction(tx, block.Hash(), blockNum, uint64(idx), block.BaseFee()) + rpcTx := NewRPCTransaction(tx, block.Hash(), blockNum, uint64(idx), block.BaseFee(), receipt) mReceipt := marshalReceipt(blockReceipts[idx], tx, chainConfig, block.HeaderNoCopy(), tx.Hash(), true) mReceipt["timestamp"] = block.Time() rpcTxs = append(rpcTxs, rpcTx)
diff --git ledgerwatch/erigon/core/types/receipt_codecgen_gen.go bobanetwork/v3-erigon/core/types/receipt_codecgen_gen.go index e2bc7db9db1f1e9bba2ed75a6cc84f685079bf75..95f37b090661596e5f42e400d584e391ca647653 100644 --- ledgerwatch/erigon/core/types/receipt_codecgen_gen.go +++ bobanetwork/v3-erigon/core/types/receipt_codecgen_gen.go @@ -7,10 +7,11 @@ package types   import ( "errors" - libcommon "github.com/ledgerwatch/erigon-lib/common" + pkg1_common "github.com/ledgerwatch/erigon-lib/common" codec1978 "github.com/ugorji/go/codec" pkg2_big "math/big" "runtime" + "sort" "strconv" )   @@ -31,7 +32,8 @@ codecSelferDecContainerLenNil2 = -2147483648 )   var ( - errCodecSelferOnlyMapOrArrayEncodeToStruct2 = errors.New(`only encoded map or array can be decoded into a struct`) + errCodecSelferOnlyMapOrArrayEncodeToStruct2 = errors.New(`only encoded map or array can be decoded into a struct`) + _ sort.Interface = nil )   type codecSelfer2 struct{} @@ -39,22 +41,51 @@ func codecSelfer2False() bool { return false } func codecSelfer2True() bool { return true }   +type codecSelfer2stringSlice []string + +func (p codecSelfer2stringSlice) Len() int { return len(p) } +func (p codecSelfer2stringSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } +func (p codecSelfer2stringSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } + +type codecSelfer2uint64Slice []uint64 + +func (p codecSelfer2uint64Slice) Len() int { return len(p) } +func (p codecSelfer2uint64Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } +func (p codecSelfer2uint64Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } + +type codecSelfer2int64Slice []int64 + +func (p codecSelfer2int64Slice) Len() int { return len(p) } +func (p codecSelfer2int64Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } +func (p codecSelfer2int64Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } + +type codecSelfer2float64Slice []float64 + +func (p codecSelfer2float64Slice) Len() int { return len(p) } +func (p codecSelfer2float64Slice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] } +func (p codecSelfer2float64Slice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] } + func init() { - if codec1978.GenVersion != 19 { + if codec1978.GenVersion != 28 { _, file, _, _ := runtime.Caller(0) ver := strconv.FormatInt(int64(codec1978.GenVersion), 10) - panic(errors.New("codecgen version mismatch: current: 19, need " + ver + ". Re-generate file: " + file)) + panic(errors.New("codecgen version mismatch: current: 28, need " + ver + ". Re-generate file: " + file)) } if false { // reference the types, but skip this branch at build/run time - var _ libcommon.Address + var _ pkg1_common.Address var _ pkg2_big.Int } }   +func (Receipt) codecSelferViaCodecgen() {} func (x *Receipt) CodecEncodeSelf(e *codec1978.Encoder) { var h codecSelfer2 - z, r := codec1978.GenHelperEncoder(e) + z, r := codec1978.GenHelper().Encoder(e) _, _, _ = h, z, r + if z.EncBasicHandle().CheckCircularRef { + z.EncEncode(x) + return + } if x == nil { r.EncodeNil() } else { @@ -64,7 +95,13 @@ } else { yy2arr2 := z.EncBasicHandle().StructToArray _ = yy2arr2 const yyr2 bool = false // struct tag has 'toArray' - z.EncWriteArrayStart(4) + var yyn7 bool = x.DepositNonce == nil + var yyn8 bool = x.L1GasPrice == nil + var yyn9 bool = x.L1GasUsed == nil + var yyn10 bool = x.L1Fee == nil + var yyn11 bool = x.FeeScalar == nil + var yyn12 bool = x.DepositReceiptVersion == nil + z.EncWriteArrayStart(10) z.EncWriteArrayElem() r.EncodeUint(uint64(x.Type)) z.EncWriteArrayElem() @@ -77,6 +114,66 @@ z.EncWriteArrayElem() r.EncodeUint(uint64(x.Status)) z.EncWriteArrayElem() r.EncodeUint(uint64(x.CumulativeGasUsed)) + if yyn7 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + yy17 := *x.DepositNonce + r.EncodeUint(uint64(yy17)) + } + if yyn8 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + if !z.EncBinary() && z.IsJSONHandle() { + z.EncJSONMarshal(x.L1GasPrice) + } else { + z.EncFallback(x.L1GasPrice) + } + } + if yyn9 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + if !z.EncBinary() && z.IsJSONHandle() { + z.EncJSONMarshal(x.L1GasUsed) + } else { + z.EncFallback(x.L1GasUsed) + } + } + if yyn10 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + if !z.EncBinary() && z.IsJSONHandle() { + z.EncJSONMarshal(x.L1Fee) + } else { + z.EncFallback(x.L1Fee) + } + } + if yyn11 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + if !z.EncBinary() { + z.EncTextMarshal(x.FeeScalar) + } else { + z.EncFallback(x.FeeScalar) + } + } + if yyn12 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + yy23 := *x.DepositReceiptVersion + r.EncodeUint(uint64(yy23)) + } z.EncWriteArrayEnd() } } @@ -84,7 +181,7 @@ }   func (x *Receipt) CodecDecodeSelf(d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(x) @@ -113,114 +210,281 @@ }   func (x *Receipt) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r var yyhl3 bool = l >= 0 - for yyj3 := 0; ; yyj3++ { - if yyhl3 { - if yyj3 >= l { - break - } - } else { - if z.DecCheckBreak() { - break - } - } + for yyj3 := 0; z.DecContainerNext(yyj3, l, yyhl3); yyj3++ { z.DecReadMapElemKey() - yys3 := z.StringView(r.DecodeStringAsBytes()) + yys3 := r.DecodeStringAsBytes() z.DecReadMapElemValue() - switch yys3 { + switch string(yys3) { case "Type": x.Type = (uint8)(z.C.UintV(r.DecodeUint64(), 8)) case "1": - x.PostState = r.DecodeBytes(([]byte)(x.PostState), false) + x.PostState = z.DecodeBytesInto(([]byte)(x.PostState)) case "2": x.Status = (uint64)(r.DecodeUint64()) case "3": x.CumulativeGasUsed = (uint64)(r.DecodeUint64()) + case "DepositNonce": + if r.TryNil() { + if x.DepositNonce != nil { // remove the if-true + x.DepositNonce = nil + } + } else { + if x.DepositNonce == nil { + x.DepositNonce = new(uint64) + } + *x.DepositNonce = (uint64)(r.DecodeUint64()) + } + case "L1GasPrice": + if r.TryNil() { + if x.L1GasPrice != nil { // remove the if-true + x.L1GasPrice = nil + } + } else { + if x.L1GasPrice == nil { + x.L1GasPrice = new(pkg2_big.Int) + } + if !z.DecBinary() && z.IsJSONHandle() { + z.DecJSONUnmarshal(x.L1GasPrice) + } else { + z.DecFallback(x.L1GasPrice, false) + } + } + case "L1GasUsed": + if r.TryNil() { + if x.L1GasUsed != nil { // remove the if-true + x.L1GasUsed = nil + } + } else { + if x.L1GasUsed == nil { + x.L1GasUsed = new(pkg2_big.Int) + } + if !z.DecBinary() && z.IsJSONHandle() { + z.DecJSONUnmarshal(x.L1GasUsed) + } else { + z.DecFallback(x.L1GasUsed, false) + } + } + case "L1Fee": + if r.TryNil() { + if x.L1Fee != nil { // remove the if-true + x.L1Fee = nil + } + } else { + if x.L1Fee == nil { + x.L1Fee = new(pkg2_big.Int) + } + if !z.DecBinary() && z.IsJSONHandle() { + z.DecJSONUnmarshal(x.L1Fee) + } else { + z.DecFallback(x.L1Fee, false) + } + } + case "FeeScalar": + if r.TryNil() { + if x.FeeScalar != nil { // remove the if-true + x.FeeScalar = nil + } + } else { + if x.FeeScalar == nil { + x.FeeScalar = new(pkg2_big.Float) + } + if !z.DecBinary() { + z.DecTextUnmarshal(x.FeeScalar) + } else { + z.DecFallback(x.FeeScalar, false) + } + } + case "DepositReceiptVersion": + if r.TryNil() { + if x.DepositReceiptVersion != nil { // remove the if-true + x.DepositReceiptVersion = nil + } + } else { + if x.DepositReceiptVersion == nil { + x.DepositReceiptVersion = new(uint64) + } + *x.DepositReceiptVersion = (uint64)(r.DecodeUint64()) + } default: - z.DecStructFieldNotFound(-1, yys3) + z.DecStructFieldNotFound(-1, string(yys3)) } // end switch yys3 } // end for yyj3 }   func (x *Receipt) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r - var yyj9 int - var yyb9 bool - var yyhl9 bool = l >= 0 - yyj9++ - if yyhl9 { - yyb9 = yyj9 > l + var yyj21 int + var yyb21 bool + var yyhl21 bool = l >= 0 + yyb21 = !z.DecContainerNext(yyj21, l, yyhl21) + if yyb21 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + x.Type = (uint8)(z.C.UintV(r.DecodeUint64(), 8)) + yyj21++ + yyb21 = !z.DecContainerNext(yyj21, l, yyhl21) + if yyb21 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + x.PostState = z.DecodeBytesInto(([]byte)(x.PostState)) + yyj21++ + yyb21 = !z.DecContainerNext(yyj21, l, yyhl21) + if yyb21 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + x.Status = (uint64)(r.DecodeUint64()) + yyj21++ + yyb21 = !z.DecContainerNext(yyj21, l, yyhl21) + if yyb21 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + x.CumulativeGasUsed = (uint64)(r.DecodeUint64()) + yyj21++ + yyb21 = !z.DecContainerNext(yyj21, l, yyhl21) + if yyb21 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + if r.TryNil() { + if x.DepositNonce != nil { // remove the if-true + x.DepositNonce = nil + } } else { - yyb9 = z.DecCheckBreak() + if x.DepositNonce == nil { + x.DepositNonce = new(uint64) + } + *x.DepositNonce = (uint64)(r.DecodeUint64()) } - if yyb9 { + yyj21++ + yyb21 = !z.DecContainerNext(yyj21, l, yyhl21) + if yyb21 { z.DecReadArrayEnd() return } z.DecReadArrayElem() - x.Type = (uint8)(z.C.UintV(r.DecodeUint64(), 8)) - yyj9++ - if yyhl9 { - yyb9 = yyj9 > l + if r.TryNil() { + if x.L1GasPrice != nil { // remove the if-true + x.L1GasPrice = nil + } } else { - yyb9 = z.DecCheckBreak() + if x.L1GasPrice == nil { + x.L1GasPrice = new(pkg2_big.Int) + } + if !z.DecBinary() && z.IsJSONHandle() { + z.DecJSONUnmarshal(x.L1GasPrice) + } else { + z.DecFallback(x.L1GasPrice, false) + } } - if yyb9 { + yyj21++ + yyb21 = !z.DecContainerNext(yyj21, l, yyhl21) + if yyb21 { z.DecReadArrayEnd() return } z.DecReadArrayElem() - x.PostState = r.DecodeBytes(([]byte)(x.PostState), false) - yyj9++ - if yyhl9 { - yyb9 = yyj9 > l + if r.TryNil() { + if x.L1GasUsed != nil { // remove the if-true + x.L1GasUsed = nil + } } else { - yyb9 = z.DecCheckBreak() + if x.L1GasUsed == nil { + x.L1GasUsed = new(pkg2_big.Int) + } + if !z.DecBinary() && z.IsJSONHandle() { + z.DecJSONUnmarshal(x.L1GasUsed) + } else { + z.DecFallback(x.L1GasUsed, false) + } } - if yyb9 { + yyj21++ + yyb21 = !z.DecContainerNext(yyj21, l, yyhl21) + if yyb21 { z.DecReadArrayEnd() return } z.DecReadArrayElem() - x.Status = (uint64)(r.DecodeUint64()) - yyj9++ - if yyhl9 { - yyb9 = yyj9 > l + if r.TryNil() { + if x.L1Fee != nil { // remove the if-true + x.L1Fee = nil + } } else { - yyb9 = z.DecCheckBreak() + if x.L1Fee == nil { + x.L1Fee = new(pkg2_big.Int) + } + if !z.DecBinary() && z.IsJSONHandle() { + z.DecJSONUnmarshal(x.L1Fee) + } else { + z.DecFallback(x.L1Fee, false) + } } - if yyb9 { + yyj21++ + yyb21 = !z.DecContainerNext(yyj21, l, yyhl21) + if yyb21 { z.DecReadArrayEnd() return } z.DecReadArrayElem() - x.CumulativeGasUsed = (uint64)(r.DecodeUint64()) - for { - yyj9++ - if yyhl9 { - yyb9 = yyj9 > l + if r.TryNil() { + if x.FeeScalar != nil { // remove the if-true + x.FeeScalar = nil + } + } else { + if x.FeeScalar == nil { + x.FeeScalar = new(pkg2_big.Float) + } + if !z.DecBinary() { + z.DecTextUnmarshal(x.FeeScalar) } else { - yyb9 = z.DecCheckBreak() + z.DecFallback(x.FeeScalar, false) } - if yyb9 { - break + } + yyj21++ + yyb21 = !z.DecContainerNext(yyj21, l, yyhl21) + if yyb21 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + if r.TryNil() { + if x.DepositReceiptVersion != nil { // remove the if-true + x.DepositReceiptVersion = nil + } + } else { + if x.DepositReceiptVersion == nil { + x.DepositReceiptVersion = new(uint64) } + *x.DepositReceiptVersion = (uint64)(r.DecodeUint64()) + } + yyj21++ + for ; z.DecContainerNext(yyj21, l, yyhl21); yyj21++ { z.DecReadArrayElem() - z.DecStructFieldNotFound(yyj9-1, "") + z.DecStructFieldNotFound(yyj21-1, "") } }   func (x *Receipt) IsCodecEmpty() bool { - return !(x.Type != 0 && len(x.PostState) != 0 && x.Status != 0 && x.CumulativeGasUsed != 0 && true) + return !(x.Type != 0 || len(x.PostState) != 0 || x.Status != 0 || x.CumulativeGasUsed != 0 || false) }   +func (Receipts) codecSelferViaCodecgen() {} func (x Receipts) CodecEncodeSelf(e *codec1978.Encoder) { var h codecSelfer2 - z, r := codec1978.GenHelperEncoder(e) + z, r := codec1978.GenHelper().Encoder(e) _, _, _ = h, z, r if x == nil { r.EncodeNil() @@ -231,15 +495,20 @@ }   func (x *Receipts) CodecDecodeSelf(d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r h.decReceipts((*Receipts)(x), d) }   +func (Log) codecSelferViaCodecgen() {} func (x *Log) CodecEncodeSelf(e *codec1978.Encoder) { var h codecSelfer2 - z, r := codec1978.GenHelperEncoder(e) + z, r := codec1978.GenHelper().Encoder(e) _, _, _ = h, z, r + if z.EncBasicHandle().CheckCircularRef { + z.EncEncode(x) + return + } if x == nil { r.EncodeNil() } else { @@ -255,13 +524,13 @@ yy6 := &x.Address if !z.EncBinary() { z.EncTextMarshal(*yy6) } else { - h.enccommon_Address((*libcommon.Address)(yy6), e) + z.F.EncSliceUint8V(([]uint8)(yy6[:]), e) } z.EncWriteArrayElem() if x.Topics == nil { r.EncodeNil() } else { - h.encSlicecommon_Hash(([]libcommon.Hash)(x.Topics), e) + h.encSlicecommon_Hash(([]pkg1_common.Hash)(x.Topics), e) } // end block: if x.Topics slice == nil z.EncWriteArrayElem() if x.Data == nil { @@ -276,7 +545,7 @@ }   func (x *Log) CodecDecodeSelf(d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(x) @@ -305,52 +574,38 @@ }   func (x *Log) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r var yyhl3 bool = l >= 0 - for yyj3 := 0; ; yyj3++ { - if yyhl3 { - if yyj3 >= l { - break - } - } else { - if z.DecCheckBreak() { - break - } - } + for yyj3 := 0; z.DecContainerNext(yyj3, l, yyhl3); yyj3++ { z.DecReadMapElemKey() - yys3 := z.StringView(r.DecodeStringAsBytes()) + yys3 := r.DecodeStringAsBytes() z.DecReadMapElemValue() - switch yys3 { + switch string(yys3) { case "1": if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(&x.Address) } else { - h.deccommon_Address((*libcommon.Address)(&x.Address), d) + z.F.DecSliceUint8N(([]uint8)(x.Address[:]), d) } case "2": - h.decSlicecommon_Hash((*[]libcommon.Hash)(&x.Topics), d) + h.decSlicecommon_Hash((*[]pkg1_common.Hash)(&x.Topics), d) case "3": - x.Data = r.DecodeBytes(([]byte)(x.Data), false) + x.Data = z.DecodeBytesInto(([]byte)(x.Data)) default: - z.DecStructFieldNotFound(-1, yys3) + z.DecStructFieldNotFound(-1, string(yys3)) } // end switch yys3 } // end for yyj3 }   func (x *Log) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r var yyj10 int var yyb10 bool var yyhl10 bool = l >= 0 - yyj10++ - if yyhl10 { - yyb10 = yyj10 > l - } else { - yyb10 = z.DecCheckBreak() - } + yyb10 = !z.DecContainerNext(yyj10, l, yyhl10) if yyb10 { z.DecReadArrayEnd() return @@ -359,54 +614,39 @@ z.DecReadArrayElem() if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(&x.Address) } else { - h.deccommon_Address((*libcommon.Address)(&x.Address), d) + z.F.DecSliceUint8N(([]uint8)(x.Address[:]), d) } yyj10++ - if yyhl10 { - yyb10 = yyj10 > l - } else { - yyb10 = z.DecCheckBreak() - } + yyb10 = !z.DecContainerNext(yyj10, l, yyhl10) if yyb10 { z.DecReadArrayEnd() return } z.DecReadArrayElem() - h.decSlicecommon_Hash((*[]libcommon.Hash)(&x.Topics), d) + h.decSlicecommon_Hash((*[]pkg1_common.Hash)(&x.Topics), d) yyj10++ - if yyhl10 { - yyb10 = yyj10 > l - } else { - yyb10 = z.DecCheckBreak() - } + yyb10 = !z.DecContainerNext(yyj10, l, yyhl10) if yyb10 { z.DecReadArrayEnd() return } z.DecReadArrayElem() - x.Data = r.DecodeBytes(([]byte)(x.Data), false) - for { - yyj10++ - if yyhl10 { - yyb10 = yyj10 > l - } else { - yyb10 = z.DecCheckBreak() - } - if yyb10 { - break - } + x.Data = z.DecodeBytesInto(([]byte)(x.Data)) + yyj10++ + for ; z.DecContainerNext(yyj10, l, yyhl10); yyj10++ { z.DecReadArrayElem() z.DecStructFieldNotFound(yyj10-1, "") } }   func (x *Log) IsCodecEmpty() bool { - return !(len(x.Address) != 0 && len(x.Topics) != 0 && len(x.Data) != 0 && true) + return !(x.Address != pkg1_common.Address{} || len(x.Topics) != 0 || len(x.Data) != 0 || false) }   +func (Logs) codecSelferViaCodecgen() {} func (x Logs) CodecEncodeSelf(e *codec1978.Encoder) { var h codecSelfer2 - z, r := codec1978.GenHelperEncoder(e) + z, r := codec1978.GenHelper().Encoder(e) _, _, _ = h, z, r if x == nil { r.EncodeNil() @@ -417,26 +657,26 @@ }   func (x *Logs) CodecDecodeSelf(d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r h.decLogs((*Logs)(x), d) }   func (x codecSelfer2) encReceipts(v Receipts, e *codec1978.Encoder) { var h codecSelfer2 - z, r := codec1978.GenHelperEncoder(e) + z, r := codec1978.GenHelper().Encoder(e) _, _, _ = h, z, r if v == nil { r.EncodeNil() return } z.EncWriteArrayStart(len(v)) - for _, yyv1 := range v { + for yyv1 := range v { z.EncWriteArrayElem() - if yyv1 == nil { + if v[yyv1] == nil { r.EncodeNil() } else { - yyv1.CodecEncodeSelf(e) + v[yyv1].CodecEncodeSelf(e) } } z.EncWriteArrayEnd() @@ -444,7 +684,7 @@ }   func (x codecSelfer2) decReceipts(v *Receipts, d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r   yyv1 := *v @@ -483,7 +723,7 @@ yyc1 = true } } var yyj1 int - for yyj1 = 0; (yyhl1 && yyj1 < yyl1) || !(yyhl1 || z.DecCheckBreak()); yyj1++ { // bounds-check-elimination + for yyj1 = 0; z.DecContainerNext(yyj1, yyl1, yyhl1); yyj1++ { if yyj1 == 0 && yyv1 == nil { if yyhl1 { yyrl1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 8) @@ -516,7 +756,7 @@ if yyj1 < len(yyv1) { yyv1 = yyv1[:yyj1] yyc1 = true } else if yyj1 == 0 && yyv1 == nil { - yyv1 = make([]*Receipt, 0) + yyv1 = []*Receipt{} yyc1 = true } } @@ -526,48 +766,30 @@ *v = yyv1 } }   -func (x codecSelfer2) enccommon_Address(v *libcommon.Address, e *codec1978.Encoder) { +func (x codecSelfer2) encSlicecommon_Hash(v []pkg1_common.Hash, e *codec1978.Encoder) { var h codecSelfer2 - z, r := codec1978.GenHelperEncoder(e) - _, _, _ = h, z, r - if v == nil { - r.EncodeNil() - return - } - r.EncodeStringBytesRaw(((*[20]byte)(v))[:]) -} - -func (x codecSelfer2) deccommon_Address(v *libcommon.Address, d *codec1978.Decoder) { - var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) - _, _, _ = h, z, r - r.DecodeBytes(((*[20]byte)(v))[:], true) -} - -func (x codecSelfer2) encSlicecommon_Hash(v []libcommon.Hash, e *codec1978.Encoder) { - var h codecSelfer2 - z, r := codec1978.GenHelperEncoder(e) + z, r := codec1978.GenHelper().Encoder(e) _, _, _ = h, z, r if v == nil { r.EncodeNil() return } z.EncWriteArrayStart(len(v)) - for _, yyv1 := range v { + for yyv1 := range v { z.EncWriteArrayElem() - yy2 := &yyv1 + yy2 := &v[yyv1] if !z.EncBinary() { z.EncTextMarshal(*yy2) } else { - h.enccommon_Hash((*libcommon.Hash)(yy2), e) + z.F.EncSliceUint8V(([]uint8)(yy2[:]), e) } } z.EncWriteArrayEnd() }   -func (x codecSelfer2) decSlicecommon_Hash(v *[]libcommon.Hash, d *codec1978.Decoder) { +func (x codecSelfer2) decSlicecommon_Hash(v *[]pkg1_common.Hash, d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r   yyv1 := *v @@ -581,7 +803,7 @@ yyc1 = true } } else if yyl1 == 0 { if yyv1 == nil { - yyv1 = []libcommon.Hash{} + yyv1 = []pkg1_common.Hash{} yyc1 = true } else if len(yyv1) != 0 { yyv1 = yyv1[:0] @@ -597,7 +819,7 @@ yyrl1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 32) if yyrl1 <= cap(yyv1) { yyv1 = yyv1[:yyrl1] } else { - yyv1 = make([]libcommon.Hash, yyrl1) + yyv1 = make([]pkg1_common.Hash, yyrl1) } yyc1 = true } else if yyl1 != len(yyv1) { @@ -606,20 +828,20 @@ yyc1 = true } } var yyj1 int - for yyj1 = 0; (yyhl1 && yyj1 < yyl1) || !(yyhl1 || z.DecCheckBreak()); yyj1++ { // bounds-check-elimination + for yyj1 = 0; z.DecContainerNext(yyj1, yyl1, yyhl1); yyj1++ { if yyj1 == 0 && yyv1 == nil { if yyhl1 { yyrl1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 32) } else { yyrl1 = 8 } - yyv1 = make([]libcommon.Hash, yyrl1) + yyv1 = make([]pkg1_common.Hash, yyrl1) yyc1 = true } yyh1.ElemContainerState(yyj1) var yydb1 bool if yyj1 >= len(yyv1) { - yyv1 = append(yyv1, libcommon.Hash{}) + yyv1 = append(yyv1, pkg1_common.Hash{}) yyc1 = true } if yydb1 { @@ -628,7 +850,7 @@ } else { if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(&yyv1[yyj1]) } else { - h.deccommon_Hash((*libcommon.Hash)(&yyv1[yyj1]), d) + z.F.DecSliceUint8N(([]uint8)(yyv1[yyj1][:]), d) } } } @@ -636,7 +858,7 @@ if yyj1 < len(yyv1) { yyv1 = yyv1[:yyj1] yyc1 = true } else if yyj1 == 0 && yyv1 == nil { - yyv1 = make([]libcommon.Hash, 0) + yyv1 = []pkg1_common.Hash{} yyc1 = true } } @@ -646,39 +868,21 @@ *v = yyv1 } }   -func (x codecSelfer2) enccommon_Hash(v *libcommon.Hash, e *codec1978.Encoder) { - var h codecSelfer2 - z, r := codec1978.GenHelperEncoder(e) - _, _, _ = h, z, r - if v == nil { - r.EncodeNil() - return - } - r.EncodeStringBytesRaw(((*[32]byte)(v))[:]) -} - -func (x codecSelfer2) deccommon_Hash(v *libcommon.Hash, d *codec1978.Decoder) { - var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) - _, _, _ = h, z, r - r.DecodeBytes(((*[32]byte)(v))[:], true) -} - func (x codecSelfer2) encLogs(v Logs, e *codec1978.Encoder) { var h codecSelfer2 - z, r := codec1978.GenHelperEncoder(e) + z, r := codec1978.GenHelper().Encoder(e) _, _, _ = h, z, r if v == nil { r.EncodeNil() return } z.EncWriteArrayStart(len(v)) - for _, yyv1 := range v { + for yyv1 := range v { z.EncWriteArrayElem() - if yyv1 == nil { + if v[yyv1] == nil { r.EncodeNil() } else { - yyv1.CodecEncodeSelf(e) + v[yyv1].CodecEncodeSelf(e) } } z.EncWriteArrayEnd() @@ -686,7 +890,7 @@ }   func (x codecSelfer2) decLogs(v *Logs, d *codec1978.Decoder) { var h codecSelfer2 - z, r := codec1978.GenHelperDecoder(d) + z, r := codec1978.GenHelper().Decoder(d) _, _, _ = h, z, r   yyv1 := *v @@ -725,7 +929,7 @@ yyc1 = true } } var yyj1 int - for yyj1 = 0; (yyhl1 && yyj1 < yyl1) || !(yyhl1 || z.DecCheckBreak()); yyj1++ { // bounds-check-elimination + for yyj1 = 0; z.DecContainerNext(yyj1, yyl1, yyhl1); yyj1++ { if yyj1 == 0 && yyv1 == nil { if yyhl1 { yyrl1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 8) @@ -758,7 +962,7 @@ if yyj1 < len(yyv1) { yyv1 = yyv1[:yyj1] yyc1 = true } else if yyj1 == 0 && yyv1 == nil { - yyv1 = make([]*Log, 0) + yyv1 = []*Log{} yyc1 = true } }
diff --git ledgerwatch/erigon/core/types/gen_receipt_json.go bobanetwork/v3-erigon/core/types/gen_receipt_json.go index 34b64b591b7c0c9824bf0bfba452471d25e02d9e..cfbbb968e3b0b8c0ccdbc7ec786dc6c253d5d734 100644 --- ledgerwatch/erigon/core/types/gen_receipt_json.go +++ bobanetwork/v3-erigon/core/types/gen_receipt_json.go @@ -5,10 +5,10 @@ import ( "encoding/json" "errors" - "github.com/ledgerwatch/erigon-lib/common/hexutil" "math/big"   - libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutil" "github.com/ledgerwatch/erigon-lib/common/hexutility" )   @@ -17,18 +17,24 @@ // MarshalJSON marshals as JSON. func (r Receipt) MarshalJSON() ([]byte, error) { type Receipt struct { - Type hexutil.Uint64 `json:"type,omitempty"` - PostState hexutility.Bytes `json:"root"` - Status hexutil.Uint64 `json:"status"` - CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"` - Bloom Bloom `json:"logsBloom" gencodec:"required"` - Logs []*Log `json:"logs" gencodec:"required"` - TxHash libcommon.Hash `json:"transactionHash" gencodec:"required"` - ContractAddress libcommon.Address `json:"contractAddress"` - GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - BlockHash libcommon.Hash `json:"blockHash,omitempty"` - BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` - TransactionIndex hexutil.Uint `json:"transactionIndex"` + Type hexutil.Uint64 `json:"type,omitempty"` + PostState hexutility.Bytes `json:"root" codec:"1"` + Status hexutil.Uint64 `json:"status" codec:"2"` + CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required" codec:"3"` + Bloom Bloom `json:"logsBloom" gencodec:"required" codec:"-"` + Logs Logs `json:"logs" gencodec:"required" codec:"-"` + TxHash common.Hash `json:"transactionHash" gencodec:"required" codec:"-"` + ContractAddress common.Address `json:"contractAddress" codec:"-"` + GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required" codec:"-"` + DepositNonce *hexutil.Uint64 `json:"depositNonce,omitempty"` + BlockHash common.Hash `json:"blockHash,omitempty" codec:"-"` + BlockNumber *hexutil.Big `json:"blockNumber,omitempty" codec:"-"` + TransactionIndex hexutil.Uint `json:"transactionIndex" codec:"-"` + L1GasPrice *hexutil.Big `json:"l1GasPrice,omitempty"` + L1GasUsed *hexutil.Big `json:"l1GasUsed,omitempty"` + L1Fee *hexutil.Big `json:"l1Fee,omitempty"` + FeeScalar *big.Float `json:"l1FeeScalar,omitempty"` + DepositReceiptVersion *hexutil.Uint64 `json:"depositReceiptVersion,omitempty"` } var enc Receipt enc.Type = hexutil.Uint64(r.Type) @@ -40,27 +46,39 @@ enc.Logs = r.Logs enc.TxHash = r.TxHash enc.ContractAddress = r.ContractAddress enc.GasUsed = hexutil.Uint64(r.GasUsed) + enc.DepositNonce = (*hexutil.Uint64)(r.DepositNonce) enc.BlockHash = r.BlockHash enc.BlockNumber = (*hexutil.Big)(r.BlockNumber) enc.TransactionIndex = hexutil.Uint(r.TransactionIndex) + enc.L1GasPrice = (*hexutil.Big)(r.L1GasPrice) + enc.L1GasUsed = (*hexutil.Big)(r.L1GasUsed) + enc.L1Fee = (*hexutil.Big)(r.L1Fee) + enc.FeeScalar = r.FeeScalar + enc.DepositReceiptVersion = (*hexutil.Uint64)(r.DepositReceiptVersion) return json.Marshal(&enc) }   // UnmarshalJSON unmarshals from JSON. func (r *Receipt) UnmarshalJSON(input []byte) error { type Receipt struct { - Type *hexutil.Uint64 `json:"type,omitempty"` - PostState *hexutility.Bytes `json:"root"` - Status *hexutil.Uint64 `json:"status"` - CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"` - Bloom *Bloom `json:"logsBloom" gencodec:"required"` - Logs []*Log `json:"logs" gencodec:"required"` - TxHash *libcommon.Hash `json:"transactionHash" gencodec:"required"` - ContractAddress *libcommon.Address `json:"contractAddress"` - GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - BlockHash *libcommon.Hash `json:"blockHash,omitempty"` - BlockNumber *hexutil.Big `json:"blockNumber,omitempty"` - TransactionIndex *hexutil.Uint `json:"transactionIndex"` + Type *hexutil.Uint64 `json:"type,omitempty"` + PostState *hexutility.Bytes `json:"root" codec:"1"` + Status *hexutil.Uint64 `json:"status" codec:"2"` + CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required" codec:"3"` + Bloom *Bloom `json:"logsBloom" gencodec:"required" codec:"-"` + Logs *Logs `json:"logs" gencodec:"required" codec:"-"` + TxHash *common.Hash `json:"transactionHash" gencodec:"required" codec:"-"` + ContractAddress *common.Address `json:"contractAddress" codec:"-"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required" codec:"-"` + DepositNonce *hexutil.Uint64 `json:"depositNonce,omitempty"` + BlockHash *common.Hash `json:"blockHash,omitempty" codec:"-"` + BlockNumber *hexutil.Big `json:"blockNumber,omitempty" codec:"-"` + TransactionIndex *hexutil.Uint `json:"transactionIndex" codec:"-"` + L1GasPrice *hexutil.Big `json:"l1GasPrice,omitempty"` + L1GasUsed *hexutil.Big `json:"l1GasUsed,omitempty"` + L1Fee *hexutil.Big `json:"l1Fee,omitempty"` + FeeScalar *big.Float `json:"l1FeeScalar,omitempty"` + DepositReceiptVersion *hexutil.Uint64 `json:"depositReceiptVersion,omitempty"` } var dec Receipt if err := json.Unmarshal(input, &dec); err != nil { @@ -86,7 +104,7 @@ r.Bloom = *dec.Bloom if dec.Logs == nil { return errors.New("missing required field 'logs' for Receipt") } - r.Logs = dec.Logs + r.Logs = *dec.Logs if dec.TxHash == nil { return errors.New("missing required field 'transactionHash' for Receipt") } @@ -98,6 +116,9 @@ if dec.GasUsed == nil { return errors.New("missing required field 'gasUsed' for Receipt") } r.GasUsed = uint64(*dec.GasUsed) + if dec.DepositNonce != nil { + r.DepositNonce = (*uint64)(dec.DepositNonce) + } if dec.BlockHash != nil { r.BlockHash = *dec.BlockHash } @@ -106,6 +127,21 @@ r.BlockNumber = (*big.Int)(dec.BlockNumber) } if dec.TransactionIndex != nil { r.TransactionIndex = uint(*dec.TransactionIndex) + } + if dec.L1GasPrice != nil { + r.L1GasPrice = (*big.Int)(dec.L1GasPrice) + } + if dec.L1GasUsed != nil { + r.L1GasUsed = (*big.Int)(dec.L1GasUsed) + } + if dec.L1Fee != nil { + r.L1Fee = (*big.Int)(dec.L1Fee) + } + if dec.FeeScalar != nil { + r.FeeScalar = dec.FeeScalar + } + if dec.DepositReceiptVersion != nil { + r.DepositReceiptVersion = (*uint64)(dec.DepositReceiptVersion) } return nil }
diff --git ledgerwatch/erigon/erigon-lib/gointerfaces/execution/execution.pb.go bobanetwork/v3-erigon/erigon-lib/gointerfaces/execution/execution.pb.go index c331568493bd18402e7a33f003e7d811d7b60d76..c6ff79329fed3404caa9ce3e3e12d7c2b2dd4785 100644 --- ledgerwatch/erigon/erigon-lib/gointerfaces/execution/execution.pb.go +++ bobanetwork/v3-erigon/erigon-lib/gointerfaces/execution/execution.pb.go @@ -1074,6 +1074,10 @@ PrevRandao *types.H256 `protobuf:"bytes,3,opt,name=prev_randao,json=prevRandao,proto3" json:"prev_randao,omitempty"` SuggestedFeeRecipient *types.H160 `protobuf:"bytes,4,opt,name=suggested_fee_recipient,json=suggestedFeeRecipient,proto3" json:"suggested_fee_recipient,omitempty"` Withdrawals []*types.Withdrawal `protobuf:"bytes,5,rep,name=withdrawals,proto3" json:"withdrawals,omitempty"` // added in Shapella (EIP-4895) ParentBeaconBlockRoot *types.H256 `protobuf:"bytes,6,opt,name=parent_beacon_block_root,json=parentBeaconBlockRoot,proto3,oneof" json:"parent_beacon_block_root,omitempty"` // added in Dencun (EIP-4788) + // Optimism support requires these fields, offset starting at 101 to avoid future conflicts + Transactions [][]byte `protobuf:"bytes,101,rep,name=transactions,proto3" json:"transactions,omitempty"` + NoTxPool bool `protobuf:"varint,102,opt,name=noTxPool,proto3" json:"noTxPool,omitempty"` + GasLimit *uint64 `protobuf:"varint,103,opt,name=gasLimit,proto3,oneof" json:"gasLimit,omitempty"` }   func (x *AssembleBlockRequest) Reset() { @@ -1150,6 +1154,27 @@ } return nil }   +func (x *AssembleBlockRequest) GetTransactions() [][]byte { + if x != nil { + return x.Transactions + } + return nil +} + +func (x *AssembleBlockRequest) GetNoTxPool() bool { + if x != nil { + return x.NoTxPool + } + return false +} + +func (x *AssembleBlockRequest) GetGasLimit() uint64 { + if x != nil && x.GasLimit != nil { + return *x.GasLimit + } + return 0 +} + type AssembleBlockResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1257,9 +1282,10 @@ state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields   - ExecutionPayload *types.ExecutionPayload `protobuf:"bytes,1,opt,name=execution_payload,json=executionPayload,proto3" json:"execution_payload,omitempty"` - BlockValue *types.H256 `protobuf:"bytes,2,opt,name=block_value,json=blockValue,proto3" json:"block_value,omitempty"` - BlobsBundle *types.BlobsBundleV1 `protobuf:"bytes,3,opt,name=blobs_bundle,json=blobsBundle,proto3" json:"blobs_bundle,omitempty"` + ExecutionPayload *types.ExecutionPayload `protobuf:"bytes,1,opt,name=execution_payload,json=executionPayload,proto3" json:"execution_payload,omitempty"` + BlockValue *types.H256 `protobuf:"bytes,2,opt,name=block_value,json=blockValue,proto3" json:"block_value,omitempty"` + BlobsBundle *types.BlobsBundleV1 `protobuf:"bytes,3,opt,name=blobs_bundle,json=blobsBundle,proto3" json:"blobs_bundle,omitempty"` + ParentBeaconBlockRoot *types.H256 `protobuf:"bytes,4,opt,name=parent_beacon_block_root,json=parentBeaconBlockRoot,proto3,oneof" json:"parent_beacon_block_root,omitempty"` }   func (x *AssembledBlockData) Reset() { @@ -1311,6 +1337,13 @@ func (x *AssembledBlockData) GetBlobsBundle() *types.BlobsBundleV1 { if x != nil { return x.BlobsBundle + } + return nil +} + +func (x *AssembledBlockData) GetParentBeaconBlockRoot() *types.H256 { + if x != nil { + return x.ParentBeaconBlockRoot } return nil } @@ -1790,7 +1823,7 @@ 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, 0x35, 0x36, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xf2, 0x02, 0x0a, 0x14, 0x41, 0x73, 0x73, 0x65, + 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xe0, 0x03, 0x0a, 0x14, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, @@ -1811,140 +1844,153 @@ 0x77, 0x61, 0x6c, 0x73, 0x12, 0x49, 0x0a, 0x18, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, 0x35, 0x36, 0x48, 0x00, 0x52, 0x15, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x65, 0x61, - 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74, 0x88, 0x01, 0x01, 0x42, - 0x1b, 0x0a, 0x19, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x65, 0x61, 0x63, 0x6f, - 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x22, 0x3b, 0x0a, 0x15, - 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x75, 0x73, 0x79, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x04, 0x62, 0x75, 0x73, 0x79, 0x22, 0x2a, 0x0a, 0x18, 0x47, 0x65, 0x74, - 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0xc1, 0x01, 0x0a, 0x12, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, - 0x6c, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61, 0x12, 0x44, 0x0a, 0x11, - 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x52, 0x10, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x12, 0x2c, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x48, 0x32, 0x35, 0x36, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x37, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x5f, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x42, - 0x6c, 0x6f, 0x62, 0x73, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x56, 0x31, 0x52, 0x0b, 0x62, 0x6c, - 0x6f, 0x62, 0x73, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x70, 0x0a, 0x19, 0x47, 0x65, 0x74, - 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, - 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x88, 0x01, 0x01, 0x12, 0x12, - 0x0a, 0x04, 0x62, 0x75, 0x73, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x62, 0x75, - 0x73, 0x79, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x22, 0x46, 0x0a, 0x16, 0x47, - 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x62, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x06, 0x62, 0x6f, 0x64, - 0x69, 0x65, 0x73, 0x22, 0x3f, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, - 0x42, 0x79, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x23, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, 0x35, 0x36, 0x52, 0x06, 0x68, 0x61, - 0x73, 0x68, 0x65, 0x73, 0x22, 0x45, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, - 0x73, 0x42, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x25, 0x0a, 0x0d, 0x52, - 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x72, 0x65, 0x61, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x72, 0x65, 0x61, - 0x64, 0x79, 0x22, 0x3b, 0x0a, 0x14, 0x46, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, - 0x6f, 0x7a, 0x65, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0c, 0x66, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x2a, - 0x71, 0x0a, 0x0f, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x10, 0x00, 0x12, - 0x0c, 0x0a, 0x08, 0x42, 0x61, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x10, 0x01, 0x12, 0x0e, 0x0a, - 0x0a, 0x54, 0x6f, 0x6f, 0x46, 0x61, 0x72, 0x41, 0x77, 0x61, 0x79, 0x10, 0x02, 0x12, 0x12, 0x0a, - 0x0e, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x10, - 0x03, 0x12, 0x15, 0x0a, 0x11, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x46, 0x6f, 0x72, 0x6b, - 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x75, 0x73, 0x79, - 0x10, 0x05, 0x32, 0xbf, 0x09, 0x0a, 0x09, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x4a, 0x0a, 0x0c, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, - 0x12, 0x1e, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x6e, 0x73, - 0x65, 0x72, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1a, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x6e, 0x73, - 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x4b, 0x0a, 0x0d, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x1c, 0x2e, - 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x47, 0x0a, 0x10, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x6b, 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x15, 0x2e, - 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x6f, 0x72, 0x6b, 0x43, 0x68, - 0x6f, 0x69, 0x63, 0x65, 0x1a, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x46, 0x6f, 0x72, 0x6b, 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, - 0x70, 0x74, 0x12, 0x52, 0x0a, 0x0d, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x12, 0x1f, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x73, 0x73, - 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x23, 0x2e, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x6d, - 0x62, 0x6c, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x24, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, - 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0d, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74, 0x88, 0x01, 0x01, 0x12, + 0x22, 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x65, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x6f, 0x54, 0x78, 0x50, 0x6f, 0x6f, 0x6c, 0x18, + 0x66, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x54, 0x78, 0x50, 0x6f, 0x6f, 0x6c, 0x12, + 0x1f, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x67, 0x20, 0x01, 0x28, + 0x04, 0x48, 0x01, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x88, 0x01, 0x01, + 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x65, 0x61, 0x63, + 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x42, 0x0b, 0x0a, + 0x09, 0x5f, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x3b, 0x0a, 0x15, 0x41, 0x73, + 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x75, 0x73, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x04, 0x62, 0x75, 0x73, 0x79, 0x22, 0x2a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x41, 0x73, + 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x02, 0x69, 0x64, 0x22, 0xa9, 0x02, 0x0a, 0x12, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, + 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61, 0x12, 0x44, 0x0a, 0x11, 0x65, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x45, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x10, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x12, 0x2c, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, + 0x35, 0x36, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x37, + 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x5f, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x42, 0x6c, 0x6f, + 0x62, 0x73, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x56, 0x31, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x62, + 0x73, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x49, 0x0a, 0x18, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x5f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, + 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x48, 0x32, 0x35, 0x36, 0x48, 0x00, 0x52, 0x15, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74, 0x88, + 0x01, 0x01, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x65, + 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x22, + 0x70, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x88, 0x01, 0x01, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x75, 0x73, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x04, 0x62, 0x75, 0x73, 0x79, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x64, 0x61, 0x74, + 0x61, 0x22, 0x46, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x62, + 0x6f, 0x64, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x42, 0x6f, 0x64, + 0x79, 0x52, 0x06, 0x62, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x22, 0x3f, 0x0a, 0x18, 0x47, 0x65, 0x74, + 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x79, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, + 0x35, 0x36, 0x52, 0x06, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x22, 0x45, 0x0a, 0x17, 0x47, 0x65, + 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x22, 0x25, 0x0a, 0x0d, 0x52, 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x61, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x05, 0x72, 0x65, 0x61, 0x64, 0x79, 0x22, 0x3b, 0x0a, 0x14, 0x46, 0x72, 0x6f, 0x7a, + 0x65, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x66, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x2a, 0x71, 0x0a, 0x0f, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x42, 0x61, 0x64, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x6f, 0x6f, 0x46, 0x61, 0x72, 0x41, 0x77, 0x61, + 0x79, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x53, 0x65, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x49, 0x6e, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x46, 0x6f, 0x72, 0x6b, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x10, 0x04, 0x12, 0x08, + 0x0a, 0x04, 0x42, 0x75, 0x73, 0x79, 0x10, 0x05, 0x32, 0xbf, 0x09, 0x0a, 0x09, 0x45, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4a, 0x0a, 0x0c, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x1e, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x12, 0x4b, 0x0a, 0x0d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x12, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, + 0x47, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x6b, 0x43, 0x68, 0x6f, + 0x69, 0x63, 0x65, 0x12, 0x15, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x46, 0x6f, 0x72, 0x6b, 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x1a, 0x1c, 0x2e, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x6f, 0x72, 0x6b, 0x43, 0x68, 0x6f, 0x69, 0x63, + 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x52, 0x0a, 0x0d, 0x41, 0x73, 0x73, 0x65, + 0x6d, 0x62, 0x6c, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x1f, 0x2e, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x11, + 0x47, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x12, 0x23, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, + 0x74, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0d, + 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x05, 0x47, 0x65, 0x74, 0x54, 0x44, 0x12, 0x1c, 0x2e, 0x65, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x44, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x12, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, + 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x48, - 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, - 0x05, 0x47, 0x65, 0x74, 0x54, 0x44, 0x12, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x47, 0x65, 0x74, 0x54, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, - 0x0a, 0x09, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, - 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x6f, - 0x64, 0x79, 0x12, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, - 0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1a, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, - 0x42, 0x6f, 0x64, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x10, - 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, - 0x12, 0x22, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, - 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x42, 0x6f, - 0x64, 0x69, 0x65, 0x73, 0x42, 0x79, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x23, 0x2e, 0x65, - 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, - 0x65, 0x73, 0x42, 0x79, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x21, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, - 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0f, 0x49, 0x73, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, - 0x63, 0x61, 0x6c, 0x48, 0x61, 0x73, 0x68, 0x12, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x48, 0x32, 0x35, 0x36, 0x1a, 0x1e, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x49, 0x73, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x48, 0x61, 0x73, 0x68, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x0b, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, 0x35, 0x36, 0x1a, 0x26, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, - 0x73, 0x68, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x3e, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x6b, 0x43, 0x68, 0x6f, 0x69, 0x63, - 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x65, 0x78, 0x65, 0x63, - 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x6f, 0x72, 0x6b, 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65, - 0x12, 0x39, 0x0a, 0x05, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x1a, 0x18, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, - 0x61, 0x64, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x46, - 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x1f, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x46, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x17, 0x5a, 0x15, 0x2e, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x3b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, + 0x07, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x1c, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x59, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, + 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x22, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x79, 0x52, 0x61, + 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, + 0x11, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x79, 0x48, 0x61, 0x73, 0x68, + 0x65, 0x73, 0x12, 0x23, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, + 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x79, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0f, 0x49, 0x73, + 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x48, 0x61, 0x73, 0x68, 0x12, 0x0b, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, 0x35, 0x36, 0x1a, 0x1e, 0x2e, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x49, 0x73, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, + 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x13, 0x47, 0x65, + 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x0b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x32, 0x35, 0x36, 0x1a, 0x26, + 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, + 0x6b, 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x15, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x6f, 0x72, 0x6b, + 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x05, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x47, 0x0a, 0x0c, 0x46, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1f, 0x2e, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x72, 0x6f, 0x7a, 0x65, 0x6e, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x17, 0x5a, 0x15, 0x2e, 0x2f, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }   var ( @@ -2037,46 +2083,47 @@ 26, // 36: execution.AssembleBlockRequest.parent_beacon_block_root:type_name -> types.H256 30, // 37: execution.AssembledBlockData.execution_payload:type_name -> types.ExecutionPayload 26, // 38: execution.AssembledBlockData.block_value:type_name -> types.H256 31, // 39: execution.AssembledBlockData.blobs_bundle:type_name -> types.BlobsBundleV1 - 19, // 40: execution.GetAssembledBlockResponse.data:type_name -> execution.AssembledBlockData - 5, // 41: execution.GetBodiesBatchResponse.bodies:type_name -> execution.BlockBody - 26, // 42: execution.GetBodiesByHashesRequest.hashes:type_name -> types.H256 - 12, // 43: execution.Execution.InsertBlocks:input_type -> execution.InsertBlocksRequest - 15, // 44: execution.Execution.ValidateChain:input_type -> execution.ValidationRequest - 13, // 45: execution.Execution.UpdateForkChoice:input_type -> execution.ForkChoice - 16, // 46: execution.Execution.AssembleBlock:input_type -> execution.AssembleBlockRequest - 18, // 47: execution.Execution.GetAssembledBlock:input_type -> execution.GetAssembledBlockRequest - 32, // 48: execution.Execution.CurrentHeader:input_type -> google.protobuf.Empty - 11, // 49: execution.Execution.GetTD:input_type -> execution.GetSegmentRequest - 11, // 50: execution.Execution.GetHeader:input_type -> execution.GetSegmentRequest - 11, // 51: execution.Execution.GetBody:input_type -> execution.GetSegmentRequest - 23, // 52: execution.Execution.GetBodiesByRange:input_type -> execution.GetBodiesByRangeRequest - 22, // 53: execution.Execution.GetBodiesByHashes:input_type -> execution.GetBodiesByHashesRequest - 26, // 54: execution.Execution.IsCanonicalHash:input_type -> types.H256 - 26, // 55: execution.Execution.GetHeaderHashNumber:input_type -> types.H256 - 32, // 56: execution.Execution.GetForkChoice:input_type -> google.protobuf.Empty - 32, // 57: execution.Execution.Ready:input_type -> google.protobuf.Empty - 32, // 58: execution.Execution.FrozenBlocks:input_type -> google.protobuf.Empty - 14, // 59: execution.Execution.InsertBlocks:output_type -> execution.InsertionResult - 2, // 60: execution.Execution.ValidateChain:output_type -> execution.ValidationReceipt - 1, // 61: execution.Execution.UpdateForkChoice:output_type -> execution.ForkChoiceReceipt - 17, // 62: execution.Execution.AssembleBlock:output_type -> execution.AssembleBlockResponse - 20, // 63: execution.Execution.GetAssembledBlock:output_type -> execution.GetAssembledBlockResponse - 7, // 64: execution.Execution.CurrentHeader:output_type -> execution.GetHeaderResponse - 8, // 65: execution.Execution.GetTD:output_type -> execution.GetTDResponse - 7, // 66: execution.Execution.GetHeader:output_type -> execution.GetHeaderResponse - 9, // 67: execution.Execution.GetBody:output_type -> execution.GetBodyResponse - 21, // 68: execution.Execution.GetBodiesByRange:output_type -> execution.GetBodiesBatchResponse - 21, // 69: execution.Execution.GetBodiesByHashes:output_type -> execution.GetBodiesBatchResponse - 3, // 70: execution.Execution.IsCanonicalHash:output_type -> execution.IsCanonicalResponse - 10, // 71: execution.Execution.GetHeaderHashNumber:output_type -> execution.GetHeaderHashNumberResponse - 13, // 72: execution.Execution.GetForkChoice:output_type -> execution.ForkChoice - 24, // 73: execution.Execution.Ready:output_type -> execution.ReadyResponse - 25, // 74: execution.Execution.FrozenBlocks:output_type -> execution.FrozenBlocksResponse - 59, // [59:75] is the sub-list for method output_type - 43, // [43:59] is the sub-list for method input_type - 43, // [43:43] is the sub-list for extension type_name - 43, // [43:43] is the sub-list for extension extendee - 0, // [0:43] is the sub-list for field type_name + 26, // 40: execution.AssembledBlockData.parent_beacon_block_root:type_name -> types.H256 + 19, // 41: execution.GetAssembledBlockResponse.data:type_name -> execution.AssembledBlockData + 5, // 42: execution.GetBodiesBatchResponse.bodies:type_name -> execution.BlockBody + 26, // 43: execution.GetBodiesByHashesRequest.hashes:type_name -> types.H256 + 12, // 44: execution.Execution.InsertBlocks:input_type -> execution.InsertBlocksRequest + 15, // 45: execution.Execution.ValidateChain:input_type -> execution.ValidationRequest + 13, // 46: execution.Execution.UpdateForkChoice:input_type -> execution.ForkChoice + 16, // 47: execution.Execution.AssembleBlock:input_type -> execution.AssembleBlockRequest + 18, // 48: execution.Execution.GetAssembledBlock:input_type -> execution.GetAssembledBlockRequest + 32, // 49: execution.Execution.CurrentHeader:input_type -> google.protobuf.Empty + 11, // 50: execution.Execution.GetTD:input_type -> execution.GetSegmentRequest + 11, // 51: execution.Execution.GetHeader:input_type -> execution.GetSegmentRequest + 11, // 52: execution.Execution.GetBody:input_type -> execution.GetSegmentRequest + 23, // 53: execution.Execution.GetBodiesByRange:input_type -> execution.GetBodiesByRangeRequest + 22, // 54: execution.Execution.GetBodiesByHashes:input_type -> execution.GetBodiesByHashesRequest + 26, // 55: execution.Execution.IsCanonicalHash:input_type -> types.H256 + 26, // 56: execution.Execution.GetHeaderHashNumber:input_type -> types.H256 + 32, // 57: execution.Execution.GetForkChoice:input_type -> google.protobuf.Empty + 32, // 58: execution.Execution.Ready:input_type -> google.protobuf.Empty + 32, // 59: execution.Execution.FrozenBlocks:input_type -> google.protobuf.Empty + 14, // 60: execution.Execution.InsertBlocks:output_type -> execution.InsertionResult + 2, // 61: execution.Execution.ValidateChain:output_type -> execution.ValidationReceipt + 1, // 62: execution.Execution.UpdateForkChoice:output_type -> execution.ForkChoiceReceipt + 17, // 63: execution.Execution.AssembleBlock:output_type -> execution.AssembleBlockResponse + 20, // 64: execution.Execution.GetAssembledBlock:output_type -> execution.GetAssembledBlockResponse + 7, // 65: execution.Execution.CurrentHeader:output_type -> execution.GetHeaderResponse + 8, // 66: execution.Execution.GetTD:output_type -> execution.GetTDResponse + 7, // 67: execution.Execution.GetHeader:output_type -> execution.GetHeaderResponse + 9, // 68: execution.Execution.GetBody:output_type -> execution.GetBodyResponse + 21, // 69: execution.Execution.GetBodiesByRange:output_type -> execution.GetBodiesBatchResponse + 21, // 70: execution.Execution.GetBodiesByHashes:output_type -> execution.GetBodiesBatchResponse + 3, // 71: execution.Execution.IsCanonicalHash:output_type -> execution.IsCanonicalResponse + 10, // 72: execution.Execution.GetHeaderHashNumber:output_type -> execution.GetHeaderHashNumberResponse + 13, // 73: execution.Execution.GetForkChoice:output_type -> execution.ForkChoice + 24, // 74: execution.Execution.Ready:output_type -> execution.ReadyResponse + 25, // 75: execution.Execution.FrozenBlocks:output_type -> execution.FrozenBlocksResponse + 60, // [60:76] is the sub-list for method output_type + 44, // [44:60] is the sub-list for method input_type + 44, // [44:44] is the sub-list for extension type_name + 44, // [44:44] is the sub-list for extension extendee + 0, // [0:44] is the sub-list for field type_name }   func init() { file_execution_execution_proto_init() } @@ -2394,6 +2441,7 @@ file_execution_execution_proto_msgTypes[9].OneofWrappers = []interface{}{} file_execution_execution_proto_msgTypes[10].OneofWrappers = []interface{}{} file_execution_execution_proto_msgTypes[12].OneofWrappers = []interface{}{} file_execution_execution_proto_msgTypes[15].OneofWrappers = []interface{}{} + file_execution_execution_proto_msgTypes[18].OneofWrappers = []interface{}{} file_execution_execution_proto_msgTypes[19].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{
diff --git ledgerwatch/erigon/.golangci.yml bobanetwork/v3-erigon/.golangci.yml index ea4a442c1de8736afcf5dcf37b07d7e8668fa546..a7ec604b67711e5e50e343c4c5001bd7b6586923 100644 --- ledgerwatch/erigon/.golangci.yml +++ bobanetwork/v3-erigon/.golangci.yml @@ -84,7 +84,7 @@ ruleguard: rules: "rules.go" hugeParam: # size in bytes that makes the warning trigger (default 80) - sizeThreshold: 1000 + sizeThreshold: 1100 rangeExprCopy: # size in bytes that makes the warning trigger (default 512) sizeThreshold: 512
diff --git ledgerwatch/erigon/UpstreamMerge.md bobanetwork/v3-erigon/UpstreamMerge.md new file mode 100644 index 0000000000000000000000000000000000000000..0efd5748c38406857564dd9da06190f20807cc66 --- /dev/null +++ bobanetwork/v3-erigon/UpstreamMerge.md @@ -0,0 +1,33 @@ +This document is an attempt to outline the procedure for merging in changes +from upstream. + +Merge conflicts in this repository tend to be substantive when they occur, so +this document is currently fairly limited. However, the intent is to have it +here as a place to document any repetitive merge techniques that may not be +initially obvious. + +### Typical merge conflicts + +### `go.mod`/`go.sum` + +Generally, the safest way to resolve this conflicts is to remove duplicate +dependencies between the two sections, leaving the one at the higher version. +Once done, simply run `go mod tidy`. Note, the tidy step will likely fail +until any `*.go` conflicts have been resolved. + +Note, we have replace directives in most go.mod files that must be kept up to +date as well. + +### `*.pb.go` + +If any of the generated protobuf files have conflicts at merge, then most +likely something has changed upstream in the `interfaces` repository. First, +merge this upstream repo to match the version referenced, and update the +`replace` directive in the `go.mod`. Finally regenerate the protos by running +`make` in the `erigon-lib` directory. + +### Flags + +We have additional flags for historical RPC endpoints. These are often the +subject of merge conflicts, and need only be preserved in addition to any +other flag modifications.
diff --git ledgerwatch/erigon/cl/fork/fork_test.go bobanetwork/v3-erigon/cl/fork/fork_test.go index 568be1e4dc59048a4faa5385f75f70d3d6a1e7ed..f20fc90c9ac6cc7f0d64f66b485b4e1a836f3673 100644 --- ledgerwatch/erigon/cl/fork/fork_test.go +++ bobanetwork/v3-erigon/cl/fork/fork_test.go @@ -66,7 +66,7 @@ digest, err := ComputeForkDigest(&beaconCfg, &genesisCfg) require.NoError(t, err) _, err = ComputeForkId(&beaconCfg, &genesisCfg) require.NoError(t, err) - require.Equal(t, [4]uint8{0x47, 0xeb, 0x72, 0xb3}, digest) + require.Equal(t, [4]uint8{0xd3, 0x1f, 0x61, 0x91}, digest) }   // ForkDigestVersion
diff --git ledgerwatch/erigon/cmd/devnet/services/polygon/proofgenerator_test.go bobanetwork/v3-erigon/cmd/devnet/services/polygon/proofgenerator_test.go index 79565cd9fb3b0506b1af2f35c6fa4fc65e7f524c..8c9bd9f985f295846dad6a64a5008bc2faad7fef 100644 --- ledgerwatch/erigon/cmd/devnet/services/polygon/proofgenerator_test.go +++ bobanetwork/v3-erigon/cmd/devnet/services/polygon/proofgenerator_test.go @@ -107,7 +107,7 @@ transactions := make([]*jsonrpc.RPCTransaction, len(block.Transactions()))   for i, tx := range block.Transactions() { rg.txBlockMap[tx.Hash()] = block - transactions[i] = jsonrpc.NewRPCTransaction(tx, block.Hash(), blockNum.Uint64(), uint64(i), block.BaseFee()) + transactions[i] = jsonrpc.NewRPCTransaction(tx, block.Hash(), blockNum.Uint64(), uint64(i), block.BaseFee(), nil) }   return &requests.Block{
diff --git ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest/test_util.go bobanetwork/v3-erigon/cmd/rpcdaemon/rpcdaemontest/test_util.go index ecff7012c16cae7f3865518cf22fdeebe85aabab..a3451d10735c2710ce7c9b410a33716172146e3d 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/rpcdaemontest/test_util.go +++ bobanetwork/v3-erigon/cmd/rpcdaemon/rpcdaemontest/test_util.go @@ -112,6 +112,53 @@ return m, chain, []*core.ChainPack{orphanedChain} }   +func CreateOptimismTestSentry(t *testing.T) (*mock.MockSentry, *core.ChainPack, []*core.ChainPack) { + addresses := makeTestAddresses() + var ( + key = addresses.key + address = addresses.address + address1 = addresses.address1 + address2 = addresses.address2 + ) + + var ( + gspec = &types.Genesis{ + Config: params.TestOptimismChainConfig, + Alloc: types.GenesisAlloc{ + address: {Balance: big.NewInt(9000000000000000000)}, + address1: {Balance: big.NewInt(200000000000000000)}, + address2: {Balance: big.NewInt(300000000000000000)}, + }, + GasLimit: 10000000, + } + ) + m := mock.MockWithGenesis(t, gspec, key, false) + + contractBackend := backends.NewTestSimulatedBackendWithConfig(t, gspec.Alloc, gspec.Config, gspec.GasLimit) + defer contractBackend.Close() + + // Generate empty chain to have some orphaned blocks for tests + orphanedChain, err := core.GenerateChain(m.ChainConfig, m.Genesis, m.Engine, m.DB, 5, func(i int, block *core.BlockGen) { + }) + if err != nil { + t.Fatal(err) + } + + chain, err := getChainInstance(&addresses, m.ChainConfig, m.Genesis, m.Engine, m.DB, contractBackend) + if err != nil { + t.Fatal(err) + } + + if err = m.InsertChain(orphanedChain); err != nil { + t.Fatal(err) + } + if err = m.InsertChain(chain); err != nil { + t.Fatal(err) + } + + return m, chain, []*core.ChainPack{orphanedChain} +} + var chainInstance *core.ChainPack   func getChainInstance(
diff --git ledgerwatch/erigon/cmd/state/commands/opcode_tracer.go bobanetwork/v3-erigon/cmd/state/commands/opcode_tracer.go index 72901c7b1fa90781916281a558945eb08d10942c..92c73d4ec4a8924dd394cb8524d4a407241213e2 100644 --- ledgerwatch/erigon/cmd/state/commands/opcode_tracer.go +++ bobanetwork/v3-erigon/cmd/state/commands/opcode_tracer.go @@ -25,6 +25,7 @@ "github.com/ledgerwatch/erigon/common/debug" "github.com/ledgerwatch/erigon/consensus" "github.com/ledgerwatch/erigon/consensus/ethash" + "github.com/ledgerwatch/erigon/consensus/misc" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/state" @@ -713,6 +714,10 @@ gp := new(core.GasPool).AddGas(block.GasLimit()).AddBlobGas(chainConfig.GetMaxBlobGasPerBlock()) usedGas := new(uint64) usedBlobGas := new(uint64) var receipts types.Receipts + + // Optimism Canyon + misc.EnsureCreate2Deployer(chainConfig, header.Time, ibs) + core.InitializeBlockExecution(engine, nil, header, chainConfig, ibs, logger) rules := chainConfig.Rules(block.NumberU64(), block.Time()) for i, tx := range block.Transactions() {
diff --git ledgerwatch/erigon/cmd/state/exec3/state.go bobanetwork/v3-erigon/cmd/state/exec3/state.go index b687065e9b548b5d1bb03110da72eb90e0b88060..93302df017f31ca849104adc0d336016280e3418 100644 --- ledgerwatch/erigon/cmd/state/exec3/state.go +++ bobanetwork/v3-erigon/cmd/state/exec3/state.go @@ -11,9 +11,11 @@ "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/opstack"   "github.com/ledgerwatch/erigon/cmd/state/exec22" "github.com/ledgerwatch/erigon/consensus" + "github.com/ledgerwatch/erigon/consensus/misc" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/state" @@ -136,9 +138,17 @@ rules := txTask.Rules var err error header := txTask.Header   + // Optimism Canyon + create2DeployerTx := misc.IsCanyonActivationBlock(rw.chainConfig, header.Time) && txTask.TxIndex == -1 + var logger = log.New("worker-tx")   switch { + case create2DeployerTx: + if create2DeployerTx && header != nil { + // Optimism Canyon + misc.EnsureCreate2Deployer(rw.chainConfig, header.Time, ibs) + } case txTask.TxIndex == -1: if txTask.BlockNum == 0 { // Genesis block @@ -195,6 +205,7 @@ blockContext := txTask.EvmBlockContext if !rw.background { getHashFn := core.GetHashFn(header, rw.getHeader) blockContext = core.NewEVMBlockContext(header, getHashFn, rw.engine, nil /* author */) + blockContext.L1CostFunc = opstack.NewL1CostFunc(rw.chainConfig, rw.ibs) } rw.evm.ResetBetweenBlocks(blockContext, core.NewEVMTxContext(msg), ibs, vmConfig, rules)
diff --git ledgerwatch/erigon/cmd/state/exec3/state_recon.go bobanetwork/v3-erigon/cmd/state/exec3/state_recon.go index 1700c3428167f7008e7bdfa24f0a7986d9bcb4fe..98740461d4853587d5f52a746a48c658a34a65e0 100644 --- ledgerwatch/erigon/cmd/state/exec3/state_recon.go +++ bobanetwork/v3-erigon/cmd/state/exec3/state_recon.go @@ -18,6 +18,7 @@ libstate "github.com/ledgerwatch/erigon-lib/state"   "github.com/ledgerwatch/erigon/cmd/state/exec22" "github.com/ledgerwatch/erigon/consensus" + "github.com/ledgerwatch/erigon/consensus/misc" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/state" "github.com/ledgerwatch/erigon/core/types" @@ -292,6 +293,9 @@ ibs := rw.ibs rules := txTask.Rules var err error   + // Optimism Canyon + create2DeployerTx := misc.IsCanyonActivationBlock(rw.chainConfig, txTask.Header.Time) && txTask.TxIndex == -1 + var logger = log.New("recon-tx")   if txTask.BlockNum == 0 && txTask.TxIndex == -1 { @@ -303,6 +307,11 @@ return err } // For Genesis, rules should be empty, so that empty accounts can be included rules = &chain.Rules{} + } else if create2DeployerTx { + if create2DeployerTx && txTask.Header != nil { + // Optimism Canyon + misc.EnsureCreate2Deployer(rw.chainConfig, txTask.Header.Time, ibs) + } } else if txTask.Final { if txTask.BlockNum > 0 { //fmt.Printf("txNum=%d, blockNum=%d, finalisation of the block\n", txTask.TxNum, txTask.BlockNum)
diff --git ledgerwatch/erigon/consensus/misc/create2deployer.go bobanetwork/v3-erigon/consensus/misc/create2deployer.go new file mode 100644 index 0000000000000000000000000000000000000000..a0b599f5a4bac8bf9a8e881c7b90dca7cf3fcf3f --- /dev/null +++ bobanetwork/v3-erigon/consensus/misc/create2deployer.go @@ -0,0 +1,37 @@ +package misc + +import ( + "encoding/hex" + + "github.com/ledgerwatch/erigon-lib/chain" + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon/core/state" + "github.com/ledgerwatch/log/v3" +) + +// The original create2deployer contract could not be deployed to Base mainnet at +// the canonical address of 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2 due to +// an accidental nonce increment from a deposit transaction. See +// https://github.com/pcaversaccio/create2deployer/issues/128 for context. This +// file applies the contract code to the canonical address manually in the Canyon +// hardfork. + +var create2DeployerAddress = libcommon.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2") +var create2DeployerCodeHash = libcommon.HexToHash("0xb0550b5b431e30d38000efb7107aaa0ade03d48a7198a140edda9d27134468b2") + +// TODO: bytecode will be fetched from superchain-registry +// remove TestCreateDeployerCodeHash test after integration is done +var create2DeployerCode, _ = hex.DecodeString("6080604052600436106100435760003560e01c8063076c37b21461004f578063481286e61461007157806356299481146100ba57806366cfa057146100da57600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5061006f61006a366004610327565b6100fa565b005b34801561007d57600080fd5b5061009161008c366004610327565b61014a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100c657600080fd5b506100916100d5366004610349565b61015d565b3480156100e657600080fd5b5061006f6100f53660046103ca565b610172565b61014582826040518060200161010f9061031a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604052610183565b505050565b600061015683836102e7565b9392505050565b600061016a8484846102f0565b949350505050565b61017d838383610183565b50505050565b6000834710156101f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b815160000361025f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016101eb565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610156576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f790000000000000060448201526064016101eb565b60006101568383305b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b61014e806104ad83390190565b6000806040838503121561033a57600080fd5b50508035926020909101359150565b60008060006060848603121561035e57600080fd5b8335925060208401359150604084013573ffffffffffffffffffffffffffffffffffffffff8116811461039057600080fd5b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156103df57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561040557600080fd5b818601915086601f83011261041957600080fd5b81358181111561042b5761042b61039b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104715761047161039b565b8160405282815289602084870101111561048a57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fe608060405234801561001057600080fd5b5061012e806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063249cb3fa14602d575b600080fd5b603c603836600460b1565b604e565b60405190815260200160405180910390f35b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16608857600060aa565b7fa2ef4600d742022d532d4747cb3547474667d6f13804902513b2ec01c848f4b45b9392505050565b6000806040838503121560c357600080fd5b82359150602083013573ffffffffffffffffffffffffffffffffffffffff8116811460ed57600080fd5b80915050925092905056fea26469706673582212205ffd4e6cede7d06a5daf93d48d0541fc68189eeb16608c1999a82063b666eb1164736f6c63430008130033a2646970667358221220fdc4a0fe96e3b21c108ca155438d37c9143fb01278a3c1d274948bad89c564ba64736f6c63430008130033") + +func IsCanyonActivationBlock(c *chain.Config, timestamp uint64) bool { + return c.IsOptimism() && c.CanyonTime != nil && (*c.CanyonTime).Uint64() == timestamp +} + +func EnsureCreate2Deployer(c *chain.Config, timestamp uint64, statedb *state.IntraBlockState) bool { + if !IsCanyonActivationBlock(c, timestamp) { + return false + } + log.Info("Setting Create2Deployer code", "address", create2DeployerAddress, "codeHash", create2DeployerCodeHash) + statedb.SetCode(create2DeployerAddress, create2DeployerCode) + return true +}
diff --git ledgerwatch/erigon/consensus/misc/create2deployer_test.go bobanetwork/v3-erigon/consensus/misc/create2deployer_test.go new file mode 100644 index 0000000000000000000000000000000000000000..98a60be5d3193b6c75716908ff950cb751c57bb5 --- /dev/null +++ bobanetwork/v3-erigon/consensus/misc/create2deployer_test.go @@ -0,0 +1,94 @@ +package misc + +import ( + "bytes" + "math/big" + "testing" + + "github.com/ledgerwatch/erigon-lib/chain" + "github.com/ledgerwatch/erigon-lib/kv/memdb" + "github.com/ledgerwatch/erigon/core/state" + "github.com/ledgerwatch/erigon/crypto" + "github.com/ledgerwatch/erigon/params" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCreateDeployerCodeHash(t *testing.T) { + // superchain-registry verified contract bytecode is correct. + // Before integraing superchain-registry, we manually verify here. + codeHash := crypto.Keccak256Hash(create2DeployerCode) + require.Equal(t, create2DeployerCodeHash, codeHash) +} + +func TestEnsureCreate2Deployer(t *testing.T) { + canyonTime := uint64(1000) + var tests = []struct { + name string + override func(cfg *chain.Config) + timestamp uint64 + applied bool + }{ + { + name: "at hardfork", + timestamp: canyonTime, + applied: true, + }, + { + name: "another chain ID", + override: func(cfg *chain.Config) { + cfg.ChainID = big.NewInt(params.OPMainnetChainID) + }, + timestamp: canyonTime, + applied: true, + }, + { + name: "pre canyon", + timestamp: canyonTime - 1, + applied: false, + }, + { + name: "post hardfork", + timestamp: canyonTime + 1, + applied: false, + }, + { + name: "canyon not configured", + override: func(cfg *chain.Config) { + cfg.CanyonTime = nil + }, + timestamp: canyonTime, + applied: false, + }, + { + name: "not optimism", + override: func(cfg *chain.Config) { + cfg.Optimism = nil + }, + timestamp: canyonTime, + applied: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := chain.Config{ + ChainID: big.NewInt(params.OPMainnetChainID), + Optimism: &chain.OptimismConfig{}, + CanyonTime: big.NewInt(int64(canyonTime)), + } + if tt.override != nil { + tt.override(&cfg) + } + + _, tx := memdb.NewTestTx(t) + state := state.New(state.NewPlainStateReader(tx)) + // make sure state is empty + assert.NotEqual(t, state.GetCode(create2DeployerAddress), create2DeployerCode) + + EnsureCreate2Deployer(&cfg, tt.timestamp, state) + + applied := bytes.Equal(state.GetCode(create2DeployerAddress), create2DeployerCode) + assert.Equal(t, tt.applied, applied) + }) + } +}
diff --git ledgerwatch/erigon/consensus/misc/eip1559_test.go bobanetwork/v3-erigon/consensus/misc/eip1559_test.go index c937880ffa06dde39a6dd0169539da77f1285b64..41e2b698a2381086c466b7b766e6eaaac5d779c0 100644 --- ledgerwatch/erigon/consensus/misc/eip1559_test.go +++ bobanetwork/v3-erigon/consensus/misc/eip1559_test.go @@ -40,6 +40,19 @@ config.LondonBlock = big.NewInt(5) return config }   +func opConfig() *chain.Config { + config := copyConfig(params.TestChainConfig) + config.BedrockBlock = big.NewInt(0) + config.LondonBlock = big.NewInt(5) + config.CanyonTime = big.NewInt(10) + config.Optimism = &chain.OptimismConfig{ + EIP1559Elasticity: 6, + EIP1559Denominator: 50, + EIP1559DenominatorCanyon: 250, + } + return config +} + // TestBlockGasLimits tests the gasLimit checks for blocks both across // the EIP-1559 boundary and post-1559 blocks func TestBlockGasLimits(t *testing.T) { @@ -109,7 +122,40 @@ GasLimit: test.parentGasLimit, GasUsed: test.parentGasUsed, BaseFee: big.NewInt(test.parentBaseFee), } - if have, want := CalcBaseFee(config(), parent), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 { + if have, want := CalcBaseFee(config(), parent, 0), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 { + t.Errorf("test %d: have %d want %d, ", i, have, want) + } + } +} + +// TestCalcBaseFeeOptimism assumes all blocks are 1559-blocks but tests the Canyon activation +func TestCalcBaseFeeOptimism(t *testing.T) { + tests := []struct { + parentBaseFee int64 + parentGasLimit uint64 + parentGasUsed uint64 + expectedBaseFee int64 + postCanyon bool + }{ + {params.InitialBaseFee, 30_000_000, 5_000_000, params.InitialBaseFee, false}, // usage == target + {params.InitialBaseFee, 30_000_000, 4_000_000, 996000000, false}, // usage below target + {params.InitialBaseFee, 30_000_000, 10_000_000, 1020000000, false}, // usage above target + {params.InitialBaseFee, 30_000_000, 5_000_000, params.InitialBaseFee, true}, // usage == target + {params.InitialBaseFee, 30_000_000, 4_000_000, 999200000, true}, // usage below target + {params.InitialBaseFee, 30_000_000, 10_000_000, 1004000000, true}, // usage above target + } + for i, test := range tests { + parent := &types.Header{ + Number: common.Big32, + GasLimit: test.parentGasLimit, + GasUsed: test.parentGasUsed, + BaseFee: big.NewInt(test.parentBaseFee), + Time: 6, + } + if test.postCanyon { + parent.Time = 8 + } + if have, want := CalcBaseFee(opConfig(), parent, parent.Time+2), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 { t.Errorf("test %d: have %d want %d, ", i, have, want) } }
diff --git ledgerwatch/erigon/consensus/misc/eip4788.go bobanetwork/v3-erigon/consensus/misc/eip4788.go index 26293004b28e54d0e83318d337de88645e919330..a53788ed9ac0bd1e0b11e4f2a5d5b8547568ab0b 100644 --- ledgerwatch/erigon/consensus/misc/eip4788.go +++ bobanetwork/v3-erigon/consensus/misc/eip4788.go @@ -9,6 +9,10 @@ "github.com/ledgerwatch/erigon/params" )   func ApplyBeaconRootEip4788(parentBeaconBlockRoot *libcommon.Hash, syscall consensus.SystemCall) { + if parentBeaconBlockRoot == nil { + log.Warn("Skipping EIP-4788 as there is no parentBeaconBlockRoot") + return + } _, err := syscall(params.BeaconRootsAddress, parentBeaconBlockRoot.Bytes()) if err != nil { log.Warn("Failed to call beacon roots contract", "err", err)
diff --git ledgerwatch/erigon/core/blockchain.go bobanetwork/v3-erigon/core/blockchain.go index d750e6bbc283130afd6818377ce6936e899befab..7b645b89b3d51f8ce1b49217fe529fb792d9c381 100644 --- ledgerwatch/erigon/core/blockchain.go +++ bobanetwork/v3-erigon/core/blockchain.go @@ -29,9 +29,11 @@ "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/cmp" "github.com/ledgerwatch/erigon-lib/metrics" + "github.com/ledgerwatch/erigon-lib/opstack" "github.com/ledgerwatch/erigon/common/math" "github.com/ledgerwatch/erigon/common/u256" "github.com/ledgerwatch/erigon/consensus" + "github.com/ledgerwatch/erigon/consensus/misc" "github.com/ledgerwatch/erigon/core/state" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/core/vm" @@ -102,6 +104,9 @@ if err := InitializeBlockExecution(engine, chainReader, block.Header(), chainConfig, ibs, logger); err != nil { return nil, err } + + // Optimism Canyon + misc.EnsureCreate2Deployer(chainConfig, header.Time, ibs)   noop := state.NewNoopWriter() //fmt.Printf("====txs processing start: %d====\n", block.NumberU64()) @@ -208,6 +213,9 @@ return h }   func SysCallContract(contract libcommon.Address, data []byte, chainConfig *chain.Config, ibs *state.IntraBlockState, header *types.Header, engine consensus.EngineReader, constCall bool) (result []byte, err error) { + // Optimism Canyon + misc.EnsureCreate2Deployer(chainConfig, header.Time, ibs) + msg := types.NewMessage( state.SystemAddress, &contract, @@ -232,6 +240,7 @@ author = &state.SystemAddress txContext = NewEVMTxContext(msg) } blockContext := NewEVMBlockContext(header, GetHashFn(header, nil), engine, author) + blockContext.L1CostFunc = opstack.NewL1CostFunc(chainConfig, ibs) evm := vm.NewEVM(blockContext, txContext, ibs, chainConfig, vmConfig)   ret, _, err := evm.Call( @@ -250,6 +259,9 @@ }   // SysCreate is a special (system) contract creation methods for genesis constructors. func SysCreate(contract libcommon.Address, data []byte, chainConfig chain.Config, ibs *state.IntraBlockState, header *types.Header) (result []byte, err error) { + // Optimism Canyon + misc.EnsureCreate2Deployer(&chainConfig, header.Time, ibs) + msg := types.NewMessage( contract, nil, // to @@ -266,6 +278,7 @@ // Create a new context to be used in the EVM environment author := &contract txContext := NewEVMTxContext(msg) blockContext := NewEVMBlockContext(header, GetHashFn(header, nil), nil, author) + blockContext.L1CostFunc = opstack.NewL1CostFunc(&chainConfig, ibs) evm := vm.NewEVM(blockContext, txContext, ibs, &chainConfig, vmConfig)   ret, _, err := evm.SysCreate(
diff --git ledgerwatch/erigon/core/genesis_test.go bobanetwork/v3-erigon/core/genesis_test.go index 174a9df7c8b67fdb05fba550190dc27dcf05a4f5..8b52e2b5d89eb116ee283515cb43759d5691ad3e 100644 --- ledgerwatch/erigon/core/genesis_test.go +++ bobanetwork/v3-erigon/core/genesis_test.go @@ -34,13 +34,16 @@ if err != nil { t.Fatal(err) } defer tx.Rollback() - _, block, err := core.WriteGenesisBlock(tx, genesis, nil, "", logger) + _, block, err := core.WriteGenesisBlock(tx, genesis, nil, nil, nil, nil, "", logger) require.NoError(t, err) expect := params.GenesisHashByChainName(network) require.NotNil(t, expect, network) require.Equal(t, block.Hash().Bytes(), expect.Bytes(), network) } for _, network := range networkname.All { + if network == "optimism-mainnet" || network == "boba-sepolia" { + t.Skip() + } check(network) } } @@ -83,13 +86,13 @@ require.NoError(t, err) defer tx.Rollback()   genesis := core.GenesisBlockByChainName(networkname.MainnetChainName) - _, _, err = core.WriteGenesisBlock(tx, genesis, nil, "", logger) + _, _, err = core.WriteGenesisBlock(tx, genesis, nil, nil, nil, nil, "", logger) require.NoError(t, err) seq, err := tx.ReadSequence(kv.EthTx) require.NoError(t, err) require.Equal(t, uint64(2), seq)   - _, _, err = core.WriteGenesisBlock(tx, genesis, nil, "", logger) + _, _, err = core.WriteGenesisBlock(tx, genesis, nil, nil, nil, nil, "", logger) require.NoError(t, err) seq, err = tx.ReadSequence(kv.EthTx) require.NoError(t, err)
diff --git ledgerwatch/erigon/core/genesis_write.go bobanetwork/v3-erigon/core/genesis_write.go index f30ca60bc9223253a228d68fc9ebd37542f43d30..07a73f339be11ecdd933ea13cc5b2b6a4d4ac8fe 100644 --- ledgerwatch/erigon/core/genesis_write.go +++ bobanetwork/v3-erigon/core/genesis_write.go @@ -24,9 +24,11 @@ "encoding/binary" "encoding/json" "fmt" "math/big" + "reflect" "sync"   "github.com/c2h5oh/datasize" + "github.com/ethereum-optimism/superchain-registry/superchain" "github.com/holiman/uint256" "github.com/ledgerwatch/log/v3" "golang.org/x/exp/slices" @@ -66,16 +68,16 @@ // error is a *params.ConfigCompatError and the new, unwritten config is returned. // // The returned chain configuration is never nil. func CommitGenesisBlock(db kv.RwDB, genesis *types.Genesis, tmpDir string, logger log.Logger) (*chain.Config, *types.Block, error) { - return CommitGenesisBlockWithOverride(db, genesis, nil, tmpDir, logger) + return CommitGenesisBlockWithOverride(db, genesis, nil, nil, nil, nil, tmpDir, logger) }   -func CommitGenesisBlockWithOverride(db kv.RwDB, genesis *types.Genesis, overrideCancunTime *big.Int, tmpDir string, logger log.Logger) (*chain.Config, *types.Block, error) { +func CommitGenesisBlockWithOverride(db kv.RwDB, genesis *types.Genesis, overrideCancunTime, overrideShanghaiTime, overrideOptimismCanyonTime, overrideOptimismEcotoneTime *big.Int, tmpDir string, logger log.Logger) (*chain.Config, *types.Block, error) { tx, err := db.BeginRw(context.Background()) if err != nil { return nil, nil, err } defer tx.Rollback() - c, b, err := WriteGenesisBlock(tx, genesis, overrideCancunTime, tmpDir, logger) + c, b, err := WriteGenesisBlock(tx, genesis, overrideCancunTime, overrideShanghaiTime, overrideOptimismCanyonTime, overrideOptimismEcotoneTime, tmpDir, logger) if err != nil { return c, b, err } @@ -86,7 +88,8 @@ } return c, b, nil }   -func WriteGenesisBlock(tx kv.RwTx, genesis *types.Genesis, overrideCancunTime *big.Int, tmpDir string, logger log.Logger) (*chain.Config, *types.Block, error) { +func WriteGenesisBlock(tx kv.RwTx, genesis *types.Genesis, overrideCancunTime, overrideShanghaiTime, overrideOptimismCanyonTime, overrideOptimismEcotoneTime *big.Int, + tmpDir string, logger log.Logger) (*chain.Config, *types.Block, error) { var storedBlock *types.Block if genesis != nil && genesis.Config == nil { return params.AllProtocolChanges, nil, types.ErrGenesisNoConfig @@ -98,9 +101,38 @@ return nil, nil, storedErr }   applyOverrides := func(config *chain.Config) { + if overrideShanghaiTime != nil { + config.ShanghaiTime = overrideShanghaiTime + } if overrideCancunTime != nil { config.CancunTime = overrideCancunTime } + if config.IsOptimism() && overrideOptimismCanyonTime != nil { + config.CanyonTime = overrideOptimismCanyonTime + // Shanghai hardfork is included in canyon hardfork + config.ShanghaiTime = overrideOptimismCanyonTime + if config.Optimism.EIP1559DenominatorCanyon == 0 { + logger.Warn("EIP1559DenominatorCanyon set to 0. Overriding to 250 to avoid divide by zero.") + config.Optimism.EIP1559DenominatorCanyon = 250 + } + } + if overrideShanghaiTime != nil && config.IsOptimism() && overrideOptimismCanyonTime != nil { + if overrideShanghaiTime.Cmp(overrideOptimismCanyonTime) != 0 { + logger.Warn("Shanghai hardfork time is overridden by optimism canyon time", + "shanghai", overrideShanghaiTime.String(), "canyon", overrideOptimismCanyonTime.String()) + } + } + if config.IsOptimism() && overrideOptimismEcotoneTime != nil { + config.EcotoneTime = overrideOptimismEcotoneTime + // Cancun hardfork is included in Ecotone hardfork + config.CancunTime = overrideOptimismEcotoneTime + } + if overrideCancunTime != nil && config.IsOptimism() && overrideOptimismEcotoneTime != nil { + if overrideCancunTime.Cmp(overrideOptimismEcotoneTime) != 0 { + logger.Warn("Cancun hardfork time is overridden by optimism Ecotone time", + "cancun", overrideCancunTime.String(), "ecotone", overrideOptimismEcotoneTime.String()) + } + } }   if (storedHash == libcommon.Hash{}) { @@ -165,6 +197,18 @@ if genesis == nil && params.ChainConfigByGenesisHash(storedHash) == nil { newCfg = storedCfg applyOverrides(newCfg) } + + if newCfg.IsOptimism() { + if !reflect.DeepEqual(newCfg, storedCfg) { + log.Info("Update latest chain config from superchain registry") + } + // rewrite using superchain config just in case + if err := rawdb.WriteChainConfig(tx, storedHash, newCfg); err != nil { + return newCfg, nil, err + } + return newCfg, storedBlock, nil + } + // Check config compatibility and write the config. Compatibility errors // are returned to the caller unless we're already at block zero. height := rawdb.ReadHeaderNumber(tx, rawdb.ReadHeadHeaderHash(tx)) @@ -284,6 +328,13 @@ return nil, nil, err } if err := rawdb.WriteChainConfig(tx, block.Hash(), config); err != nil { return nil, nil, err + } + + if g.Config.TerminalTotalDifficultyPassed { + // The genesis block is implicitly the first fork choice in PoS Networks + rawdb.WriteForkchoiceHead(tx, block.Hash()) + rawdb.WriteForkchoiceFinalized(tx, block.Hash()) + rawdb.WriteForkchoiceSafe(tx, block.Hash()) }   // We support ethash/merge for issuance (for now) @@ -619,6 +670,13 @@ if err != nil { return nil, nil, err }   + if g.StateHash != nil { + if len(g.Alloc) > 0 { + panic(fmt.Errorf("cannot both have genesis hash %s "+ + "and non-empty state-allocation", *g.StateHash)) + } + root = *g.StateHash + } head.Root = root   return types.NewBlock(head, nil, nil, nil, withdrawals), statedb, nil @@ -654,6 +712,13 @@ return ga }   func GenesisBlockByChainName(chain string) *types.Genesis { + genesis, err := loadOPStackGenesisByChainName(chain) + if err != nil { + panic(err) + } + if genesis != nil { + return genesis + } switch chain { case networkname.MainnetChainName: return MainnetGenesisBlock() @@ -679,3 +744,98 @@ default: return nil } } + +// loadOPStackGenesisByChainName loads genesis block corresponding to the chain name from superchain regsitry. +// This implementation is based on op-geth(https://github.com/ethereum-optimism/op-geth/blob/c7871bc4454ffc924eb128fa492975b30c9c46ad/core/superchain.go#L13) +func loadOPStackGenesisByChainName(name string) (*types.Genesis, error) { + opStackChainCfg := params.OPStackChainConfigByName(name) + if opStackChainCfg == nil { + return nil, nil + } + + cfg := params.LoadSuperChainConfig(opStackChainCfg) + if cfg == nil { + return nil, nil + } + + gen, err := superchain.LoadGenesis(opStackChainCfg.ChainID) + if err != nil { + return nil, fmt.Errorf("failed to load genesis definition for chain %d: %w", opStackChainCfg.ChainID, err) + } + + genesis := &types.Genesis{ + Config: cfg, + Nonce: gen.Nonce, + Timestamp: gen.Timestamp, + ExtraData: gen.ExtraData, + GasLimit: gen.GasLimit, + Difficulty: (*big.Int)(gen.Difficulty), + Mixhash: libcommon.Hash(gen.Mixhash), + Coinbase: libcommon.Address(gen.Coinbase), + Alloc: make(types.GenesisAlloc), + Number: gen.Number, + GasUsed: gen.GasUsed, + ParentHash: libcommon.Hash(gen.ParentHash), + BaseFee: (*big.Int)(gen.BaseFee), + } + + for addr, acc := range gen.Alloc { + var code []byte + if acc.CodeHash != ([32]byte{}) { + dat, err := superchain.LoadContractBytecode(acc.CodeHash) + if err != nil { + return nil, fmt.Errorf("failed to load bytecode %s of address %s in chain %d: %w", acc.CodeHash, addr, opStackChainCfg.ChainID, err) + } + code = dat + } + var storage map[libcommon.Hash]libcommon.Hash + if len(acc.Storage) > 0 { + storage = make(map[libcommon.Hash]libcommon.Hash) + for k, v := range acc.Storage { + storage[libcommon.Hash(k)] = libcommon.Hash(v) + } + } + bal := libcommon.Big0 + if acc.Balance != nil { + bal = (*big.Int)(acc.Balance) + } + genesis.Alloc[libcommon.Address(addr)] = types.GenesisAccount{ + Code: code, + Storage: storage, + Balance: bal, + Nonce: acc.Nonce, + } + } + if gen.StateHash != nil { + if len(gen.Alloc) > 0 { + return nil, fmt.Errorf("chain definition unexpectedly contains both allocation (%d) and state-hash %s", len(gen.Alloc), *gen.StateHash) + } + genesis.StateHash = (*libcommon.Hash)(gen.StateHash) + } + + genesisBlock, _, err := GenesisToBlock(genesis, "", log.New()) + if err != nil { + return nil, fmt.Errorf("failed to build genesis block: %w", err) + } + genesisBlockHash := genesisBlock.Hash() + expectedHash := libcommon.Hash([32]byte(opStackChainCfg.Genesis.L2.Hash)) + + // Verify we correctly produced the genesis config by recomputing the genesis-block-hash, + // and check the genesis matches the chain genesis definition. + if opStackChainCfg.Genesis.L2.Number != genesisBlock.NumberU64() { + switch opStackChainCfg.ChainID { + case params.OPMainnetChainID: + expectedHash = params.OPMainnetGenesisHash + case params.OPGoerliChainID: + expectedHash = params.OPGoerliGenesisHash + case params.BobaSepoliaChainID: + expectedHash = params.BobaSepoliaGenesisHash + default: + return nil, fmt.Errorf("unknown stateless genesis definition for chain %d", opStackChainCfg.ChainID) + } + } + if expectedHash != genesisBlockHash { + return nil, fmt.Errorf("produced genesis with hash %s but expected %s", genesisBlockHash, expectedHash) + } + return genesis, nil +}
diff --git ledgerwatch/erigon/core/types/blob_tx_wrapper.go bobanetwork/v3-erigon/core/types/blob_tx_wrapper.go index 654e53e71223777f97e30e7ba1f0abe691f8d8e3..1f5c78cbb56b1e2e1bb373a0963925d90c12ee27 100644 --- ledgerwatch/erigon/core/types/blob_tx_wrapper.go +++ bobanetwork/v3-erigon/core/types/blob_tx_wrapper.go @@ -370,6 +370,10 @@ return s.ListEnd() }   +func (txw *BlobTxWrapper) RollupCostData() types2.RollupCostData { + return txw.Tx.RollupCostData() +} + // We deliberately encode only the transaction payload because the only case we need to serialize // blobs/commitments/proofs is when we reply to GetPooledTransactions (and that's handled by the txpool). func (txw BlobTxWrapper) EncodingSize() int {
diff --git ledgerwatch/erigon/core/types/deposit_tx_test.go bobanetwork/v3-erigon/core/types/deposit_tx_test.go new file mode 100644 index 0000000000000000000000000000000000000000..7ab589c08eee7d955f7a81ae12541f69ac2382ac --- /dev/null +++ bobanetwork/v3-erigon/core/types/deposit_tx_test.go @@ -0,0 +1,26 @@ +package types + +import ( + "testing" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/common" + "github.com/stretchr/testify/require" +) + +func TestDepositTxHash(t *testing.T) { + dtx := DepositTx{ + SourceHash: common.HexToHash("0xc9fa17cc88928d8303f4efcc0053ddbd8c5baea5ed4c1da2efd019833070c182"), + From: common.HexToAddress("0x976EA74026E726554dB657fA54763abd0C3a0aa9"), + To: ptr(common.HexToAddress("0x976EA74026E726554dB657fA54763abd0C3a0aa9")), + Mint: uint256.NewInt(1_000_000_000_000), + Value: uint256.NewInt(0), + Gas: 1_000_000, + } + + require.Equal(t, common.HexToHash("0x5c7753e59abb0904e0e70a28f4d24458cf20c2b5b491365411ce54a662874197"), dtx.Hash()) +} + +func ptr[T any](v T) *T { + return &v +}
diff --git ledgerwatch/erigon/core/types/gen_genesis.go bobanetwork/v3-erigon/core/types/gen_genesis.go index 3528ce38e560652ed8117b3792147470d5f7f12a..4ee6ea9efca451d7ea212e889a819dfd870f92cc 100644 --- ledgerwatch/erigon/core/types/gen_genesis.go +++ bobanetwork/v3-erigon/core/types/gen_genesis.go @@ -27,16 +27,17 @@ GasLimit math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"` Mixhash common.Hash `json:"mixHash"` Coinbase common.Address `json:"coinbase"` - BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` - BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"` - ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"` Alloc map[common0.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"` AuRaStep uint64 `json:"auRaStep"` AuRaSeal []byte `json:"auRaSeal"` - ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` Number math.HexOrDecimal64 `json:"number"` GasUsed math.HexOrDecimal64 `json:"gasUsed"` ParentHash common.Hash `json:"parentHash"` + BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` + BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"` + ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"` + ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` + StateHash *common.Hash `json:"stateHash,omitempty"` } var enc Genesis enc.Config = g.Config @@ -47,9 +48,6 @@ enc.GasLimit = math.HexOrDecimal64(g.GasLimit) enc.Difficulty = (*math.HexOrDecimal256)(g.Difficulty) enc.Mixhash = g.Mixhash enc.Coinbase = g.Coinbase - enc.BaseFee = (*math.HexOrDecimal256)(g.BaseFee) - enc.BlobGasUsed = (*math.HexOrDecimal64)(g.BlobGasUsed) - enc.ExcessBlobGas = (*math.HexOrDecimal64)(g.ExcessBlobGas) if g.Alloc != nil { enc.Alloc = make(map[common0.UnprefixedAddress]GenesisAccount, len(g.Alloc)) for k, v := range g.Alloc { @@ -58,10 +56,14 @@ } } enc.AuRaStep = g.AuRaStep enc.AuRaSeal = g.AuRaSeal - enc.ParentBeaconBlockRoot = g.ParentBeaconBlockRoot enc.Number = math.HexOrDecimal64(g.Number) enc.GasUsed = math.HexOrDecimal64(g.GasUsed) enc.ParentHash = g.ParentHash + enc.BaseFee = (*math.HexOrDecimal256)(g.BaseFee) + enc.BlobGasUsed = (*math.HexOrDecimal64)(g.BlobGasUsed) + enc.ExcessBlobGas = (*math.HexOrDecimal64)(g.ExcessBlobGas) + enc.ParentBeaconBlockRoot = g.ParentBeaconBlockRoot + enc.StateHash = g.StateHash return json.Marshal(&enc) }   @@ -76,16 +78,17 @@ GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"` Mixhash *common.Hash `json:"mixHash"` Coinbase *common.Address `json:"coinbase"` - BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` - BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"` - ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"` Alloc map[common0.UnprefixedAddress]GenesisAccount `json:"alloc" gencodec:"required"` AuRaStep *uint64 `json:"auRaStep"` AuRaSeal []byte `json:"auRaSeal"` - ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` Number *math.HexOrDecimal64 `json:"number"` GasUsed *math.HexOrDecimal64 `json:"gasUsed"` ParentHash *common.Hash `json:"parentHash"` + BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` + BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"` + ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"` + ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` + StateHash *common.Hash `json:"stateHash,omitempty"` } var dec Genesis if err := json.Unmarshal(input, &dec); err != nil { @@ -117,15 +120,6 @@ } if dec.Coinbase != nil { g.Coinbase = *dec.Coinbase } - if dec.BaseFee != nil { - g.BaseFee = (*big.Int)(dec.BaseFee) - } - if dec.BlobGasUsed != nil { - g.BlobGasUsed = (*uint64)(dec.BlobGasUsed) - } - if dec.ExcessBlobGas != nil { - g.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) - } if dec.Alloc == nil { return errors.New("missing required field 'alloc' for Genesis") } @@ -139,9 +133,6 @@ } if dec.AuRaSeal != nil { g.AuRaSeal = dec.AuRaSeal } - if dec.ParentBeaconBlockRoot != nil { - g.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot - } if dec.Number != nil { g.Number = uint64(*dec.Number) } @@ -150,6 +141,21 @@ g.GasUsed = uint64(*dec.GasUsed) } if dec.ParentHash != nil { g.ParentHash = *dec.ParentHash + } + if dec.BaseFee != nil { + g.BaseFee = (*big.Int)(dec.BaseFee) + } + if dec.BlobGasUsed != nil { + g.BlobGasUsed = (*uint64)(dec.BlobGasUsed) + } + if dec.ExcessBlobGas != nil { + g.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) + } + if dec.ParentBeaconBlockRoot != nil { + g.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot + } + if dec.StateHash != nil { + g.StateHash = dec.StateHash } return nil }
diff --git ledgerwatch/erigon/core/types/gen_genesis_account.go bobanetwork/v3-erigon/core/types/gen_genesis_account.go index 21fa482d88cef96644e252d516ecda7d175508f9..858502cbdbb829e4861606cfb94bbaf9b277a9e7 100644 --- ledgerwatch/erigon/core/types/gen_genesis_account.go +++ bobanetwork/v3-erigon/core/types/gen_genesis_account.go @@ -7,9 +7,8 @@ "encoding/json" "errors" "math/big"   - libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/hexutility" - "github.com/ledgerwatch/erigon/common/math" )   @@ -61,9 +60,9 @@ if dec.Code != nil { g.Code = *dec.Code } if dec.Storage != nil { - g.Storage = make(map[libcommon.Hash]libcommon.Hash, len(dec.Storage)) + g.Storage = make(map[common.Hash]common.Hash, len(dec.Storage)) for k, v := range dec.Storage { - g.Storage[libcommon.Hash(k)] = libcommon.Hash(v) + g.Storage[common.Hash(k)] = common.Hash(v) } } if dec.Balance == nil {
diff --git ledgerwatch/erigon/core/types/gen_withdrawal_json.go bobanetwork/v3-erigon/core/types/gen_withdrawal_json.go index 6ed318cc54bc89d439e9c391f32b493289df78d0..64d39fba79ea2c4ea9dc43a04fc5834bac936be1 100644 --- ledgerwatch/erigon/core/types/gen_withdrawal_json.go +++ bobanetwork/v3-erigon/core/types/gen_withdrawal_json.go @@ -4,9 +4,9 @@ package types   import ( "encoding/json" - "github.com/ledgerwatch/erigon-lib/common/hexutil"   "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/hexutil" )   var _ = (*withdrawalMarshaling)(nil)
diff --git ledgerwatch/erigon/core/types/genesis.go bobanetwork/v3-erigon/core/types/genesis.go index d6f0e8cbc218a423394544b38a09c5892c60ab90..5023108b4f3febabbd21b663c431e935025da5ee 100644 --- ledgerwatch/erigon/core/types/genesis.go +++ bobanetwork/v3-erigon/core/types/genesis.go @@ -65,6 +65,11 @@ BaseFee *big.Int `json:"baseFeePerGas"` // EIP-1559 BlobGasUsed *uint64 `json:"blobGasUsed"` // EIP-4844 ExcessBlobGas *uint64 `json:"excessBlobGas"` // EIP-4844 ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` // EIP-4788 + + // StateHash represents the genesis state, to allow instantiation of a chain with missing initial state. + // Chains with history pruning, or extraordinarily large genesis allocation (e.g. after a regenesis event) + // may utilize this to get started, and then state-sync the latest state, while still verifying the header chain. + StateHash *common.Hash `json:"stateHash,omitempty"` }   // GenesisAlloc specifies the initial state that is part of the genesis block.
diff --git ledgerwatch/erigon/docker-compose.yml bobanetwork/v3-erigon/docker-compose.yml index e1a5be919d376f182158d1d0985048f97792fd74..36ecaa115ad4821d822c61f5c7aaafa55694a1db 100644 --- ledgerwatch/erigon/docker-compose.yml +++ bobanetwork/v3-erigon/docker-compose.yml @@ -15,7 +15,7 @@ version: '2.2'   # Basic erigon's service x-erigon-service: &default-erigon-service - image: thorax/erigon:${TAG:-latest} + image: erigon:${TAG:-latest} pid: service:erigon # Use erigon's PID namespace. It's required to open Erigon's DB from another process (RPCDaemon local-mode) volumes_from: [ erigon ] restart: unless-stopped @@ -24,7 +24,7 @@ user: ${DOCKER_UID:-1000}:${DOCKER_GID:-1000}   services: erigon: - image: thorax/erigon:${TAG:-latest} + image: bobanetwork/erigon-base:${TAG:-latest} build: args: UID: ${DOCKER_UID:-1000}
diff --git ledgerwatch/erigon/erigon-lib/chain/networkname/network_name.go bobanetwork/v3-erigon/erigon-lib/chain/networkname/network_name.go index 877b3738976e46c9d4cd041332b6c3fb852c8aaf..641997e64c7e09a66556fb7ff54abf180661342a 100644 --- ledgerwatch/erigon/erigon-lib/chain/networkname/network_name.go +++ bobanetwork/v3-erigon/erigon-lib/chain/networkname/network_name.go @@ -13,6 +13,18 @@ BorDevnetChainName = "bor-devnet" GnosisChainName = "gnosis" BorE2ETestChain2ValName = "bor-e2e-test-2Val" ChiadoChainName = "chiado" + + OPMainnetChainName = "op-mainnet" + OPGoerliChainName = "op-goerli" + OPSepoliaChainName = "op-sepolia" + + BobaSepoliaChainName = "boba-sepolia" + + LegacyOPMainnetChainName = "optimism-mainnet" + LegacyOPGoerliChainName = "optimism-goerli" + LegacyOPSepoliaChainName = "optimism-sepolia" + + BobaSepoliaSuperchainName = "boba-boba-sepolia" )   var All = []string{ @@ -26,4 +38,32 @@ BorMainnetChainName, BorDevnetChainName, GnosisChainName, ChiadoChainName, + + OPMainnetChainName, + OPSepoliaChainName, + OPGoerliChainName, + + BobaSepoliaChainName, +} + +func HandleLegacyName(name string) string { + switch name { + case LegacyOPGoerliChainName: + return OPGoerliChainName + case LegacyOPSepoliaChainName: + return OPSepoliaChainName + case LegacyOPMainnetChainName: + return OPMainnetChainName + default: + return name + } +} + +func HandleBobaSuperchainName(name string) string { + switch name { + case BobaSepoliaChainName: + return BobaSepoliaSuperchainName + default: + return name + } }
diff --git ledgerwatch/erigon/erigon-lib/go.mod bobanetwork/v3-erigon/erigon-lib/go.mod index e424d2cb2c8de6d569f9dd92ef2cd5129103b37e..f1c9a70e70a253c2cd216f70bfcd4c9ccd886551 100644 --- ledgerwatch/erigon/erigon-lib/go.mod +++ bobanetwork/v3-erigon/erigon-lib/go.mod @@ -149,3 +149,7 @@ modernc.org/sqlite v1.26.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect zombiezen.com/go/sqlite v0.13.1 // indirect ) + +replace github.com/ledgerwatch/interfaces => github.com/bobanetwork/v3-erigon-interfaces v0.0.0-20240209204708-d76c58717dca + +// replace github.com/ledgerwatch/interfaces => ../erigon-interfaces
diff --git ledgerwatch/erigon/erigon-lib/go.sum bobanetwork/v3-erigon/erigon-lib/go.sum index 126b278b19e19805fdf480db52102a5c0b9c970f..8c31bee951e9bc0196856b0274334b1ef011b1ed 100644 --- ledgerwatch/erigon/erigon-lib/go.sum +++ bobanetwork/v3-erigon/erigon-lib/go.sum @@ -127,6 +127,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bobanetwork/v3-erigon-interfaces v0.0.0-20240209204708-d76c58717dca h1:PAwKCwu28Jdr5nErdgYJgdtkWENyijS0OviNW0gxIm8= +github.com/bobanetwork/v3-erigon-interfaces v0.0.0-20240209204708-d76c58717dca/go.mod h1:ugQv1QllJzBny3cKZKxUrSnykkjkBgm27eQM6dnGAcc= github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8= @@ -295,8 +297,6 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/ledgerwatch/erigon-snapshot v1.3.1-0.20240115083615-b5feeb63e191 h1:X/mHEyh0xEuhixj6hKCNQl04NuNDToYWJ08vr66e6L0= github.com/ledgerwatch/erigon-snapshot v1.3.1-0.20240115083615-b5feeb63e191/go.mod h1:3AuPxZc85jkehh/HA9h8gabv5MSi3kb/ddtzBsTVJFo= -github.com/ledgerwatch/interfaces v0.0.0-20240105174738-fe57049f198c h1:j9IrDNf6oTtc9R+1rra3Umf7xIYvTgJWXsCavGcqv7k= -github.com/ledgerwatch/interfaces v0.0.0-20240105174738-fe57049f198c/go.mod h1:ugQv1QllJzBny3cKZKxUrSnykkjkBgm27eQM6dnGAcc= github.com/ledgerwatch/log/v3 v3.9.0 h1:iDwrXe0PVwBC68Dd94YSsHbMgQ3ufsgjzXtFNFVZFRk= github.com/ledgerwatch/log/v3 v3.9.0/go.mod h1:EiAY6upmI/6LkNhOVxb4eVsmsP11HZCnZ3PlJMjYiqE= github.com/ledgerwatch/secp256k1 v1.0.0 h1:Usvz87YoTG0uePIV8woOof5cQnLXGYa162rFf3YnwaQ=
diff --git ledgerwatch/erigon/erigon-lib/opstack/rollup_cost.go bobanetwork/v3-erigon/erigon-lib/opstack/rollup_cost.go new file mode 100644 index 0000000000000000000000000000000000000000..bf972342aae6c50501bdd1882b6980ed8aebb44b --- /dev/null +++ bobanetwork/v3-erigon/erigon-lib/opstack/rollup_cost.go @@ -0,0 +1,307 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +// This file implements OP stack L1 cost calculation, based on op-geth +// https://github.com/ethereum-optimism/op-geth/commit/a290ca164a36c80a8d106d88bd482b6f82220bef + +package opstack + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/chain" + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/common/fixedgas" + "github.com/ledgerwatch/erigon-lib/types" + "github.com/ledgerwatch/log/v3" +) + +const ( + // The two 4-byte Ecotone fee scalar values are packed into the same storage slot as the 8-byte + // sequence number and have the following Solidity offsets within the slot. Note that Solidity + // offsets correspond to the last byte of the value in the slot, counting backwards from the + // end of the slot. For example, The 8-byte sequence number has offset 0, and is therefore + // stored as big-endian format in bytes [24:32] of the slot. + BaseFeeScalarSlotOffset = 12 // bytes [16:20] of the slot + BlobBaseFeeScalarSlotOffset = 8 // bytes [20:24] of the slot + + // scalarSectionStart is the beginning of the scalar values segment in the slot + // array. baseFeeScalar is in the first four bytes of the segment, blobBaseFeeScalar the next + // four. + scalarSectionStart = 32 - BaseFeeScalarSlotOffset - 4 + + LegacyL1InfoBytes = 4 + 32*8 + EcotoneL1InfoBytes = 164 +) + +func init() { + if BlobBaseFeeScalarSlotOffset != BaseFeeScalarSlotOffset-4 { + panic("this code assumes the scalars are at adjacent positions in the scalars slot") + } +} + +var ( + // BedrockL1AttributesSelector is the function selector indicating Bedrock style L1 gas + // attributes. + BedrockL1AttributesSelector = []byte{0x01, 0x5d, 0x8e, 0xb9} + // EcotoneL1AttributesSelector is the selector indicating Ecotone style L1 gas attributes. + EcotoneL1AttributesSelector = []byte{0x44, 0x0a, 0x5e, 0x20} + + // L1BlockAddr is the address of the L1Block contract which stores the L1 gas attributes. + L1BlockAddr = libcommon.HexToAddress("0x4200000000000000000000000000000000000015") + + L1BaseFeeSlot = libcommon.BigToHash(big.NewInt(1)) + OverheadSlot = libcommon.BigToHash(big.NewInt(5)) + ScalarSlot = libcommon.BigToHash(big.NewInt(6)) + + // L2BlobBaseFeeSlot was added with the Ecotone upgrade and stores the blobBaseFee L1 gas + // attribute. + L1BlobBaseFeeSlot = libcommon.BigToHash(big.NewInt(7)) + // L1FeeScalarsSlot as of the Ecotone upgrade stores the 32-bit baseFeeScalar and + // blobBaseFeeScalar L1 gas attributes at offsets `BaseFeeScalarSlotOffset` and + // `BlobBaseFeeScalarSlotOffset` respectively. + L1FeeScalarsSlot = libcommon.BigToHash(big.NewInt(3)) + + oneMillion = uint256.NewInt(1_000_000) + ecotoneDivisor = uint256.NewInt(1_000_000 * 16) + sixteen = uint256.NewInt(16) + + emptyScalars = make([]byte, 8) +) + +type StateGetter interface { + GetState(addr libcommon.Address, key *libcommon.Hash, value *uint256.Int) +} + +// L1CostFunc is used in the state transition to determine the data availability fee charged to the +// sender of non-Deposit transactions. It returns nil if no data availability fee is charged. +type L1CostFunc func(rcd types.RollupCostData, blockTime uint64) *uint256.Int + +// l1CostFunc is an internal version of L1CostFunc that also returns the gasUsed for use in +// receipts. +type l1CostFunc func(rcd types.RollupCostData) (fee, gasUsed *uint256.Int) + +// NewL1CostFunc returns a function used for calculating data availability fees, or nil if this is +// not an op-stack chain. +func NewL1CostFunc(config *chain.Config, statedb StateGetter) L1CostFunc { + if config.Optimism == nil { + return nil + } + forBlock := ^uint64(0) + var cachedFunc l1CostFunc + return func(rollupCostData types.RollupCostData, blockTime uint64) *uint256.Int { + if rollupCostData == (types.RollupCostData{}) { + return nil // Do not charge if there is no rollup cost-data (e.g. RPC call or deposit). + } + if forBlock != blockTime { + if forBlock != ^uint64(0) { + // best practice is not to re-use l1 cost funcs across different blocks, but we + // make it work just in case. + log.Info("l1 cost func re-used for different L1 block", "oldTime", forBlock, "newTime", blockTime) + } + forBlock = blockTime + // Note: the various state variables below are not initialized from the DB until this + // point to allow deposit transactions from the block to be processed first by state + // transition. This behavior is consensus critical! + if !config.IsOptimismEcotone(blockTime) { + cachedFunc = newL1CostFuncBedrock(config, statedb, blockTime) + } else { + var l1BlobBaseFee, l1FeeScalarsInt uint256.Int + statedb.GetState(L1BlockAddr, &L1BlobBaseFeeSlot, &l1BlobBaseFee) + statedb.GetState(L1BlockAddr, &L1FeeScalarsSlot, &l1FeeScalarsInt) + l1FeeScalars := l1FeeScalarsInt.Bytes32() + + // Edge case: the very first Ecotone block requires we use the Bedrock cost + // function. We detect this scenario by checking if the Ecotone parameters are + // unset. Not here we rely on assumption that the scalar parameters are adjacent + // in the buffer and baseFeeScalar comes first. + if l1BlobBaseFee.BitLen() == 0 && + bytes.Equal(emptyScalars, l1FeeScalars[scalarSectionStart:scalarSectionStart+8]) { + log.Info("using bedrock l1 cost func for first Ecotone block", "time", blockTime) + cachedFunc = newL1CostFuncBedrock(config, statedb, blockTime) + } else { + var l1BaseFee uint256.Int + statedb.GetState(L1BlockAddr, &L1BaseFeeSlot, &l1BaseFee) + offset := scalarSectionStart + l1BaseFeeScalar := new(uint256.Int).SetBytes(l1FeeScalars[offset : offset+4]) + l1BlobBaseFeeScalar := new(uint256.Int).SetBytes(l1FeeScalars[offset+4 : offset+8]) + cachedFunc = newL1CostFuncEcotone(&l1BaseFee, &l1BlobBaseFee, l1BaseFeeScalar, l1BlobBaseFeeScalar) + } + } + } + fee, _ := cachedFunc(rollupCostData) + return fee + } +} + +// newL1CostFuncBedrock returns an L1 cost function suitable for Bedrock, Regolith, and the first +// block only of the Ecotone upgrade. +func newL1CostFuncBedrock(config *chain.Config, statedb StateGetter, blockTime uint64) l1CostFunc { + var l1BaseFee, overhead, scalar uint256.Int + statedb.GetState(L1BlockAddr, &L1BaseFeeSlot, &l1BaseFee) + statedb.GetState(L1BlockAddr, &OverheadSlot, &overhead) + statedb.GetState(L1BlockAddr, &ScalarSlot, &scalar) + isRegolith := config.IsRegolith(blockTime) + return newL1CostFuncBedrockHelper(&l1BaseFee, &overhead, &scalar, isRegolith) +} + +// newL1CostFuncBedrockHelper is lower level version of newL1CostFuncBedrock that expects already +// extracted parameters +func newL1CostFuncBedrockHelper(l1BaseFee, overhead, scalar *uint256.Int, isRegolith bool) l1CostFunc { + return func(rollupCostData types.RollupCostData) (fee, gasUsed *uint256.Int) { + if rollupCostData == (types.RollupCostData{}) { + return nil, nil // Do not charge if there is no rollup cost-data (e.g. RPC call or deposit) + } + gas := rollupCostData.Zeroes * fixedgas.TxDataZeroGas + if isRegolith { + gas += rollupCostData.Ones * fixedgas.TxDataNonZeroGasEIP2028 + } else { + gas += (rollupCostData.Ones + 68) * fixedgas.TxDataNonZeroGasEIP2028 + } + gasWithOverhead := uint256.NewInt(gas) + gasWithOverhead.Add(gasWithOverhead, overhead) + l1Cost := l1CostHelper(gasWithOverhead, l1BaseFee, scalar) + return l1Cost, gasWithOverhead + } +} + +// newL1CostFuncEcotone returns an l1 cost function suitable for the Ecotone upgrade except for the +// very first block of the upgrade. +func newL1CostFuncEcotone(l1BaseFee, l1BlobBaseFee, l1BaseFeeScalar, l1BlobBaseFeeScalar *uint256.Int) l1CostFunc { + return func(costData types.RollupCostData) (fee, calldataGasUsed *uint256.Int) { + calldataGas := (costData.Zeroes * fixedgas.TxDataZeroGas) + (costData.Ones * fixedgas.TxDataNonZeroGasEIP2028) + calldataGasUsed = new(uint256.Int).SetUint64(calldataGas) + + // Ecotone L1 cost function: + // + // (calldataGas/16)*(l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar)/1e6 + // + // We divide "calldataGas" by 16 to change from units of calldata gas to "estimated # of bytes when + // compressed". Known as "compressedTxSize" in the spec. + // + // Function is actually computed as follows for better precision under integer arithmetic: + // + // calldataGas*(l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar)/16e6 + + calldataCostPerByte := new(uint256.Int).Set(l1BaseFee) + calldataCostPerByte = calldataCostPerByte.Mul(calldataCostPerByte, sixteen) + calldataCostPerByte = calldataCostPerByte.Mul(calldataCostPerByte, l1BaseFeeScalar) + + blobCostPerByte := new(uint256.Int).Set(l1BlobBaseFee) + blobCostPerByte = blobCostPerByte.Mul(blobCostPerByte, l1BlobBaseFeeScalar) + + fee = new(uint256.Int).Add(calldataCostPerByte, blobCostPerByte) + fee = fee.Mul(fee, calldataGasUsed) + fee = fee.Div(fee, ecotoneDivisor) + + return fee, calldataGasUsed + } +} + +// ExtractL1GasParams extracts the gas parameters necessary to compute gas costs from L1 block info +// calldata. +func ExtractL1GasParams(config *chain.Config, time uint64, data []byte) (l1BaseFee *uint256.Int, costFunc l1CostFunc, feeScalar *big.Float, err error) { + if config.IsEcotone(time) { + // edge case: for the very first Ecotone block we still need to use the Bedrock + // function. We detect this edge case by seeing if the function selector is the old one + if len(data) >= 4 && !bytes.Equal(data[0:4], BedrockL1AttributesSelector) { + l1BaseFee, costFunc, err = extractL1GasParamsEcotone(data) + return + } + } + return extractL1GasParamsLegacy(config.IsRegolith(time), data) +} + +func extractL1GasParamsLegacy(isRegolith bool, data []byte) (l1BaseFee *uint256.Int, costFunc l1CostFunc, feeScalar *big.Float, err error) { + // data consists of func selector followed by 7 ABI-encoded parameters (32 bytes each) + if len(data) < LegacyL1InfoBytes { + return nil, nil, nil, fmt.Errorf("expected at least %d L1 info bytes, got %d", LegacyL1InfoBytes, len(data)) + } + data = data[4:] // trim function selector + l1BaseFee = new(uint256.Int).SetBytes(data[32*2 : 32*3]) // arg index 2 + overhead := new(uint256.Int).SetBytes(data[32*6 : 32*7]) // arg index 6 + scalar := new(uint256.Int).SetBytes(data[32*7 : 32*8]) // arg index 7 + fscalar := new(big.Float).SetInt(scalar.ToBig()) // legacy: format fee scalar as big Float + fdivisor := new(big.Float).SetUint64(1_000_000) // 10**6, i.e. 6 decimals + feeScalar = new(big.Float).Quo(fscalar, fdivisor) + costFunc = newL1CostFuncBedrockHelper(l1BaseFee, overhead, scalar, isRegolith) + return l1BaseFee, costFunc, feeScalar, nil +} + +// extractEcotoneL1GasParams extracts the gas parameters necessary to compute gas from L1 attribute +// info calldata after the Ecotone upgrade, but not for the very first Ecotone block. +func extractL1GasParamsEcotone(data []byte) (l1BaseFee *uint256.Int, costFunc l1CostFunc, err error) { + if len(data) != EcotoneL1InfoBytes { + return nil, nil, fmt.Errorf("expected 164 L1 info bytes, got %d", len(data)) + } + // data layout assumed for Ecotone: + // offset type varname + // 0 <selector> + // 4 uint32 _baseFeeScalar + // 8 uint32 _blobBaseFeeScalar + // 12 uint64 _sequenceNumber, + // 20 uint64 _timestamp, + // 28 uint64 _l1BlockNumber + // 36 uint256 _baseFee, + // 68 uint256 _blobBaseFee, + // 100 bytes32 _hash, + // 132 bytes32 _batcherHash, + l1BaseFee = new(uint256.Int).SetBytes(data[36:68]) + l1BlobBaseFee := new(uint256.Int).SetBytes(data[68:100]) + l1BaseFeeScalar := new(uint256.Int).SetBytes(data[4:8]) + l1BlobBaseFeeScalar := new(uint256.Int).SetBytes(data[8:12]) + costFunc = newL1CostFuncEcotone(l1BaseFee, l1BlobBaseFee, l1BaseFeeScalar, l1BlobBaseFeeScalar) + return +} + +// L1Cost computes the the data availability fee for transactions in blocks prior to the Ecotone +// upgrade. It is used by e2e tests so must remain exported. +func L1Cost(rollupDataGas uint64, l1BaseFee, overhead, scalar *uint256.Int) *uint256.Int { + l1GasUsed := uint256.NewInt(rollupDataGas) + l1GasUsed.Add(l1GasUsed, overhead) + return l1CostHelper(l1GasUsed, l1BaseFee, scalar) +} + +func l1CostHelper(gasWithOverhead, l1BaseFee, scalar *uint256.Int) *uint256.Int { + fee := new(uint256.Int).Set(gasWithOverhead) + fee.Mul(fee, l1BaseFee).Mul(fee, scalar).Div(fee, oneMillion) + return fee +} + +func L1CostFnForTxPool(data []byte) (types.L1CostFn, error) { + var costFunc l1CostFunc + var err error + if len(data) == EcotoneL1InfoBytes { + _, costFunc, err = extractL1GasParamsEcotone(data) + if err != nil { + return nil, err + } + } else { + // This method is used for txpool that is needed for OP sequencer. + // Assume that isRegolith will be always true for new block. + _, costFunc, _, err = extractL1GasParamsLegacy(true, data) + if err != nil { + return nil, err + } + } + return func(tx *types.TxSlot) *uint256.Int { + fee, _ := costFunc(tx.RollupCostData) + return fee + }, nil +}
diff --git ledgerwatch/erigon/erigon-lib/opstack/rollup_cost_test.go bobanetwork/v3-erigon/erigon-lib/opstack/rollup_cost_test.go new file mode 100644 index 0000000000000000000000000000000000000000..741803422e36b4d1bb30b69376f0ae2e3a1a9475 --- /dev/null +++ bobanetwork/v3-erigon/erigon-lib/opstack/rollup_cost_test.go @@ -0,0 +1,255 @@ +package opstack + +import ( + "encoding/binary" + "math/big" + "testing" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/chain" + "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon-lib/types" + "github.com/stretchr/testify/require" +) + +// This file is based on op-geth +// https://github.com/ethereum-optimism/op-geth/commit/a290ca164a36c80a8d106d88bd482b6f82220bef + +var ( + basefee = uint256.NewInt(1000 * 1e6) + overhead = uint256.NewInt(50) + scalar = uint256.NewInt(7 * 1e6) + + blobBasefee = uint256.NewInt(10 * 1e6) + basefeeScalar = uint256.NewInt(2) + blobBasefeeScalar = uint256.NewInt(3) + + // below are the expected cost func outcomes for the above parameter settings on the emptyTx + // which is defined in transaction_test.go + bedrockFee = uint256.NewInt(11326000000000) + regolithFee = uint256.NewInt(3710000000000) + ecotoneFee = uint256.NewInt(960900) // (480/16)*(2*16*1000 + 3*10) == 960900 + + bedrockGas = uint256.NewInt(1618) + regolithGas = uint256.NewInt(530) // 530 = 1618 - (16*68) + ecotoneGas = uint256.NewInt(480) + + OptimismTestConfig = &chain.OptimismConfig{EIP1559Elasticity: 50, EIP1559Denominator: 10} + + // RollupCostData of emptyTx + emptyTxRollupCostData = types.RollupCostData{Zeroes: 0, Ones: 30} +) + +func TestBedrockL1CostFunc(t *testing.T) { + costFunc0 := newL1CostFuncBedrockHelper(basefee, overhead, scalar, false /*isRegolith*/) + costFunc1 := newL1CostFuncBedrockHelper(basefee, overhead, scalar, true) + + c0, g0 := costFunc0(emptyTxRollupCostData) // pre-Regolith + c1, g1 := costFunc1(emptyTxRollupCostData) + + require.Equal(t, bedrockFee, c0) + require.Equal(t, bedrockGas, g0) // gas-used + + require.Equal(t, regolithFee, c1) + require.Equal(t, regolithGas, g1) +} + +func TestEcotoneL1CostFunc(t *testing.T) { + costFunc := newL1CostFuncEcotone(basefee, blobBasefee, basefeeScalar, blobBasefeeScalar) + c, g := costFunc(emptyTxRollupCostData) + require.Equal(t, ecotoneGas, g) + require.Equal(t, ecotoneFee, c) +} + +func TestExtractBedrockGasParams(t *testing.T) { + regolithTime := uint64(1) + config := &chain.Config{ + Optimism: OptimismTestConfig, + RegolithTime: big.NewInt(1), + } + + data := getBedrockL1Attributes(basefee, overhead, scalar) + + _, costFuncPreRegolith, _, err := ExtractL1GasParams(config, regolithTime-1, data) + require.NoError(t, err) + + // Function should continue to succeed even with extra data (that just gets ignored) since we + // have been testing the data size is at least the expected number of bytes instead of exactly + // the expected number of bytes. It's unclear if this flexibility was intentional, but since + // it's been in production we shouldn't change this behavior. + data = append(data, []byte{0xBE, 0xEE, 0xEE, 0xFF}...) // tack on garbage data + _, costFuncRegolith, _, err := ExtractL1GasParams(config, regolithTime, data) + require.NoError(t, err) + + c, _ := costFuncPreRegolith(emptyTxRollupCostData) + require.Equal(t, bedrockFee, c) + + c, _ = costFuncRegolith(emptyTxRollupCostData) + require.Equal(t, regolithFee, c) + + // try to extract from data which has not enough params, should get error. + data = data[:len(data)-4-32] + _, _, _, err = ExtractL1GasParams(config, regolithTime, data) + require.Error(t, err) +} + +func TestExtractEcotoneGasParams(t *testing.T) { + zeroTime := big.NewInt(0) + // create a config where ecotone upgrade is active + config := &chain.Config{ + Optimism: OptimismTestConfig, + RegolithTime: zeroTime, + EcotoneTime: zeroTime, + } + require.True(t, config.IsOptimismEcotone(0)) + + data := getEcotoneL1Attributes(basefee, blobBasefee, basefeeScalar, blobBasefeeScalar) + + _, costFunc, _, err := ExtractL1GasParams(config, 0, data) + require.NoError(t, err) + + c, g := costFunc(emptyTxRollupCostData) + + require.Equal(t, ecotoneGas, g) + require.Equal(t, ecotoneFee, c) + + // make sure wrong amont of data results in error + data = append(data, 0x00) // tack on garbage byte + _, _, err = extractL1GasParamsEcotone(data) + require.Error(t, err) +} + +// make sure the first block of the ecotone upgrade is properly detected, and invokes the bedrock +// cost function appropriately +func TestFirstBlockEcotoneGasParams(t *testing.T) { + zeroTime := big.NewInt(0) + // create a config where ecotone upgrade is active + config := &chain.Config{ + Optimism: OptimismTestConfig, + RegolithTime: zeroTime, + EcotoneTime: zeroTime, + } + require.True(t, config.IsOptimismEcotone(0)) + + data := getBedrockL1Attributes(basefee, overhead, scalar) + + _, oldCostFunc, _, err := ExtractL1GasParams(config, 0, data) + require.NoError(t, err) + c, _ := oldCostFunc(emptyTxRollupCostData) + require.Equal(t, regolithFee, c) +} + +func getBedrockL1Attributes(basefee, overhead, scalar *uint256.Int) []byte { + uint256 := make([]byte, 32) + ignored := big.NewInt(1234) + data := []byte{} + data = append(data, BedrockL1AttributesSelector...) + data = append(data, ignored.FillBytes(uint256)...) // arg 0 + data = append(data, ignored.FillBytes(uint256)...) // arg 1 + data = append(data, basefee.ToBig().FillBytes(uint256)...) // arg 2 + data = append(data, ignored.FillBytes(uint256)...) // arg 3 + data = append(data, ignored.FillBytes(uint256)...) // arg 4 + data = append(data, ignored.FillBytes(uint256)...) // arg 5 + data = append(data, overhead.ToBig().FillBytes(uint256)...) // arg 6 + data = append(data, scalar.ToBig().FillBytes(uint256)...) // arg 7 + return data +} + +func getEcotoneL1Attributes(basefee, blobBasefee, basefeeScalar, blobBasefeeScalar *uint256.Int) []byte { + ignored := big.NewInt(1234) + data := []byte{} + uint256 := make([]byte, 32) + uint64bytes := make([]byte, 8) + uint32bytes := make([]byte, 4) + data = append(data, EcotoneL1AttributesSelector...) + data = append(data, basefeeScalar.ToBig().FillBytes(uint32bytes)...) + data = append(data, blobBasefeeScalar.ToBig().FillBytes(uint32bytes)...) + data = append(data, ignored.FillBytes(uint64bytes)...) + data = append(data, ignored.FillBytes(uint64bytes)...) + data = append(data, ignored.FillBytes(uint64bytes)...) + data = append(data, basefee.ToBig().FillBytes(uint256)...) + data = append(data, blobBasefee.ToBig().FillBytes(uint256)...) + data = append(data, ignored.FillBytes(uint256)...) + data = append(data, ignored.FillBytes(uint256)...) + return data +} + +type testStateGetter struct { + basefee, blobBasefee, overhead, scalar *uint256.Int + basefeeScalar, blobBasefeeScalar uint32 +} + +func (sg *testStateGetter) GetState(addr common.Address, key *common.Hash, value *uint256.Int) { + switch *key { + case L1BaseFeeSlot: + value.Set(sg.basefee) + case OverheadSlot: + value.Set(sg.overhead) + case ScalarSlot: + value.Set(sg.scalar) + case L1BlobBaseFeeSlot: + value.Set(sg.blobBasefee) + case L1FeeScalarsSlot: + offset := scalarSectionStart + buf := common.Hash{} + binary.BigEndian.PutUint32(buf[offset:offset+4], sg.basefeeScalar) + binary.BigEndian.PutUint32(buf[offset+4:offset+8], sg.blobBasefeeScalar) + value.SetBytes(buf.Bytes()) + default: + panic("unknown slot") + } +} + +// TestNewL1CostFunc tests that the appropriate cost function is selected based on the +// configuration and statedb values. +func TestNewL1CostFunc(t *testing.T) { + time := uint64(1) + config := &chain.Config{ + Optimism: OptimismTestConfig, + } + statedb := &testStateGetter{ + basefee: basefee, + overhead: overhead, + scalar: scalar, + blobBasefee: blobBasefee, + basefeeScalar: uint32(basefeeScalar.Uint64()), + blobBasefeeScalar: uint32(blobBasefeeScalar.Uint64()), + } + + costFunc := NewL1CostFunc(config, statedb) + require.NotNil(t, costFunc) + + // empty cost data should result in nil fee + fee := costFunc(types.RollupCostData{}, time) + require.Nil(t, fee) + + // emptyTx fee w/ bedrock config should be the bedrock fee + fee = costFunc(emptyTxRollupCostData, time) + require.NotNil(t, fee) + require.Equal(t, bedrockFee, fee) + + // emptyTx fee w/ regolith config should be the regolith fee + config.RegolithTime = new(big.Int).SetUint64(time) + costFunc = NewL1CostFunc(config, statedb) + require.NotNil(t, costFunc) + fee = costFunc(emptyTxRollupCostData, time) + require.NotNil(t, fee) + require.Equal(t, regolithFee, fee) + + // emptyTx fee w/ ecotone config should be the ecotone fee + config.EcotoneTime = new(big.Int).SetUint64(time) + costFunc = NewL1CostFunc(config, statedb) + fee = costFunc(emptyTxRollupCostData, time) + require.NotNil(t, fee) + require.Equal(t, ecotoneFee, fee) + + // emptyTx fee w/ ecotone config, but simulate first ecotone block by blowing away the ecotone + // params. Should result in regolith fee. + statedb.basefeeScalar = 0 + statedb.blobBasefeeScalar = 0 + statedb.blobBasefee = new(uint256.Int) + costFunc = NewL1CostFunc(config, statedb) + fee = costFunc(emptyTxRollupCostData, time) + require.NotNil(t, fee) + require.Equal(t, regolithFee, fee) +}
diff --git ledgerwatch/erigon/erigon-lib/rlp/parse.go bobanetwork/v3-erigon/erigon-lib/rlp/parse.go index cbe59749a0fb027bac332f03c796bc08510213d6..4710d0cd98f01524719e68a3f5603db5a2587a0e 100644 --- ledgerwatch/erigon/erigon-lib/rlp/parse.go +++ bobanetwork/v3-erigon/erigon-lib/rlp/parse.go @@ -237,6 +237,11 @@ copy(hashbuf, payload[pos:pos+32]) return pos + 32, nil }   +func SkipString(payload []byte, pos int) (nextPos, dataLen int, err error) { + dataPos, dataLen, err := String(payload, pos) + return dataPos + dataLen, dataLen, err +} + const ParseHashErrorPrefix = "parse hash payload"   const ParseAnnouncementsErrorPrefix = "parse announcement payload"
diff --git ledgerwatch/erigon/erigon-lib/txpool/pool.go bobanetwork/v3-erigon/erigon-lib/txpool/pool.go index d56b4d7ccece74db9207925280c0a5f56cdb4278..05699cd53a3b6ad78eb37df0a385830f8e41b1ff 100644 --- ledgerwatch/erigon/erigon-lib/txpool/pool.go +++ bobanetwork/v3-erigon/erigon-lib/txpool/pool.go @@ -57,6 +57,8 @@ "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon-lib/kv/mdbx" "github.com/ledgerwatch/erigon-lib/metrics" + "github.com/ledgerwatch/erigon-lib/opstack" + "github.com/ledgerwatch/erigon-lib/rlp" "github.com/ledgerwatch/erigon-lib/txpool/txpoolcfg" "github.com/ledgerwatch/erigon-lib/types" ) @@ -309,6 +311,14 @@ return res, nil }   +// SetInitialBlockGasLimit is a hack to allow the txpool to function before the +// op-node makes the call to create the first block, setting the block gas +// limit, and triggering the processing of the transactions in the transaction +// pool +func (p *TxPool) SetInitialBlockGasLimit(limit uint64) { + p.blockGasLimit.Store(limit) +} + func (p *TxPool) Start(ctx context.Context, db kv.RwDB) error { if p.started.Load() { return nil @@ -336,6 +346,56 @@ return nil }) }   +func RawRLPTxToOptimismL1CostFn(payload []byte) (types.L1CostFn, error) { + // skip prefix byte + if len(payload) == 0 { + return nil, fmt.Errorf("empty tx payload") + } + offset, _, err := rlp.String(payload, 0) + if err != nil { + return nil, fmt.Errorf("failed to parse rlp string: %w", err) + } + if payload[offset] != 0x7E { + return nil, fmt.Errorf("expected deposit tx type, but got %d", payload[offset]) + } + pos := offset + 1 + _, _, isList, err := rlp.Prefix(payload, pos) + if err != nil { + return nil, fmt.Errorf("failed to parse rlp prefix: %w", err) + } + if !isList { + return nil, fmt.Errorf("expected list") + } + dataPos, _, err := rlp.List(payload, pos) + if err != nil { + return nil, fmt.Errorf("bad tx rlp list start: %w", err) + } + pos = dataPos + + // skip 7 fields: + // source hash + // from + // to + // mint + // value + // gas + // isSystemTx + for i := 0; i < 7; i++ { + dataPos, dataLen, _, err := rlp.Prefix(payload, pos) + if err != nil { + return nil, fmt.Errorf("failed to skip rlp element of tx: %w", err) + } + pos = dataPos + dataLen + } + // data + dataPos, dataLen, _, err := rlp.Prefix(payload, pos) + if err != nil { + return nil, fmt.Errorf("failed to read tx data entry rlp prefix: %w", err) + } + txCalldata := payload[dataPos : dataPos+dataLen] + return opstack.L1CostFnForTxPool(txCalldata) +} + func (p *TxPool) OnNewBlock(ctx context.Context, stateChanges *remote.StateChangeBatch, unwindTxs, unwindBlobTxs, minedTxs types.TxSlots, tx kv.Tx) error { defer newBlockTimer.ObserveDuration(time.Now()) //t := time.Now() @@ -797,6 +857,16 @@ return blobs }   func (p *TxPool) validateTx(txn *types.TxSlot, isLocal bool, stateCache kvcache.CacheView) txpoolcfg.DiscardReason { + // No unauthenticated deposits allowed in the transaction pool. + // This is for spam protection, not consensus, + // as the external engine-API user authenticates deposits. + if txn.Type == types.DepositTxType { + return txpoolcfg.TxTypeNotSupported + } + if p.cfg.Optimism && txn.Type == types.BlobTxType { + return txpoolcfg.TxTypeNotSupported + } + isShanghai := p.isShanghai() || p.isAgra() if isShanghai { if txn.DataLen > fixedgas.MaxInitCodeSize { @@ -1187,7 +1257,6 @@ p.lock.Lock() defer p.lock.Unlock() return p._chainDB, p._stateCache } - func (p *TxPool) addTxs(blockNum uint64, cacheView kvcache.CacheView, senders *sendersBatch, newTxs types.TxSlots, pendingBaseFee, pendingBlobFee, blockGasLimit uint64, collect bool, logger log.Logger) (types.Announcements, []txpoolcfg.DiscardReason, error) { if assert.Enable {
diff --git ledgerwatch/erigon/erigon-lib/txpool/pool_test.go bobanetwork/v3-erigon/erigon-lib/txpool/pool_test.go index 9dcbf1cc908c0ab385e40ecf5bc488eaffda4e86..98dc31c2893bed3bd606939753f5eb7e12feacb3 100644 --- ledgerwatch/erigon/erigon-lib/txpool/pool_test.go +++ bobanetwork/v3-erigon/erigon-lib/txpool/pool_test.go @@ -733,7 +733,6 @@ assert.NoError(err) require.True(pool != nil) ctx := context.Background() var stateVersionID uint64 = 0 - h1 := gointerfaces.ConvertHashToH256([32]byte{}) change := &remote.StateChangeBatch{ StateVersionId: stateVersionID, @@ -750,7 +749,6 @@ // Add 1 eth to the user account, as a part of change v := make([]byte, types.EncodeSenderLengthForStorage(2, *uint256.NewInt(1 * common.Ether))) types.EncodeSender(2, *uint256.NewInt(1 * common.Ether), v) - change.ChangeBatch[0].Changes = append(change.ChangeBatch[0].Changes, &remote.AccountChange{ Action: remote.Action_UPSERT, Address: gointerfaces.ConvertAddressToH160(addr), @@ -779,7 +777,6 @@ for _, reason := range reasons { assert.Equal(txpoolcfg.Success, reason, reason.String()) } } - { // try to replace it with 5% extra blob gas, 2x higher tx fee - should fail txSlots := types.TxSlots{}
diff --git ledgerwatch/erigon/erigon-lib/txpool/txpoolcfg/txpoolcfg.go bobanetwork/v3-erigon/erigon-lib/txpool/txpoolcfg/txpoolcfg.go index 4dc6169c948c20f0a0d49eb945c5bb062d723f22..6db72506c17437ef74183ab4d45a94a4840ae678 100644 --- ledgerwatch/erigon/erigon-lib/txpool/txpoolcfg/txpoolcfg.go +++ bobanetwork/v3-erigon/erigon-lib/txpool/txpoolcfg/txpoolcfg.go @@ -29,17 +29,20 @@ "github.com/ledgerwatch/erigon-lib/types" )   type Config struct { - DBDir string - TracedSenders []string // List of senders for which tx pool should print out debugging info - PendingSubPoolLimit int - BaseFeeSubPoolLimit int - QueuedSubPoolLimit int - MinFeeCap uint64 - AccountSlots uint64 // Number of executable transaction slots guaranteed per account - BlobSlots uint64 // Total number of blobs (not txs) allowed per account - PriceBump uint64 // Price bump percentage to replace an already existing transaction - BlobPriceBump uint64 //Price bump percentage to replace an existing 4844 blob tx (type-3) - OverrideCancunTime *big.Int + DBDir string + TracedSenders []string // List of senders for which tx pool should print out debugging info + PendingSubPoolLimit int + BaseFeeSubPoolLimit int + QueuedSubPoolLimit int + MinFeeCap uint64 + AccountSlots uint64 // Number of executable transaction slots guaranteed per account + BlobSlots uint64 // Total number of blobs (not txs) allowed per account + PriceBump uint64 // Price bump percentage to replace an already existing transaction + BlobPriceBump uint64 //Price bump percentage to replace an existing 4844 blob tx (type-3) + OverrideShanghaiTime *big.Int + OverrideCancunTime *big.Int + + OverrideOptimismCanyonTime *big.Int   // regular batch tasks processing SyncToNewPeersEvery time.Duration @@ -52,6 +55,7 @@ MdbxPageSize datasize.ByteSize MdbxDBSizeLimit datasize.ByteSize MdbxGrowthStep datasize.ByteSize   + Optimism bool NoGossip bool // this mode doesn't broadcast any txs, and if receive remote-txn - skip it }   @@ -108,6 +112,7 @@ UnequalBlobTxExt DiscardReason = 27 // blob_versioned_hashes, blobs, commitments and proofs must have equal number BlobHashCheckFail DiscardReason = 28 // KZGcommitment's versioned hash has to be equal to blob_versioned_hash at the same index UnmatchedBlobTxExt DiscardReason = 29 // KZGcommitments must match the corresponding blobs and proofs BlobTxReplace DiscardReason = 30 // Cannot replace type-3 blob txn with another type of txn + TxTypeNotSupported DiscardReason = 31 )   func (r DiscardReason) String() string { @@ -160,6 +165,8 @@ case InitCodeTooLarge: return "initcode too large" case TypeNotActivated: return "fork supporting this transaction type is not activated yet" + case TxTypeNotSupported: + return types.ErrTxTypeNotSupported.Error() case CreateBlobTxn: return "blob transactions cannot have the form of a create transaction" case NoBlobs:
diff --git ledgerwatch/erigon/eth/gasprice/feehistory.go bobanetwork/v3-erigon/eth/gasprice/feehistory.go index 2e9923a23022bde9242d9d2fd1a3c21b608095d8..045936daeb130b997f9fe3547ced0e2320d37bb7 100644 --- ledgerwatch/erigon/eth/gasprice/feehistory.go +++ bobanetwork/v3-erigon/eth/gasprice/feehistory.go @@ -83,7 +83,7 @@ if bf.baseFee = bf.header.BaseFee; bf.baseFee == nil { bf.baseFee = new(big.Int) } if chainconfig.IsLondon(bf.blockNumber + 1) { - bf.nextBaseFee = misc.CalcBaseFee(chainconfig, bf.header) + bf.nextBaseFee = misc.CalcBaseFee(chainconfig, bf.header, bf.header.Time+1) } else { bf.nextBaseFee = new(big.Int) }
diff --git ledgerwatch/erigon/eth/gasprice/gasprice.go bobanetwork/v3-erigon/eth/gasprice/gasprice.go index 81c47fc161d8a07e9033e4ed97fce8bec3f813bb..46dc23edcf1213950e0c64c39aacbbf4e5add8de 100644 --- ledgerwatch/erigon/eth/gasprice/gasprice.go +++ bobanetwork/v3-erigon/eth/gasprice/gasprice.go @@ -62,6 +62,8 @@ checkBlocks int percentile int maxHeaderHistory, maxBlockHistory int + + minSuggestedPriorityFee *big.Int // for Optimism fee suggestion }   // NewOracle returns a new gasprice oracle which can recommend suitable @@ -91,7 +93,7 @@ if ignorePrice == nil || ignorePrice.Int64() < 0 { ignorePrice = gaspricecfg.DefaultIgnorePrice log.Warn("Sanitizing invalid gasprice oracle ignore price", "provided", params.IgnorePrice, "updated", ignorePrice) } - return &Oracle{ + r := &Oracle{ backend: backend, lastPrice: params.Default, maxPrice: maxPrice, @@ -102,6 +104,17 @@ cache: cache, maxHeaderHistory: params.MaxHeaderHistory, maxBlockHistory: params.MaxBlockHistory, } + + if backend.ChainConfig().IsOptimism() { + r.minSuggestedPriorityFee = params.MinSuggestedPriorityFee + if r.minSuggestedPriorityFee == nil || r.minSuggestedPriorityFee.Int64() <= 0 { + r.minSuggestedPriorityFee = gaspricecfg.DefaultMinSuggestedPriorityFee + log.Warn("Sanitizing invalid optimism gasprice oracle min priority fee suggestion", + "provided", params.MinSuggestedPriorityFee, + "updated", r.minSuggestedPriorityFee) + } + } + return r }   // SuggestTipCap returns a TipCap so that newly created transaction can @@ -127,6 +140,10 @@ // check again, the last request could have populated the cache latestHead, latestPrice = oracle.cache.GetLatest() if latestHead == headHash { return latestPrice, nil + } + + if oracle.backend.ChainConfig().IsOptimism() { + return oracle.SuggestOptimismPriorityFee(ctx, head, headHash), nil }   number := head.Number.Uint64() @@ -280,3 +297,9 @@ old[n-1] = nil // avoid memory leak *s = old[0 : n-1] return x } + +type bigIntArray []*big.Int + +func (s bigIntArray) Len() int { return len(s) } +func (s bigIntArray) Less(i, j int) bool { return s[i].Cmp(s[j]) < 0 } +func (s bigIntArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
diff --git ledgerwatch/erigon/eth/gasprice/gasprice_test.go bobanetwork/v3-erigon/eth/gasprice/gasprice_test.go index 96184ffc296a0637c1fb1810fcd9d633bd58b1f8..9897084847a0e51156b4b0d397bdadb840b61606 100644 --- ledgerwatch/erigon/eth/gasprice/gasprice_test.go +++ bobanetwork/v3-erigon/eth/gasprice/gasprice_test.go @@ -53,7 +53,7 @@ return nil, err } defer tx.Rollback()   - receipts := rawdb.ReadReceipts(tx, block, nil) + receipts := rawdb.ReadReceipts(b.cfg, tx, block, nil) return receipts, nil }
diff --git ledgerwatch/erigon/eth/gasprice/gaspricecfg/gaspricecfg.go bobanetwork/v3-erigon/eth/gasprice/gaspricecfg/gaspricecfg.go index af364b0a220c96d625ae3395b2e3fcccc85a941e..0242e9155851ebee47547f2ea77272a3594837db 100644 --- ledgerwatch/erigon/eth/gasprice/gaspricecfg/gaspricecfg.go +++ bobanetwork/v3-erigon/eth/gasprice/gaspricecfg/gaspricecfg.go @@ -10,6 +10,8 @@ var DefaultIgnorePrice = big.NewInt(2 * params.Wei)   var ( DefaultMaxPrice = big.NewInt(500 * params.GWei) + + DefaultMinSuggestedPriorityFee = big.NewInt(1e6 * params.Wei) // 0.001 gwei, for Optimism fee suggestion )   type Config struct { @@ -20,4 +22,6 @@ MaxBlockHistory int Default *big.Int `toml:",omitempty"` MaxPrice *big.Int `toml:",omitempty"` IgnorePrice *big.Int `toml:",omitempty"` + + MinSuggestedPriorityFee *big.Int `toml:",omitempty"` // for Optimism fee suggestion }
diff --git ledgerwatch/erigon/eth/gasprice/optimism-gasprice.go bobanetwork/v3-erigon/eth/gasprice/optimism-gasprice.go new file mode 100644 index 0000000000000000000000000000000000000000..0bcbb9e48c952210f42895c4d9d792a9a8efc187 --- /dev/null +++ bobanetwork/v3-erigon/eth/gasprice/optimism-gasprice.go @@ -0,0 +1,112 @@ +package gasprice + +import ( + "context" + "math/big" + "sort" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/log/v3" +) + +// SuggestOptimismPriorityFee returns a max priority fee value that can be used such that newly +// created transactions have a very high chance to be included in the following blocks, using a +// simplified and more predictable algorithm appropriate for chains like Optimism with a single +// known block builder. +// +// In the typical case, which results whenever the last block had room for more transactions, this +// function returns a minimum suggested priority fee value. Otherwise it returns the higher of this +// minimum suggestion or 10% over the median effective priority fee from the last block. +// +// Rationale: For a chain such as Optimism where there is a single block builder whose behavior is +// known, we know priority fee (as long as it is non-zero) has no impact on the probability for tx +// inclusion as long as there is capacity for it in the block. In this case then, there's no reason +// to return any value higher than some fixed minimum. Blocks typically reach capacity only under +// extreme events such as airdrops, meaning predicting whether the next block is going to be at +// capacity is difficult *except* in the case where we're already experiencing the increased demand +// from such an event. We therefore expect whether the last known block is at capacity to be one of +// the best predictors of whether the next block is likely to be at capacity. (An even better +// predictor is to look at the state of the transaction pool, but we want an algorithm that works +// even if the txpool is private or unavailable.) +// +// In the event the next block may be at capacity, the algorithm should allow for average fees to +// rise in order to reach a market price that appropriately reflects demand. We accomplish this by +// returning a suggestion that is a significant amount (10%) higher than the median effective +// priority fee from the previous block. +func (oracle *Oracle) SuggestOptimismPriorityFee(ctx context.Context, h *types.Header, headHash common.Hash) *big.Int { + suggestion := new(big.Int).Set(oracle.minSuggestedPriorityFee) + + // find the maximum gas used by any of the transactions in the block to use as the capacity + // margin + block, err := oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(h.Number.Int64())) + if err != nil { + log.Error("failed to get block", "err", err) + return suggestion + } + receipts, err := oracle.backend.GetReceipts(ctx, block) + if receipts == nil || err != nil { + log.Error("failed to get block receipts", "err", err) + return suggestion + } + var maxTxGasUsed uint64 + for i := range receipts { + gu := receipts[i].GasUsed + if gu > maxTxGasUsed { + maxTxGasUsed = gu + } + } + // sanity check the max gas used value + if maxTxGasUsed > h.GasLimit { + log.Error("found tx consuming more gas than the block limit", "gas", maxTxGasUsed) + return suggestion + } + + if h.GasUsed+maxTxGasUsed > h.GasLimit { + // A block is "at capacity" if, when it is built, there is a pending tx in the txpool that + // could not be included because the block's gas limit would be exceeded. Since we don't + // have access to the txpool, we instead adopt the following heuristic: consider a block as + // at capacity if the total gas consumed by its transactions is within max-tx-gas-used of + // the block limit, where max-tx-gas-used is the most gas used by any one transaction + // within the block. This heuristic is almost perfectly accurate when transactions always + // consume the same amount of gas, but becomes less accurate as tx gas consumption begins + // to vary. The typical error is we assume a block is at capacity when it was not because + // max-tx-gas-used will in most cases over-estimate the "capacity margin". But it's better + // to err on the side of returning a higher-than-needed suggestion than a lower-than-needed + // one in order to satisfy our desire for high chance of inclusion and rising fees under + // high demand. + block, err := oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(h.Number.Int64())) + if block == nil || err != nil { + log.Error("failed to get last block", "err", err) + return suggestion + } + baseFee := block.BaseFee() + txs := block.Transactions() + if len(txs) == 0 { + log.Error("block was at capacity but doesn't have transactions") + return suggestion + } + tips := bigIntArray(make([]*big.Int, len(txs))) + for i := range txs { + tips[i] = txs[i].GetEffectiveGasTip(uint256.MustFromBig(baseFee)).ToBig() + } + sort.Sort(tips) + median := tips[len(tips)/2] + newSuggestion := new(big.Int).Add(median, new(big.Int).Div(median, big.NewInt(10))) + // use the new suggestion only if it's bigger than the minimum + if newSuggestion.Cmp(suggestion) > 0 { + suggestion = newSuggestion + } + } + + // the suggestion should be capped by oracle.maxPrice + if suggestion.Cmp(oracle.maxPrice) > 0 { + suggestion.Set(oracle.maxPrice) + } + + oracle.cache.SetLatest(headHash, suggestion) + + return new(big.Int).Set(suggestion) +}
diff --git ledgerwatch/erigon/eth/gasprice/optimism-gasprice_test.go bobanetwork/v3-erigon/eth/gasprice/optimism-gasprice_test.go new file mode 100644 index 0000000000000000000000000000000000000000..fac5a1b321023794a0f2ba4fbd16b1b081885459 --- /dev/null +++ bobanetwork/v3-erigon/eth/gasprice/optimism-gasprice_test.go @@ -0,0 +1,157 @@ +// Copyright 2020 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package gasprice + +import ( + "context" + "math/big" + "testing" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/chain" + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/crypto" + "github.com/ledgerwatch/erigon/eth/gasprice/gaspricecfg" + "github.com/ledgerwatch/erigon/event" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/erigon/rpc" +) + +const ( + blockGasLimit = params.TxGas * 3 +) + +type testTxData struct { + priorityFee int64 + gasLimit uint64 +} + +type testCache struct { + latestHash libcommon.Hash + latestPrice *big.Int +} + +// GetLatest implements Cache. +func (c *testCache) GetLatest() (libcommon.Hash, *big.Int) { + return c.latestHash, c.latestPrice +} + +// SetLatest implements Cache. +func (c *testCache) SetLatest(hash libcommon.Hash, price *big.Int) { + c.latestHash = hash + c.latestPrice = price +} + +type opTestBackend struct { + block *types.Block + receipts []*types.Receipt +} + +func (b *opTestBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { + panic("not implemented") +} + +func (b *opTestBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { + return b.block, nil +} + +func (b *opTestBackend) GetReceipts(ctx context.Context, block *types.Block) (types.Receipts, error) { + return b.receipts, nil +} + +func (b *opTestBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { + panic("not implemented") +} + +func (b *opTestBackend) ChainConfig() *chain.Config { + return params.OptimismTestConfig +} + +func (b *opTestBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { + return nil +} + +func newOpTestBackend(t *testing.T, txs []testTxData) *opTestBackend { + var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + signer = types.LatestSigner(params.TestChainConfig) + ) + // only the most recent block is considered for optimism priority fee suggestions, so this is + // where we add the test transactions + ts := []types.Transaction{} + rs := []*types.Receipt{} + header := types.Header{} + header.GasLimit = blockGasLimit + var nonce uint64 + for _, tx := range txs { + txdata := &types.DynamicFeeTransaction{ + ChainID: uint256.MustFromBig(params.TestChainConfig.ChainID), + FeeCap: uint256.MustFromBig(big.NewInt(100 * params.GWei)), + Tip: uint256.MustFromBig(big.NewInt(tx.priorityFee)), + CommonTx: types.CommonTx{}, + } + t := types.MustSignNewTx(key, *signer, txdata) + ts = append(ts, t) + r := types.Receipt{} + r.GasUsed = tx.gasLimit + header.GasUsed += r.GasUsed + rs = append(rs, &r) + nonce++ + } + // hasher := trie.NewStackTrie(nil) + b := types.NewBlock(&header, ts, nil, nil, nil) + return &opTestBackend{block: b, receipts: rs} +} + +func TestSuggestOptimismPriorityFee(t *testing.T) { + minSuggestion := new(big.Int).SetUint64(1e8 * params.Wei) + var cases = []struct { + txdata []testTxData + want *big.Int + }{ + { + // block well under capacity, expect min priority fee suggestion + txdata: []testTxData{{params.GWei, 21000}}, + want: minSuggestion, + }, + { + // 2 txs, still under capacity, expect min priority fee suggestion + txdata: []testTxData{{params.GWei, 21000}, {params.GWei, 21000}}, + want: minSuggestion, + }, + { + // 2 txs w same priority fee (1 gwei), but second tx puts it right over capacity + txdata: []testTxData{{params.GWei, 21000}, {params.GWei, 21001}}, + want: big.NewInt(1100000000), // 10 percent over 1 gwei, the median + }, + { + // 3 txs, full block. return 10% over the median tx (10 gwei * 10% == 11 gwei) + txdata: []testTxData{{10 * params.GWei, 21000}, {1 * params.GWei, 21000}, {100 * params.GWei, 21000}}, + want: big.NewInt(11 * params.GWei), + }, + } + for i, c := range cases { + backend := newOpTestBackend(t, c.txdata) + oracle := NewOracle(backend, gaspricecfg.Config{MinSuggestedPriorityFee: minSuggestion}, &testCache{}) + got := oracle.SuggestOptimismPriorityFee(context.Background(), backend.block.Header(), backend.block.Hash()) + if got.Cmp(c.want) != 0 { + t.Errorf("Gas price mismatch for test case %d: want %d, got %d", i, c.want, got) + } + } +}
diff --git ledgerwatch/erigon/eth/protocols/eth/handler_test.go bobanetwork/v3-erigon/eth/protocols/eth/handler_test.go index a373858c043ce660b9cecb9847adff9793120759..0bb92a1c621b74d75891430c379c007abf968817 100644 --- ledgerwatch/erigon/eth/protocols/eth/handler_test.go +++ bobanetwork/v3-erigon/eth/protocols/eth/handler_test.go @@ -97,7 +97,7 @@ require.NoError(t, err)   hashes = append(hashes, block.Hash()) // If known, encode and queue for response packet - r := rawdb.ReadReceipts(tx, block, nil) + r := rawdb.ReadReceipts(params.TestChainConfig, tx, block, nil) encoded, err := rlp.EncodeToBytes(r) require.NoError(t, err) receipts = append(receipts, encoded)
diff --git ledgerwatch/erigon/eth/protocols/eth/handlers.go bobanetwork/v3-erigon/eth/protocols/eth/handlers.go index 774092027e1edaa56a748185d1a7739ca0c4410b..60e23cede61649f458178c5cdac5b049c128e237 100644 --- ledgerwatch/erigon/eth/protocols/eth/handlers.go +++ bobanetwork/v3-erigon/eth/protocols/eth/handlers.go @@ -20,6 +20,7 @@ import ( "context" "fmt"   + "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/log/v3" @@ -157,7 +158,7 @@ } return bodies }   -func AnswerGetReceiptsQuery(br services.FullBlockReader, db kv.Tx, query GetReceiptsPacket) ([]rlp.RawValue, error) { //nolint:unparam +func AnswerGetReceiptsQuery(chainConfig *chain.Config, br services.FullBlockReader, db kv.Tx, query GetReceiptsPacket) ([]rlp.RawValue, error) { //nolint:unparam // Gather state data until the fetch or network limits is reached var ( bytes int @@ -180,7 +181,7 @@ } if b == nil { return nil, nil } - results := rawdb.ReadReceipts(db, b, s) + results := rawdb.ReadReceipts(chainConfig, db, b, s) if results == nil { header, err := rawdb.ReadHeaderByHash(db, hash) if err != nil {
diff --git ledgerwatch/erigon/eth/stagedsync/stage_finish.go bobanetwork/v3-erigon/eth/stagedsync/stage_finish.go index 9a96e47f0e0351998107453d996bcc1616ecde43..f0c618091c1dfb6c4300b09f4fef9675662b2ea1 100644 --- ledgerwatch/erigon/eth/stagedsync/stage_finish.go +++ bobanetwork/v3-erigon/eth/stagedsync/stage_finish.go @@ -54,9 +54,6 @@ var err error if executionAt, err = s.ExecutionAt(tx); err != nil { return err } - if s.BlockNumber > executionAt { // Erigon will self-heal (download missed blocks) eventually - return nil - } if executionAt <= s.BlockNumber { return nil }
diff --git ledgerwatch/erigon/eth/stagedsync/stage_headers.go bobanetwork/v3-erigon/eth/stagedsync/stage_headers.go index 6ac18f587ab614983e31f9b3579dc0abd9a3ac4c..8a36be2f64ab3990f9f26a42380525eb27c01ecf 100644 --- ledgerwatch/erigon/eth/stagedsync/stage_headers.go +++ bobanetwork/v3-erigon/eth/stagedsync/stage_headers.go @@ -118,7 +118,6 @@ } }   return HeadersPOW(s, u, ctx, tx, cfg, initialCycle, test, useExternalTx, logger) - }   // HeadersPOW progresses Headers stage for Proof-of-Work headers
diff --git ledgerwatch/erigon/go.mod bobanetwork/v3-erigon/go.mod index 4aaa1848490da6413de3bf60c4aef20a936db098..5de87b5ebc89d303b974d8c19b197c77ed265821 100644 --- ledgerwatch/erigon/go.mod +++ bobanetwork/v3-erigon/go.mod @@ -1,6 +1,6 @@ module github.com/ledgerwatch/erigon   -go 1.20 +go 1.21   require ( github.com/erigontech/mdbx-go v0.27.21 @@ -8,8 +8,6 @@ github.com/erigontech/silkworm-go v0.10.0 github.com/ledgerwatch/log/v3 v3.9.0 github.com/ledgerwatch/secp256k1 v1.0.0 ) - -replace github.com/ledgerwatch/erigon-lib => ./erigon-lib   require ( gfx.cafe/util/go/generic v0.0.0-20230721185457-c559e86c829c @@ -23,7 +21,7 @@ github.com/anacrolix/log v0.14.3-0.20230823030427-4b296d71a6b4 github.com/anacrolix/sync v0.4.0 github.com/anacrolix/torrent v1.52.6-0.20231201115409-7ea994b6bbd8 github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b - github.com/btcsuite/btcd/btcec/v2 v2.1.3 + github.com/btcsuite/btcd/btcec/v2 v2.2.0 github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b github.com/consensys/gnark-crypto v0.12.1 github.com/crate-crypto/go-ipa v0.0.0-20221111143132-9aa5d42120bc @@ -35,6 +33,7 @@ github.com/docker/docker v1.6.2 github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf github.com/edsrzf/mmap-go v1.1.0 github.com/emicklei/dot v1.6.0 + github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240201223137-d57c2429e4fc github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c github.com/gballet/go-verkle v0.0.0-20221121182333-31427a1f2d35 github.com/gfx-labs/sse v0.0.0-20231226060816-f747e26a9baa @@ -82,15 +81,15 @@ github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.4 github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e github.com/tidwall/btree v1.6.0 - github.com/ugorji/go/codec v1.1.13 - github.com/ugorji/go/codec/codecgen v1.1.13 + github.com/ugorji/go/codec v1.2.12 + github.com/ugorji/go/codec/codecgen v1.2.12 github.com/urfave/cli/v2 v2.27.1 github.com/valyala/fastjson v1.6.4 github.com/vektah/gqlparser/v2 v2.5.10 github.com/xsleonard/go-merkle v1.1.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.17.0 - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 + golang.org/x/crypto v0.18.0 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/net v0.19.0 golang.org/x/sync v0.6.0 golang.org/x/sys v0.16.0 @@ -151,7 +150,6 @@ github.com/benbjohnson/immutable v0.4.1-0.20221220213129-8932b999621d // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.7.0 // indirect github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cilium/ebpf v0.9.1 // indirect github.com/consensys/bavard v0.1.13 // indirect @@ -193,6 +191,7 @@ github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/ledgerwatch/erigon-snapshot v1.3.1-0.20240115083615-b5feeb63e191 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect @@ -299,4 +298,8 @@ rsc.io/tmplfunc v0.0.3 // indirect zombiezen.com/go/sqlite v0.13.1 // indirect )   +replace github.com/ledgerwatch/erigon-lib => ./erigon-lib + replace github.com/tendermint/tendermint => github.com/bnb-chain/tendermint v0.31.12 + +replace github.com/ethereum-optimism/superchain-registry/superchain => github.com/bobanetwork/superchain-registry/superchain v0.0.0-20240223212802-3cf921f7ab5c
diff --git ledgerwatch/erigon/p2p/sentry/sentry_multi_client/sentry_multi_client.go bobanetwork/v3-erigon/p2p/sentry/sentry_multi_client/sentry_multi_client.go index a95d68af7948d85cbd4d9b9e99f48c85d1084d11..3762538dd73e881f0189fe712962f40f3a073058 100644 --- ledgerwatch/erigon/p2p/sentry/sentry_multi_client/sentry_multi_client.go +++ bobanetwork/v3-erigon/p2p/sentry/sentry_multi_client/sentry_multi_client.go @@ -668,7 +668,7 @@ if err != nil { return err } defer tx.Rollback() - receipts, err := eth.AnswerGetReceiptsQuery(cs.blockReader, tx, query.GetReceiptsPacket) + receipts, err := eth.AnswerGetReceiptsQuery(cs.ChainConfig, cs.blockReader, tx, query.GetReceiptsPacket) if err != nil { return err }
diff --git ledgerwatch/erigon/p2p/sentry/simulator/simulator_test.go bobanetwork/v3-erigon/p2p/sentry/simulator/simulator_test.go index 3821bb88bf73035ef8ad462ba45dcf185d45fd2b..f94815e44e790c1415f1d5c5229509d3cc1ab4ea 100644 --- ledgerwatch/erigon/p2p/sentry/simulator/simulator_test.go +++ bobanetwork/v3-erigon/p2p/sentry/simulator/simulator_test.go @@ -7,16 +7,18 @@ "bytes" "context" "testing"   + "github.com/ledgerwatch/log/v3" + "github.com/ledgerwatch/erigon-lib/direct" "github.com/ledgerwatch/erigon-lib/gointerfaces/sentry" sentry_if "github.com/ledgerwatch/erigon-lib/gointerfaces/sentry" "github.com/ledgerwatch/erigon/eth/protocols/eth" "github.com/ledgerwatch/erigon/p2p/sentry/simulator" "github.com/ledgerwatch/erigon/rlp" - "github.com/ledgerwatch/log/v3" )   func TestSimulatorStart(t *testing.T) { + t.Skip("For now, this test is intended for manual runs only as it downloads snapshots and takes too long")   ctx, cancel := context.WithCancel(context.Background())
diff --git ledgerwatch/erigon/params/config_test.go bobanetwork/v3-erigon/params/config_test.go index c5463a12fb247d15be1dcf5cf3b47e81265d89bd..3840b00c9fe5fcc6ba9aa0b25b881f22b1047b8d 100644 --- ledgerwatch/erigon/params/config_test.go +++ bobanetwork/v3-erigon/params/config_test.go @@ -17,6 +17,7 @@ package params   import ( + "math" "math/big" "reflect" "testing" @@ -103,6 +104,25 @@ } } }   +func TestConfigRulesRegolith(t *testing.T) { + c := &chain.Config{ + RegolithTime: big.NewInt(500), + Optimism: &chain.OptimismConfig{}, + } + var stamp uint64 + if r := c.Rules(0, stamp); r.IsOptimismRegolith { + t.Errorf("expected %v to not be regolith", stamp) + } + stamp = 500 + if r := c.Rules(0, stamp); !r.IsOptimismRegolith { + t.Errorf("expected %v to be regolith", stamp) + } + stamp = math.MaxInt64 + if r := c.Rules(0, stamp); !r.IsOptimismRegolith { + t.Errorf("expected %v to be regolith", stamp) + } +} + func TestGetBurntContract(t *testing.T) { // Ethereum assert.Nil(t, MainnetChainConfig.GetBurntContract(0)) @@ -138,3 +158,30 @@ addr = AmoyChainConfig.GetBurntContract(0) require.NotNil(t, addr) assert.Equal(t, common.HexToAddress("0x000000000000000000000000000000000000dead"), *addr) } + +// TODO: remove when superchain-registry is integrated +// TestCanyonTimestampOnBlockBoundary asserts that Canyon will activate on a block's timestamp. +// This is critical because the create2Deployer only activates on a block's timestamp. +func TestCanyonTimestampOnBlockBoundary(t *testing.T) { + superchainConfigs := []*chain.Config{} + l2BlockTime := 2 + for _, config := range superchainConfigs { + if config.CanyonTime == nil { + continue + } + regolithTime := 0 + if config.RegolithTime != nil { + regolithTime = int(config.RegolithTime.Int64()) + } + canyonTime := int(config.CanyonTime.Int64()) + if regolithTime > canyonTime { + t.Fatalf("Canyon time on superchain %v is less then Regolith time. canyon time: %v, regolith time: %v", + config.ChainName, canyonTime, regolithTime) + } + canyonOffset := canyonTime - regolithTime + if canyonOffset%l2BlockTime != 0 { + t.Fatalf("Canyon time on superchain %v is not on the block time. canyon time: %v, regolith time: %v, block time: %v", + config.ChainName, canyonTime, regolithTime, l2BlockTime) + } + } +}
diff --git ledgerwatch/erigon/params/superchain.go bobanetwork/v3-erigon/params/superchain.go new file mode 100644 index 0000000000000000000000000000000000000000..39b192fe0ffdaa29b92635734281fe2cd77260a3 --- /dev/null +++ bobanetwork/v3-erigon/params/superchain.go @@ -0,0 +1,198 @@ +package params + +import ( + "bytes" + "math/big" + "strings" + + "github.com/ethereum-optimism/superchain-registry/superchain" + "github.com/ledgerwatch/erigon-lib/chain" + "github.com/ledgerwatch/erigon-lib/chain/networkname" + "github.com/ledgerwatch/erigon-lib/common" +) + +const ( + OPMainnetChainID = 10 + OPGoerliChainID = 420 + OPSepoliaChainID = 11155420 + BaseMainnetChainID = 8453 + BaseGoerliChainID = 84531 + baseSepoliaChainID = 84532 + baseGoerliDevnetChainID = 11763071 + pgnSepoliaChainID = 58008 + devnetChainID = 997 + chaosnetChainID = 888 + BobaSepoliaChainID = 28882 +) + +// OP Stack chain config +var ( + // March 17, 2023 @ 7:00:00 pm UTC + OptimismGoerliRegolithTime = big.NewInt(1679079600) + // May 4, 2023 @ 5:00:00 pm UTC + BaseGoerliRegolithTime = big.NewInt(1683219600) + // Apr 21, 2023 @ 6:30:00 pm UTC + baseGoerliDevnetRegolithTime = big.NewInt(1682101800) + // March 5, 2023 @ 2:48:00 am UTC + devnetRegolithTime = big.NewInt(1677984480) + // August 16, 2023 @ 3:34:22 am UTC + chaosnetRegolithTime = big.NewInt(1692156862) + // January 18, 2024 @ 5:59:48 pm UTC + BobaSepoliaRegolithTime = big.NewInt(1705600788) +) + +// OPStackChainConfigByName loads chain config corresponding to the chain name from superchain registry. +// This implementation is based on optimism monorepo(https://github.com/ethereum-optimism/optimism/blob/op-node/v1.4.1/op-node/chaincfg/chains.go#L59) +func OPStackChainConfigByName(name string) *superchain.ChainConfig { + // Handle legacy name aliases + name = networkname.HandleLegacyName(name) + // Handle Boba superchain name + name = networkname.HandleBobaSuperchainName(name) + for _, chainCfg := range superchain.OPChains { + if strings.EqualFold(chainCfg.Chain+"-"+chainCfg.Superchain, name) { + return chainCfg + } + } + return nil +} + +// OPStackChainConfigByGenesisHash loads chain config corresponding to the genesis hash from superchain registry. +func OPStackChainConfigByGenesisHash(genesisHash common.Hash) *superchain.ChainConfig { + if bytes.Equal(genesisHash.Bytes(), OPMainnetGenesisHash.Bytes()) { + return superchain.OPChains[OPMainnetChainID] + } else if bytes.Equal(genesisHash.Bytes(), OPSepoliaGenesisHash.Bytes()) { + return superchain.OPChains[OPSepoliaChainID] + } else if bytes.Equal(genesisHash.Bytes(), BobaSepoliaGenesisHash.Bytes()) { + return superchain.OPChains[BobaSepoliaChainID] + } + for _, chainCfg := range superchain.OPChains { + if bytes.Equal(chainCfg.Genesis.L2.Hash[:], genesisHash.Bytes()) { + return chainCfg + } + } + return nil +} + +// ChainConfigByOpStackChainName loads chain config corresponding to the chain name from superchain registry, and builds erigon chain config. +func ChainConfigByOpStackChainName(name string) *chain.Config { + opStackChainCfg := OPStackChainConfigByName(name) + if opStackChainCfg == nil { + return nil + } + return LoadSuperChainConfig(opStackChainCfg) +} + +// ChainConfigByOpStackGenesisHash loads chain config corresponding to the genesis hash from superchain registry, and builds erigon chain config. +func ChainConfigByOpStackGenesisHash(genesisHash common.Hash) *chain.Config { + opStackChainCfg := OPStackChainConfigByGenesisHash(genesisHash) + if opStackChainCfg == nil { + return nil + } + return LoadSuperChainConfig(opStackChainCfg) +} + +// LoadSuperChainConfig loads superchain config from superchain registry for given chain, and builds erigon chain config. +// This implementation is based on op-geth(https://github.com/ethereum-optimism/op-geth/blob/c7871bc4454ffc924eb128fa492975b30c9c46ad/params/superchain.go#L39) +func LoadSuperChainConfig(opStackChainCfg *superchain.ChainConfig) *chain.Config { + superchainConfig, ok := superchain.Superchains[opStackChainCfg.Superchain] + if !ok { + panic("unknown superchain: " + opStackChainCfg.Superchain) + } + out := &chain.Config{ + ChainName: opStackChainCfg.Name, + ChainID: new(big.Int).SetUint64(opStackChainCfg.ChainID), + HomesteadBlock: common.Big0, + DAOForkBlock: nil, + TangerineWhistleBlock: common.Big0, + SpuriousDragonBlock: common.Big0, + ByzantiumBlock: common.Big0, + ConstantinopleBlock: common.Big0, + PetersburgBlock: common.Big0, + IstanbulBlock: common.Big0, + MuirGlacierBlock: common.Big0, + BerlinBlock: common.Big0, + LondonBlock: common.Big0, + ArrowGlacierBlock: common.Big0, + GrayGlacierBlock: common.Big0, + MergeNetsplitBlock: common.Big0, + ShanghaiTime: nil, + CancunTime: nil, + PragueTime: nil, + BedrockBlock: common.Big0, + RegolithTime: big.NewInt(0), + CanyonTime: nil, + EcotoneTime: nil, + TerminalTotalDifficulty: common.Big0, + TerminalTotalDifficultyPassed: true, + Ethash: nil, + Clique: nil, + Optimism: &chain.OptimismConfig{ + EIP1559Elasticity: 6, + EIP1559Denominator: 50, + EIP1559DenominatorCanyon: 250, + }, + } + + if superchainConfig.Config.CanyonTime != nil { + out.ShanghaiTime = new(big.Int).SetUint64(*superchainConfig.Config.CanyonTime) // Shanghai activates with Canyon + out.CanyonTime = new(big.Int).SetUint64(*superchainConfig.Config.CanyonTime) + } + if superchainConfig.Config.EcotoneTime != nil { + out.CancunTime = new(big.Int).SetUint64(*superchainConfig.Config.EcotoneTime) // CancunTime activates with Ecotone + out.EcotoneTime = new(big.Int).SetUint64(*superchainConfig.Config.EcotoneTime) + } + + // note: no actual parameters are being loaded, yet. + // Future superchain upgrades are loaded from the superchain chConfig and applied to the geth ChainConfig here. + _ = superchainConfig.Config + + // special overrides for OP-Stack chains with pre-Regolith upgrade history + switch opStackChainCfg.ChainID { + case OPGoerliChainID: + out.LondonBlock = big.NewInt(4061224) + out.ArrowGlacierBlock = big.NewInt(4061224) + out.GrayGlacierBlock = big.NewInt(4061224) + out.MergeNetsplitBlock = big.NewInt(4061224) + out.BedrockBlock = big.NewInt(4061224) + out.RegolithTime = OptimismGoerliRegolithTime + out.Optimism.EIP1559Elasticity = 10 + case OPMainnetChainID: + out.BerlinBlock = big.NewInt(3950000) + out.LondonBlock = big.NewInt(105235063) + out.ArrowGlacierBlock = big.NewInt(105235063) + out.GrayGlacierBlock = big.NewInt(105235063) + out.MergeNetsplitBlock = big.NewInt(105235063) + out.BedrockBlock = big.NewInt(105235063) + case BaseGoerliChainID: + out.RegolithTime = BaseGoerliRegolithTime + out.Optimism.EIP1559Elasticity = 10 + case baseSepoliaChainID: + out.Optimism.EIP1559Elasticity = 10 + case baseGoerliDevnetChainID: + out.RegolithTime = baseGoerliDevnetRegolithTime + case pgnSepoliaChainID: + out.Optimism.EIP1559Elasticity = 2 + out.Optimism.EIP1559Denominator = 8 + case devnetChainID: + out.RegolithTime = devnetRegolithTime + out.Optimism.EIP1559Elasticity = 10 + case chaosnetChainID: + out.RegolithTime = chaosnetRegolithTime + out.Optimism.EIP1559Elasticity = 10 + case BobaSepoliaChainID: + out.BerlinBlock = big.NewInt(511) + out.LondonBlock = big.NewInt(511) + out.ArrowGlacierBlock = big.NewInt(511) + out.GrayGlacierBlock = big.NewInt(511) + out.MergeNetsplitBlock = big.NewInt(511) + out.BedrockBlock = big.NewInt(511) + out.RegolithTime = BobaSepoliaRegolithTime + out.ShanghaiTime = BobaSepoliaRegolithTime + out.CanyonTime = BobaSepoliaRegolithTime + out.Optimism.EIP1559Elasticity = 6 + out.Optimism.EIP1559Denominator = 50 + out.Optimism.EIP1559DenominatorCanyon = 250 + } + + return out +}
diff --git ledgerwatch/erigon/rlp/decode.go bobanetwork/v3-erigon/rlp/decode.go index 4824946e558c80c983f8932ac533c5d6284bfdec..cc83d3024d503cb9d2ff418453c9b715ea58c761 100644 --- ledgerwatch/erigon/rlp/decode.go +++ bobanetwork/v3-erigon/rlp/decode.go @@ -31,6 +31,7 @@ "github.com/ledgerwatch/log/v3"   "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/common/hexutil" )   //lint:ignore ST1012 EOL is not an error. @@ -201,6 +202,8 @@ case typ.AssignableTo(reflect.PtrTo(uint256Int)): return decodeUint256, nil case typ.AssignableTo(uint256Int): return decodeUint256NoPtr, nil + case typ == reflect.TypeOf(hexutil.Big{}): + return decodeHexBigNoPtr, nil case kind == reflect.Ptr: return makePtrDecoder(typ, tags) case reflect.PtrTo(typ).Implements(decoderInterface): @@ -261,6 +264,16 @@ }   func decodeBigIntNoPtr(s *Stream, val reflect.Value) error { return decodeBigInt(s, val.Addr()) +} + +func decodeHexBigNoPtr(s *Stream, val reflect.Value) error { + var bi big.Int + err := decodeBigInt(s, reflect.ValueOf(&bi)) + if err == nil { + hb := val.Addr().Interface().(*hexutil.Big) + *hb = (hexutil.Big)(bi) + } + return err }   func decodeBigInt(s *Stream, val reflect.Value) error {
diff --git ledgerwatch/erigon/rlp/encode.go bobanetwork/v3-erigon/rlp/encode.go index f43b71670d8bc5a1340ad494f9a5d71e69c33335..67f9d0ed8aab5c3eab768d47e23beef9087dc9f9 100644 --- ledgerwatch/erigon/rlp/encode.go +++ bobanetwork/v3-erigon/rlp/encode.go @@ -26,6 +26,7 @@ "reflect" "sync"   "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/common/hexutil"   libcommon "github.com/ledgerwatch/erigon-lib/common" ) @@ -366,6 +367,8 @@ case typ.AssignableTo(reflect.PtrTo(uint256Int)): return writeUint256Ptr, nil case typ.AssignableTo(uint256Int): return writeUint256NoPtr, nil + case typ == reflect.TypeOf(hexutil.Big{}): + return writeHexBigNoPtr, nil case kind == reflect.Ptr: return makePtrWriter(typ, ts) case reflect.PtrTo(typ).Implements(encoderInterface): @@ -422,6 +425,12 @@ func writeBigIntNoPtr(val reflect.Value, w *encbuf) error { i := val.Interface().(big.Int) return writeBigInt(&i, w) +} + +func writeHexBigNoPtr(val reflect.Value, w *encbuf) error { + bi := val.Interface().(hexutil.Big) + i := bi.ToInt() + return writeBigInt(i, w) }   // wordBytes is the number of bytes in a big.Word
diff --git ledgerwatch/erigon/tests/erigon-ext-test/go.mod.template bobanetwork/v3-erigon/tests/erigon-ext-test/go.mod.template index 515b3b1428115a8adc528ac9d13abbd489614785..5e56bf3d7611715705230e6e95e6bb2f2eea8f4e 100644 --- ledgerwatch/erigon/tests/erigon-ext-test/go.mod.template +++ bobanetwork/v3-erigon/tests/erigon-ext-test/go.mod.template @@ -2,8 +2,10 @@ module example.com/erigon-ext-test   go 1.20   -require github.com/ledgerwatch/erigon $COMMIT_SHA +require github.com/ledgerwatch/erigon devel   -replace github.com/ledgerwatch/erigon-lib => github.com/ledgerwatch/erigon/erigon-lib $COMMIT_SHA +replace github.com/ledgerwatch/erigon => github.com/bobanetwork/v3-erigon $COMMIT_SHA + +replace github.com/ledgerwatch/erigon-lib => github.com/bobanetwork/v3-erigon/erigon-lib $COMMIT_SHA   require github.com/ethereum/go-ethereum v1.13.3
diff --git ledgerwatch/erigon/tests/state_test_util.go bobanetwork/v3-erigon/tests/state_test_util.go index 32cf2e639ecc85d7f480c8d96c678f2eb35fa892..4100ae186639188f9565fab138700b4c939efc86 100644 --- ledgerwatch/erigon/tests/state_test_util.go +++ bobanetwork/v3-erigon/tests/state_test_util.go @@ -33,6 +33,7 @@ libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/hexutility" "github.com/ledgerwatch/erigon-lib/common/length" "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/opstack" types2 "github.com/ledgerwatch/erigon-lib/types"   "github.com/ledgerwatch/erigon/common" @@ -235,6 +236,7 @@ // Prepare the EVM. txContext := core.NewEVMTxContext(msg) header := block.Header() context := core.NewEVMBlockContext(header, core.GetHashFn(header, nil), nil, &t.json.Env.Coinbase) + context.L1CostFunc = opstack.NewL1CostFunc(config, statedb) context.GetHash = vmTestBlockHash if baseFee != nil { context.BaseFee = new(uint256.Int)
diff --git ledgerwatch/erigon/turbo/adapter/ethapi/get_proof.go bobanetwork/v3-erigon/turbo/adapter/ethapi/get_proof.go index ddeda5bd466a26e164cb6854ec7abfbfcdfda160..c3b47a8c8949956498e84af46da68f35333e0748 100644 --- ledgerwatch/erigon/turbo/adapter/ethapi/get_proof.go +++ bobanetwork/v3-erigon/turbo/adapter/ethapi/get_proof.go @@ -2,7 +2,6 @@ package ethapi   import ( "bytes" - "github.com/ledgerwatch/erigon-lib/common/hexutil"   libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/length" @@ -11,6 +10,7 @@ "github.com/ledgerwatch/erigon/core/types/accounts" "github.com/ledgerwatch/erigon/turbo/trie" )   +/* // Result structs for GetProof type AccountResult struct { Address libcommon.Address `json:"address"` @@ -21,12 +21,13 @@ Nonce hexutil.Uint64 `json:"nonce"` StorageHash libcommon.Hash `json:"storageHash"` StorageProof []StorageResult `json:"storageProof"` } + type StorageResult struct { Key string `json:"key"` Value *hexutil.Big `json:"value"` Proof []string `json:"proof"` } - +*/ /*TODO: to support proofs func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address libcommon.Address, storageKeys []string, blockNr rpc.BlockNumber) (*AccountResult, error) { block := uint64(blockNr.Int64()) + 1
diff --git ledgerwatch/erigon/turbo/cli/flags.go bobanetwork/v3-erigon/turbo/cli/flags.go index 88ab5ca946ab37b4cbbea1d9e468d7a12b370812..083fc8ee272723cc5d03a643b07148f2f960b79b 100644 --- ledgerwatch/erigon/turbo/cli/flags.go +++ bobanetwork/v3-erigon/turbo/cli/flags.go @@ -473,6 +473,10 @@ OtsMaxPageSize: ctx.Uint64(utils.OtsSearchMaxCapFlag.Name),   TxPoolApiAddr: ctx.String(utils.TxpoolApiAddrFlag.Name),   + RollupSequencerHTTP: ctx.String(utils.RollupSequencerHTTPFlag.Name), + RollupHistoricalRPC: ctx.String(utils.RollupHistoricalRPCFlag.Name), + RollupHistoricalRPCTimeout: ctx.Duration(utils.RollupHistoricalRPCTimeoutFlag.Name), + StateCache: kvcache.DefaultCoherentConfig, RPCSlowLogThreshold: ctx.Duration(utils.RPCSlowFlag.Name), }
diff --git ledgerwatch/erigon/turbo/jsonrpc/debug_api.go bobanetwork/v3-erigon/turbo/jsonrpc/debug_api.go index 81aab4fc903f2b950cb49ba88c7ddf9666082646..5be670aca0376c40ba510e9a32b498144e341f2c 100644 --- ledgerwatch/erigon/turbo/jsonrpc/debug_api.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/debug_api.go @@ -60,6 +60,10 @@ GasCap: gascap, } }   +func (api *PrivateDebugAPIImpl) relayToHistoricalBackend(ctx context.Context, result interface{}, method string, args ...interface{}) error { + return api.historicalRPCService.CallContext(ctx, result, method, args...) +} + // storageRangeAt implements debug_storageRangeAt. Returns information about a range of storage locations (if any) for the given address. func (api *PrivateDebugAPIImpl) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex uint64, contractAddress common.Address, keyStart hexutility.Bytes, maxResult int) (StorageRangeResult, error) { tx, err := api.db.BeginRo(ctx)
diff --git ledgerwatch/erigon/turbo/jsonrpc/debug_api_test.go bobanetwork/v3-erigon/turbo/jsonrpc/debug_api_test.go index a67440281bf699512a5d1772c93cd1cb6dd89012..c16f1769cda27ac5cd291809ad47d13c7ed232b4 100644 --- ledgerwatch/erigon/turbo/jsonrpc/debug_api_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/debug_api_test.go @@ -51,7 +51,7 @@ func TestTraceBlockByNumber(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - baseApi := NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + baseApi := NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) ethApi := NewEthAPI(baseApi, m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) api := NewPrivateDebugAPI(baseApi, m.DB, 0) for _, tt := range debugTraceTransactionTests {
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_api_test.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_api_test.go index 78e398da7f1a46f3d21a114b1f23c469e5e8a7ba..79014212945a43bd86d8e87349558d6ec05f1369 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_api_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_api_test.go @@ -2,17 +2,22 @@ package jsonrpc   import ( "context" + "encoding/json" "fmt" + "math/big" "testing"   + libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/common/hexutil"   "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/common" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require"   "github.com/ledgerwatch/erigon-lib/kv/kvcache" "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/rpc" "github.com/ledgerwatch/erigon/rpc/rpccfg" "github.com/ledgerwatch/erigon/turbo/adapter/ethapi" @@ -25,7 +30,7 @@ func newBaseApiForTest(m *mock.MockSentry) *BaseAPI { agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - return NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + return NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) }   func TestGetBalanceChangesInBlock(t *testing.T) { @@ -55,7 +60,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) db := m.DB agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), db, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + api := NewEthAPI(NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), db, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) // Call GetTransactionReceipt for transaction which is not in the database if _, err := api.GetTransactionReceipt(context.Background(), common.Hash{}); err != nil { t.Errorf("calling GetTransactionReceipt with empty hash: %v", err) @@ -235,3 +240,168 @@ } else { t.Error("error expected") } } + +func TestNewRPCTransactionDepositTx(t *testing.T) { + tx := &types.DepositTx{ + SourceHash: common.Hash{1}, + From: common.Address{1}, + IsSystemTransaction: true, + Mint: uint256.NewInt(34), + Value: uint256.NewInt(1337), + } + nonce := uint64(12) + depositNonce := &nonce + receipt := &types.Receipt{DepositNonce: depositNonce} + got := NewRPCTransaction(tx, common.Hash{}, uint64(12), uint64(1), big.NewInt(0), receipt) + // Should provide zero values for unused fields that are required in other transactions + require.Equal(t, got.GasPrice, (*hexutil.Big)(big.NewInt(0)), "NewRPCTransaction().GasPrice = %v, want 0x0", got.GasPrice) + require.Equal(t, got.V, (*hexutil.Big)(big.NewInt(0)), "NewRPCTransaction().V = %v, want 0x0", got.V) + require.Equal(t, got.R, (*hexutil.Big)(big.NewInt(0)), "NewRPCTransaction().R = %v, want 0x0", got.R) + require.Equal(t, got.S, (*hexutil.Big)(big.NewInt(0)), "NewRPCTransaction().S = %v, want 0x0", got.S) + + // Should include deposit tx specific fields + require.Equal(t, got.SourceHash, &tx.SourceHash, "NewRPCTransaction().SourceHash = %v, want %v", got.SourceHash, tx.SourceHash) + require.Equal(t, got.IsSystemTx, &tx.IsSystemTransaction, "NewRPCTransaction().IsSystemTx = %v, want %v", got.IsSystemTx, tx.IsSystemTransaction) + require.Equal(t, got.Mint, (*hexutil.Big)(tx.Mint.ToBig()), "NewRPCTransaction().Mint = %v, want %v", got.Mint, tx.Mint.ToBig()) + require.Equal(t, got.Nonce, (hexutil.Uint64)(nonce), "NewRPCTransaction().Nonce = %v, want %v", got.Nonce, nonce) +} + +func TestNewRPCTransactionDepositTxWithVersion(t *testing.T) { + tx := &types.DepositTx{ + SourceHash: common.Hash{1}, + From: common.Address{1}, + IsSystemTransaction: true, + Mint: uint256.NewInt(34), + Value: uint256.NewInt(1337), + } + nonce := uint64(7) + version := types.CanyonDepositReceiptVersion + receipt := &types.Receipt{ + DepositNonce: &nonce, + DepositReceiptVersion: &version, + } + got := NewRPCTransaction(tx, libcommon.Hash{}, uint64(12), uint64(1), big.NewInt(0), receipt) + // Should provide zero values for unused fields that are required in other transactions + require.Equal(t, got.GasPrice, (*hexutil.Big)(big.NewInt(0)), "NewRPCTransaction().GasPrice = %v, want 0x0", got.GasPrice) + require.Equal(t, got.V, (*hexutil.Big)(big.NewInt(0)), "NewRPCTransaction().V = %v, want 0x0", got.V) + require.Equal(t, got.R, (*hexutil.Big)(big.NewInt(0)), "NewRPCTransaction().R = %v, want 0x0", got.R) + require.Equal(t, got.S, (*hexutil.Big)(big.NewInt(0)), "NewRPCTransaction().S = %v, want 0x0", got.S) + + // Should include versioned deposit tx specific fields + require.Equal(t, got.SourceHash, &tx.SourceHash, "NewRPCTransaction().SourceHash = %v, want %v", got.SourceHash, tx.SourceHash) + require.Equal(t, got.IsSystemTx, &tx.IsSystemTransaction, "NewRPCTransaction().IsSystemTx = %v, want %v", got.IsSystemTx, tx.IsSystemTransaction) + require.Equal(t, got.Mint, (*hexutil.Big)(tx.Mint.ToBig()), "NewRPCTransaction().Mint = %v, want %v", got.Mint, tx.Mint.ToBig()) + require.Equal(t, got.Nonce, (hexutil.Uint64)(nonce), "NewRPCTransaction().Nonce = %v, want %v", got.Nonce, nonce) + require.Equal(t, *got.DepositReceiptVersion, (hexutil.Uint64(version)), "NewRPCTransaction().DepositReceiptVersion = %v, want %v", *got.DepositReceiptVersion, version) + + // Make sure json marshal/unmarshal of the rpc tx preserves the receipt version + b, err := json.Marshal(got) + require.NoError(t, err, "marshalling failed: %w", err) + parsed := make(map[string]interface{}) + err = json.Unmarshal(b, &parsed) + require.NoError(t, err, "unmarshalling failed: %w", err) + require.Equal(t, "0x1", parsed["depositReceiptVersion"]) +} + +func TestNewRPCTransactionOmitIsSystemTxFalse(t *testing.T) { + tx := &types.DepositTx{ + IsSystemTransaction: false, + From: common.Address{1}, + Value: uint256.NewInt(1337), + } + got := NewRPCTransaction(tx, common.Hash{}, uint64(12), uint64(1), big.NewInt(0), nil) + + require.Nil(t, got.IsSystemTx, "should omit IsSystemTx when false") +} + +func TestUnmarshalRpcDepositTx(t *testing.T) { + version := hexutil.Uint64(types.CanyonDepositReceiptVersion) + tests := []struct { + name string + modifier func(tx *RPCTransaction) + valid bool + }{ + { + name: "Unmodified", + modifier: func(tx *RPCTransaction) {}, + valid: true, + }, + { + name: "Zero Values", + modifier: func(tx *RPCTransaction) { + tx.V = (*hexutil.Big)(common.Big0) + tx.R = (*hexutil.Big)(common.Big0) + tx.S = (*hexutil.Big)(common.Big0) + tx.GasPrice = (*hexutil.Big)(common.Big0) + }, + valid: true, + }, + { + name: "Nil Values", + modifier: func(tx *RPCTransaction) { + tx.V = nil + tx.R = nil + tx.S = nil + tx.GasPrice = nil + }, + valid: true, + }, + { + name: "Non-Zero GasPrice", + modifier: func(tx *RPCTransaction) { + tx.GasPrice = (*hexutil.Big)(big.NewInt(43)) + }, + valid: false, + }, + { + name: "Non-Zero V", + modifier: func(tx *RPCTransaction) { + tx.V = (*hexutil.Big)(big.NewInt(43)) + }, + valid: false, + }, + { + name: "Non-Zero R", + modifier: func(tx *RPCTransaction) { + tx.R = (*hexutil.Big)(big.NewInt(43)) + }, + valid: false, + }, + { + name: "Non-Zero S", + modifier: func(tx *RPCTransaction) { + tx.S = (*hexutil.Big)(big.NewInt(43)) + }, + valid: false, + }, + { + name: "Non-nil deposit receipt version", + modifier: func(tx *RPCTransaction) { + tx.DepositReceiptVersion = &version + }, + valid: true, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + tx := &types.DepositTx{ + SourceHash: common.Hash{1}, + From: common.Address{1}, + IsSystemTransaction: true, + Mint: uint256.NewInt(34), + Value: uint256.NewInt(1337), + } + rpcTx := NewRPCTransaction(tx, common.Hash{}, uint64(12), uint64(1), big.NewInt(0), nil) + test.modifier(rpcTx) + json, err := json.Marshal(rpcTx) + require.NoError(t, err, "marshalling failed: %w", err) + parsed := &types.DepositTx{} + err = parsed.UnmarshalJSON(json) + if test.valid { + require.NoError(t, err, "unmarshal failed: %w", err) + } else { + require.Error(t, err, "unmarshal should have failed but did not") + } + }) + } +}
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_block_test.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_block_test.go index b7a5d9af9a10414e2dbd9129a0a768f599aa1551..2d2794504f14d4a935d28da78183a8dc37250204 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_block_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_block_test.go @@ -87,7 +87,7 @@ ff.HandlePendingBlock(&txpool.OnPendingBlockReply{ RplBlock: rlpBlock, })   - api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) b, err := api.GetBlockByNumber(context.Background(), rpc.PendingBlockNumber, false) if err != nil { t.Errorf("error getting block number with pending tag: %s", err)
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_callMany.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_callMany.go index df7bfd9e377e4cffc73e30ca942e3f4bca437c61..f70f66443a0a1375e98f7b8fe0dd723d676f30e7 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_callMany.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_callMany.go @@ -4,9 +4,11 @@ import ( "context" "encoding/hex" "fmt" - "github.com/ledgerwatch/erigon-lib/common/hexutil" "math/big" "time" + + "github.com/ledgerwatch/erigon-lib/common/hexutil" + "github.com/ledgerwatch/erigon-lib/opstack"   "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/common" @@ -170,6 +172,7 @@ Difficulty: new(big.Int).Set(parent.Difficulty), GasLimit: parent.GasLimit, BaseFee: &baseFee, } + blockCtx.L1CostFunc = opstack.NewL1CostFunc(chainConfig, st)   // Get a new instance of the EVM evm = vm.NewEVM(blockCtx, txCtx, st, chainConfig, vm.Config{Debug: false})
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_callMany_test.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_callMany_test.go index e876589494c8713174a1260d0ccbe43a8794735b..d4b875f2b68d61dca755e6307dd8e38aa35d4eae 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_callMany_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_callMany_test.go @@ -85,7 +85,7 @@ db := contractBackend.DB() engine := contractBackend.Engine() api := NewEthAPI(NewBaseApi(nil, stateCache, contractBackend.BlockReader(), contractBackend.Agg(), false, rpccfg.DefaultEvmCallTimeout, engine, - datadir.New(t.TempDir())), db, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + datadir.New(t.TempDir()), nil, nil), db, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New())   callArgAddr1 := ethapi.CallArgs{From: &address, To: &tokenAddr, Nonce: &nonce, MaxPriorityFeePerGas: (*hexutil.Big)(big.NewInt(1e9)),
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_filters_test.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_filters_test.go index b7db654f31e39ee8a7af8da494cabc77e98af909..cac2551db12147809935a367935fa333641449e6 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_filters_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_filters_test.go @@ -30,7 +30,7 @@ stateCache := kvcache.New(kvcache.DefaultCoherentConfig) ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, mock.Mock(t)) mining := txpool.NewMiningClient(conn) ff := rpchelper.New(ctx, nil, nil, mining, func() {}, m.Log) - api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New()) + api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000, false, 100_000, log.New())   ptf, err := api.NewPendingTransactionFilter(ctx) assert.Nil(err)
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_mining_test.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_mining_test.go index 752b44db4fbb7fad24b7a629f1ad181d7b739ff7..7d98f7cf44ad4380fed3d39ba40e12470650e66c 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_mining_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_mining_test.go @@ -27,7 +27,7 @@ ff := rpchelper.New(ctx, nil, nil, mining, func() {}, m.Log) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) engine := ethash.NewFaker() api := NewEthAPI(NewBaseApi(ff, stateCache, m.BlockReader, nil, false, rpccfg.DefaultEvmCallTimeout, engine, - m.Dirs), nil, nil, nil, mining, 5000000, 100_000, false, 100_000, log.New()) + m.Dirs, nil, nil), nil, nil, nil, mining, 5000000, 100_000, false, 100_000, log.New()) expect := uint64(12345) b, err := rlp.EncodeToBytes(types.NewBlockWithHeader(&types.Header{Number: big.NewInt(int64(expect))})) require.NoError(t, err)
diff --git ledgerwatch/erigon/turbo/jsonrpc/eth_system.go bobanetwork/v3-erigon/turbo/jsonrpc/eth_system.go index 470b7159341df7137c0625b4648568d5c84f4602..f7777feff921ba0c35a7860dfb9b2bde20e093c8 100644 --- ledgerwatch/erigon/turbo/jsonrpc/eth_system.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/eth_system.go @@ -221,7 +221,7 @@ func (b *GasPriceOracleBackend) ChainConfig() *chain.Config { return b.cc } func (b *GasPriceOracleBackend) GetReceipts(ctx context.Context, block *types.Block) (types.Receipts, error) { - return rawdb.ReadReceipts(b.tx, block, nil), nil + return rawdb.ReadReceipts(b.cc, b.tx, block, nil), nil } func (b *GasPriceOracleBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { return nil, nil
diff --git ledgerwatch/erigon/turbo/jsonrpc/gen_traces_test.go bobanetwork/v3-erigon/turbo/jsonrpc/gen_traces_test.go index a5f4c7bdc7ae5a921532bd14594676ae8e4ad272..98c63dfaf00a05464bb7856cff2014f1594da54c 100644 --- ledgerwatch/erigon/turbo/jsonrpc/gen_traces_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/gen_traces_test.go @@ -30,7 +30,7 @@ func TestGeneratedDebugApi(t *testing.T) { m := rpcdaemontest.CreateTestSentryForTraces(t) agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - baseApi := NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + baseApi := NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) api := NewPrivateDebugAPI(baseApi, m.DB, 0) var buf bytes.Buffer stream := jsoniter.NewStream(jsoniter.ConfigDefault, &buf, 4096) @@ -118,7 +118,7 @@ func TestGeneratedTraceApi(t *testing.T) { m := rpcdaemontest.CreateTestSentryForTraces(t) agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - baseApi := NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + baseApi := NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) api := NewTraceAPI(baseApi, m.DB, &httpcfg.HttpCfg{}) traces, err := api.Block(context.Background(), rpc.BlockNumber(1), new(bool)) if err != nil { @@ -329,7 +329,7 @@ "transactionHash": "0xb2b9fa4c999c1c8370ce1fbd1c4315a9ce7f8421fe2ebed8a9051ff2e4e7e3da", "transactionPosition": 2, "type": "create" } -] +] ` var expected interface{} if err = json.Unmarshal([]byte(expectedJSON), &expected); err != nil {
diff --git ledgerwatch/erigon/turbo/jsonrpc/graphql_api.go bobanetwork/v3-erigon/turbo/jsonrpc/graphql_api.go index b32406e9f82374e6fa1912680ad1db309b9493fd..49585a68478ab73ac7cac474fba0ca392e065818 100644 --- ledgerwatch/erigon/turbo/jsonrpc/graphql_api.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/graphql_api.go @@ -3,8 +3,9 @@ import ( "context" "fmt" + "math/big" + "github.com/ledgerwatch/erigon-lib/common/hexutil" - "math/big"   "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" @@ -116,7 +117,8 @@ if err != nil { return nil, err } additionalFields := make(map[string]interface{}) - response, err := ethapi.RPCMarshalBlock(b, inclTx, inclTx, additionalFields) + receipts := rawdb.ReadRawReceipts(tx, uint64(number.Int64())) + response, err := ethapi.RPCMarshalBlock(b, inclTx, inclTx, additionalFields, receipts) if !inclTx { delete(response, "transactions") // workaround for https://github.com/ledgerwatch/erigon/issues/4989#issuecomment-1218415666 }
diff --git ledgerwatch/erigon/turbo/jsonrpc/otterscan_transaction_by_sender_and_nonce_test.go bobanetwork/v3-erigon/turbo/jsonrpc/otterscan_transaction_by_sender_and_nonce_test.go index 9e72d5d0275d98245f542ad9f4497b8d5b954437..e2f510841ed07e353cb07775e50534360b429b6c 100644 --- ledgerwatch/erigon/turbo/jsonrpc/otterscan_transaction_by_sender_and_nonce_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/otterscan_transaction_by_sender_and_nonce_test.go @@ -12,7 +12,7 @@ func TestGetTransactionBySenderAndNonce(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() - api := NewOtterscanAPI(NewBaseApi(nil, nil, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, 25) + api := NewOtterscanAPI(NewBaseApi(nil, nil, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, 25)   addr := common.HexToAddress("0x537e697c7ab75a26f9ecf0ce810e3154dfcaaf44") expectCreator := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")
diff --git ledgerwatch/erigon/turbo/jsonrpc/parity_api_test.go bobanetwork/v3-erigon/turbo/jsonrpc/parity_api_test.go index 8a3f14780c14487eb001b444338cdab2c7424777..43fc430b041061a2f859447432d31ecf7860b5e0 100644 --- ledgerwatch/erigon/turbo/jsonrpc/parity_api_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/parity_api_test.go @@ -22,7 +22,7 @@ func TestParityAPIImpl_ListStorageKeys_NoOffset(t *testing.T) { assert := assert.New(t) m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() - baseApi := NewBaseApi(nil, nil, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + baseApi := NewBaseApi(nil, nil, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) api := NewParityAPIImpl(baseApi, m.DB) answers := []string{ "0000000000000000000000000000000000000000000000000000000000000000",
diff --git ledgerwatch/erigon/turbo/jsonrpc/send_transaction_test.go bobanetwork/v3-erigon/turbo/jsonrpc/send_transaction_test.go index b0e1f736ae6fcc6e1a56f8ae4e05f393d3ff4e78..6f0cb860a471f1a74e1e2c7eb27e1565b3bdae05 100644 --- ledgerwatch/erigon/turbo/jsonrpc/send_transaction_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/send_transaction_test.go @@ -37,7 +37,7 @@ func newBaseApiForTest(m *mock.MockSentry) *jsonrpc.BaseAPI { agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - return jsonrpc.NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + return jsonrpc.NewBaseApi(nil, stateCache, m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) }   // Do 1 step to start txPool
diff --git ledgerwatch/erigon/turbo/jsonrpc/txpool_api_test.go bobanetwork/v3-erigon/turbo/jsonrpc/txpool_api_test.go index 205a7d724084eb59e1ab75c32dcb4e3c71ccfd03..09f7816932bdac229ad580c49c032111e23f4dfd 100644 --- ledgerwatch/erigon/turbo/jsonrpc/txpool_api_test.go +++ bobanetwork/v3-erigon/turbo/jsonrpc/txpool_api_test.go @@ -35,7 +35,7 @@ ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, m) txPool := txpool.NewTxpoolClient(conn) ff := rpchelper.New(ctx, nil, txPool, txpool.NewMiningClient(conn), func() {}, m.Log) agg := m.HistoryV3Components() - api := NewTxPoolAPI(NewBaseApi(ff, kvcache.New(kvcache.DefaultCoherentConfig), m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, txPool) + api := NewTxPoolAPI(NewBaseApi(ff, kvcache.New(kvcache.DefaultCoherentConfig), m.BlockReader, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, txPool)   expectValue := uint64(1234) txn, err := types.SignTx(types.NewTransaction(0, libcommon.Address{1}, uint256.NewInt(expectValue), params.TxGas, uint256.NewInt(10*params.GWei), nil), *types.LatestSignerForChainID(m.ChainConfig.ChainID), m.Key)
diff --git ledgerwatch/erigon/turbo/node/node.go bobanetwork/v3-erigon/turbo/node/node.go index 6bb3e38c5a49926a56ca5c835c33fdbcd7e43873..b20a21a314fa31264f243ec7944b7c110467678a 100644 --- ledgerwatch/erigon/turbo/node/node.go +++ bobanetwork/v3-erigon/turbo/node/node.go @@ -89,7 +89,7 @@ if !ctx.IsSet(utils.NetworkIdFlag.Name) { logger.Info("Starting Erigon on Ethereum mainnet...") } default: - logger.Info("Starting Erigon on", "devnet", chain) + logger.Info("Starting Erigon on", "chain", chain) }   nodeConfig := NewNodeConfig()
diff --git ledgerwatch/erigon/turbo/stages/blockchain_test.go bobanetwork/v3-erigon/turbo/stages/blockchain_test.go index 3b20f792c1e6ad393600eb3b6d250d62afe14169..c09fd913c0037f91024d31123784654752902c72 100644 --- ledgerwatch/erigon/turbo/stages/blockchain_test.go +++ bobanetwork/v3-erigon/turbo/stages/blockchain_test.go @@ -25,6 +25,7 @@ "math" "math/big" "testing"   + "github.com/ledgerwatch/erigon-lib/chain" "github.com/ledgerwatch/erigon-lib/common/hexutil"   "github.com/holiman/uint256" @@ -496,7 +497,7 @@ for i, txn := range txs { if bn, _ := rawdb.ReadTxLookupEntry(tx, txn.Hash()); bn != nil { t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn) } - if rcpt, _, _, _, _ := readReceipt(tx, txn.Hash(), m.BlockReader); rcpt != nil { + if rcpt, _, _, _, _ := readReceipt(m.ChainConfig, tx, txn.Hash(), m.BlockReader); rcpt != nil { t.Errorf("drop %d: receipt %v found while shouldn't have been", i, rcpt) } } @@ -511,7 +512,7 @@ if m.HistoryV3 { // m.HistoryV3 doesn't store } else { - if rcpt, _, _, _, _ := readReceipt(tx, txn.Hash(), m.BlockReader); rcpt == nil { + if rcpt, _, _, _, _ := readReceipt(m.ChainConfig, tx, txn.Hash(), m.BlockReader); rcpt == nil { t.Errorf("add %d: expected receipt to be found", i) } } @@ -525,14 +526,14 @@ } if m.HistoryV3 { // m.HistoryV3 doesn't store } else { - if rcpt, _, _, _, _ := readReceipt(tx, txn.Hash(), m.BlockReader); rcpt == nil { + if rcpt, _, _, _, _ := readReceipt(m.ChainConfig, tx, txn.Hash(), m.BlockReader); rcpt == nil { t.Errorf("share %d: expected receipt to be found", i) } } } }   -func readReceipt(db kv.Tx, txHash libcommon.Hash, br services.FullBlockReader) (*types.Receipt, libcommon.Hash, uint64, uint64, error) { +func readReceipt(chainConfig *chain.Config, db kv.Tx, txHash libcommon.Hash, br services.FullBlockReader) (*types.Receipt, libcommon.Hash, uint64, uint64, error) { // Retrieve the context of the receipt based on the transaction hash blockNumber, err := rawdb.ReadTxLookupEntry(db, txHash) if err != nil { @@ -553,7 +554,7 @@ if err != nil { return nil, libcommon.Hash{}, 0, 0, err } // Read all the receipts from the block and return the one with the matching hash - receipts := rawdb.ReadReceipts(db, b, senders) + receipts := rawdb.ReadReceipts(chainConfig, db, b, senders) for receiptIndex, receipt := range receipts { if receipt.TxHash == txHash { return receipt, blockHash, *blockNumber, uint64(receiptIndex), nil
diff --git ledgerwatch/erigon/turbo/stages/stageloop.go bobanetwork/v3-erigon/turbo/stages/stageloop.go index 35aab454bcda05cca52fe8f7a0e03b0be3fa9b61..1fe6d0df13bc63e7a3f91243356b025a650db068 100644 --- ledgerwatch/erigon/turbo/stages/stageloop.go +++ bobanetwork/v3-erigon/turbo/stages/stageloop.go @@ -316,7 +316,7 @@ } } if notifications != nil && notifications.Accumulator != nil && currentHeader != nil {   - pendingBaseFee := misc.CalcBaseFee(h.chainConfig, currentHeader) + pendingBaseFee := misc.CalcBaseFee(h.chainConfig, currentHeader, 0) if currentHeader.Number.Uint64() == 0 { notifications.Accumulator.StartChange(0, currentHeader.Hash(), nil, false) }
diff --git ledgerwatch/erigon/.circleci/ci-docker-tag-op-erigon-release.sh bobanetwork/v3-erigon/.circleci/ci-docker-tag-op-erigon-release.sh new file mode 100755 index 0000000000000000000000000000000000000000..fac3d6d7f08db5e928583ef461175ec9b5023409 --- /dev/null +++ bobanetwork/v3-erigon/.circleci/ci-docker-tag-op-erigon-release.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +set -euo pipefail + +DOCKER_REPO=$1 +GIT_TAG=$2 +GIT_SHA=$3 + +IMAGE_NAME="op-erigon" +IMAGE_TAG=$GIT_TAG + +SOURCE_IMAGE_TAG="$DOCKER_REPO/$IMAGE_NAME:$GIT_SHA" +TARGET_IMAGE_TAG="$DOCKER_REPO/$IMAGE_NAME:$IMAGE_TAG" +TARGET_IMAGE_TAG_LATEST="$DOCKER_REPO/$IMAGE_NAME:latest" + +echo "Checking if docker images exist for '$IMAGE_NAME'" +echo "" +tags=$(gcloud container images list-tags "$DOCKER_REPO/$IMAGE_NAME" --limit 1 --format json) +if [ "$tags" = "[]" ]; then + echo "No existing docker images were found for '$IMAGE_NAME'. The code tagged with '$GIT_TAG' may not have an associated dockerfile or docker build job." + echo "If this service has a dockerfile, add a docker-publish job for it in the circleci config." + echo "" + echo "Exiting" + exit 0 +fi + +echo "Tagging $SOURCE_IMAGE_TAG with '$IMAGE_TAG'" +gcloud container images add-tag -q "$SOURCE_IMAGE_TAG" "$TARGET_IMAGE_TAG" + +# Do not tag with latest if the release is a release candidate. +if [[ "$IMAGE_TAG" == *"rc"* ]]; then + echo "Not tagging with 'latest' because the release is a release candidate." + exit 0 +fi + +echo "Tagging $SOURCE_IMAGE_TAG with 'latest'" +gcloud container images add-tag -q "$SOURCE_IMAGE_TAG" "$TARGET_IMAGE_TAG_LATEST"
diff --git ledgerwatch/erigon/.circleci/config.yml bobanetwork/v3-erigon/.circleci/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..2e6a3337ccbbf2c7369ba006a08e6f6223af56ed --- /dev/null +++ bobanetwork/v3-erigon/.circleci/config.yml @@ -0,0 +1,214 @@ +version: 2.1 + +orbs: + gcp-cli: circleci/gcp-cli@3.0.1 + slack: circleci/slack@4.10.1 + +commands: + gcp-oidc-authenticate: + description: "Authenticate with GCP using a CircleCI OIDC token." + parameters: + project_number: + type: env_var_name + default: GCP_PROJECT_NUMBER + workload_identity_pool_id: + type: env_var_name + default: GCP_WIP_ID + workload_identity_pool_provider_id: + type: env_var_name + default: GCP_WIP_PROVIDER_ID + service_account_email: + type: env_var_name + default: GCP_SERVICE_ACCOUNT_EMAIL + gcp_cred_config_file_path: + type: string + default: /home/circleci/gcp_cred_config.json + oidc_token_file_path: + type: string + default: /home/circleci/oidc_token.json + steps: + - run: + name: "Create OIDC credential configuration" + command: | + # Store OIDC token in temp file + echo $CIRCLE_OIDC_TOKEN > << parameters.oidc_token_file_path >> + # Create a credential configuration for the generated OIDC ID Token + gcloud iam workload-identity-pools create-cred-config \ + "projects/${<< parameters.project_number >>}/locations/global/workloadIdentityPools/${<< parameters.workload_identity_pool_id >>}/providers/${<< parameters.workload_identity_pool_provider_id >>}"\ + --output-file="<< parameters.gcp_cred_config_file_path >>" \ + --service-account="${<< parameters.service_account_email >>}" \ + --credential-source-file=<< parameters.oidc_token_file_path >> + - run: + name: "Authenticate with GCP using OIDC" + command: | + # Configure gcloud to leverage the generated credential configuration + gcloud auth login --brief --cred-file "<< parameters.gcp_cred_config_file_path >>" + # Configure ADC + echo "export GOOGLE_APPLICATION_CREDENTIALS='<< parameters.gcp_cred_config_file_path >>'" | tee -a "$BASH_ENV" + +# our defined job, and its steps +jobs: + docker-release: + environment: + DOCKER_BUILDKIT: 1 + parameters: + project_number: + type: env_var_name + default: GCP_PROJECT_NUMBER + docker_name: + description: Docker image name + type: string + default: "op-erigon" + docker_tags: + description: Docker image tags as csv + type: string + registry: + description: Docker registry + type: string + default: "us-docker.pkg.dev" + repo: + description: Docker repo + type: string + default: "bobanetwork-tools-artifacts/images" + push_tags: + description: Push release push tags + type: boolean + default: false + machine: + image: ubuntu-2204:2022.07.1 + resource_class: xlarge + steps: + - gcp-cli/install + - gcp-oidc-authenticate + - checkout + - run: + name: Configure Docker + command: | + gcloud auth configure-docker <<parameters.registry>> + - run: + name: Build and push + no_output_timeout: 30m + command: | + RAW_TAGS="<<parameters.docker_tags>>" + if [ "$CIRCLE_BRANCH" = "optimism" ]; then + RAW_TAGS="$RAW_TAGS,optimism" + fi + IMAGE_BASE="<<parameters.registry>>/${GCP_PROJECT_ID}/<<parameters.repo>>/<<parameters.docker_name>>" + DOCKER_TAGS=$(echo -ne "$RAW_TAGS" | sed "s/,/\n/g" | sed "s/[^a-zA-Z0-9\n.]/-/g" | sed -e "s|^|-t ${IMAGE_BASE}:|") + docker context create buildx-build + docker buildx create --use buildx-build + docker buildx build --push \ + $(echo -ne $DOCKER_TAGS | tr '\n' ' ') \ + --platform=linux/arm64,linux/amd64 \ + --build-arg VERSION=$CIRCLE_TAG \ + --build-arg COMMIT=$CIRCLE_SHA \ + --build-arg BUILDNUM=$CIRCLE_BUILD_NUM \ + --progress plain \ + -f Dockerfile . + - when: + condition: + equal: [ true, <<parameters.push_tags>> ] + steps: + - run: + name: Tag + command: | + ./.circleci/ci-docker-tag-op-erigon-release.sh <<parameters.registry>>/${GCP_PROJECT_ID}/<<parameters.repo>> $CIRCLE_TAG $CIRCLE_SHA1 + v3-achorage-checkout: + machine: + image: ubuntu-2204:2022.07.1 + resource_class: medium + steps: + #modifying the usual checkout step so that we can clone two projects into a directory ~/project/<> + - run: git clone -b "$CIRCLE_BRANCH" "$CIRCLE_REPOSITORY_URL" v3-erigon/ + - run: git clone https://github.com/bobanetwork/v3-anchorage v3-anchorage/ + - run: git -C v3-anchorage rev-parse HEAD + - persist_to_workspace: + root: "." + paths: + - "v3-erigon/" + - "v3-anchorage/" + go-e2e-test: + parameters: + module: + description: Go Module Name + type: string + target: + description: The make target to execute + type: string + docker: + - image: us-docker.pkg.dev/${GCP_PROJECT_ID}/${GCP_ARTIFACT_REPOSITORY}/images/ci-builder:v1.2.0 + resource_class: xlarge + steps: + - attach_workspace: { at: "." } + - run: + name: Modify target Erigon + command: | + cp ~/project/v3-erigon/go.mod ~/project/v3-anchorage/op-erigon/go.mod + cd ~/project/v3-anchorage/op-erigon + go mod edit -module="github.com/ethereum-optimism/optimism/op-erigon" + go mod edit \ + -replace "github.com/ledgerwatch/erigon=github.com/bobanetwork/v3-erigon@$CIRCLE_SHA1" \ + -replace "github.com/ledgerwatch/erigon-lib=github.com/bobanetwork/v3-erigon/erigon-lib@$CIRCLE_SHA1" + go mod tidy + - run: + name: prep results dir + command: mkdir -p /tmp/test-results + working_directory: ~/project/v3-anchorage + - run: + name: Initial build + command: make + working_directory: ~/project/v3-anchorage + - run: + name: Devnet-allocs + command: make devnet-allocs + working_directory: ~/project/v3-anchorage + - run: + name: Cannon-prestate + command: make cannon-prestate + working_directory: ~/project/v3-anchorage + - run: + name: print go's available MIPS targets + command: go tool dist list | grep mips + working_directory: ~/project/v3-anchorage + - run: + name: run tests + command: + # Note: We don't use circle CI test splits because we need to split by test name, not by package. There is an additional + # constraint that gotestsum does not currently (nor likely will) accept files from different pacakges when building. + JUNIT_FILE=/tmp/test-results/<<parameters.module>>_<<parameters.target>>.xml make <<parameters.target>> + working_directory: ~/project/v3-anchorage/<<parameters.module>> + - store_test_results: + path: /tmp/test-results + +workflows: + release: + jobs: + - hold: + type: approval + filters: + tags: + only: /^v.*/ + branches: + ignore: /.*/ + - docker-release: + name: Push to Docker (release) + filters: + tags: + only: /^v.*/ + branches: + ignore: /.*/ + docker_tags: <<pipeline.git.revision>>,<<pipeline.git.tag>> + push_tags: true + context: + - bobanetwork-gcr-release + requires: + - hold + main: + jobs: + - v3-achorage-checkout + - go-e2e-test: + name: op-e2e-ext-erigon-tests + module: op-e2e + target: test-external-erigon + requires: + - v3-achorage-checkout
diff --git ledgerwatch/erigon/.github/workflows/ci.yml bobanetwork/v3-erigon/.github/workflows/ci.yml index 85bac657092e8fa4064231254b48e429decdf44b..bf973280852a3aff9fe2fb09754fa25d938f6624 100644 --- ledgerwatch/erigon/.github/workflows/ci.yml +++ bobanetwork/v3-erigon/.github/workflows/ci.yml @@ -5,10 +5,12 @@ branches: - devel - alpha - 'release/**' + - boba-develop pull_request: branches: - devel - alpha + - boba-develop - 'release/**' types: - opened
diff --git ledgerwatch/erigon/.github/workflows/release.yml bobanetwork/v3-erigon/.github/workflows/release.yml index 9b61c414e249c6cf1c5e3797b49e40420a4b014c..c4531295ef8e34ece2c70ca0d3841b8ef8b760b3 100644 --- ledgerwatch/erigon/.github/workflows/release.yml +++ bobanetwork/v3-erigon/.github/workflows/release.yml @@ -10,9 +10,9 @@ push: branches-ignore: - '**' tags: - - 'v*.*.*' + #- 'v*.*.*' # to be used by fork patch-releases ^^ - - 'v*.*.*-*' + #- 'v*.*.*-*' workflow_dispatch:   jobs:
diff --git ledgerwatch/erigon/.github/workflows/test-integration.yml bobanetwork/v3-erigon/.github/workflows/test-integration.yml index 40564d2af165410e6beacb249be568f9ebd09bcd..7e4380be4be787d791e2b92a7e1582196acc49b2 100644 --- ledgerwatch/erigon/.github/workflows/test-integration.yml +++ bobanetwork/v3-erigon/.github/workflows/test-integration.yml @@ -5,6 +5,11 @@ branches: - devel - alpha - 'release/**' + - boba-develop + pull_request: + branches: + - boba-develop + - 'release/**' schedule: - cron: '20 16 * * *' # daily at 16:20 UTC workflow_dispatch:
diff --git ledgerwatch/erigon/Dockerfile.debian bobanetwork/v3-erigon/Dockerfile.debian index e3e8c9d5d89cf4d6eac146252922327a14024517..01d38f3d105712816eca3b50469df08e8dc700b7 100644 --- ledgerwatch/erigon/Dockerfile.debian +++ bobanetwork/v3-erigon/Dockerfile.debian @@ -96,10 +96,8 @@ LABEL org.label-schema.build-date=$BUILD_DATE \ org.label-schema.description="Erigon Ethereum Client" \ org.label-schema.name="Erigon" \ org.label-schema.schema-version="1.0" \ - org.label-schema.url="https://torquem.ch" \ org.label-schema.vcs-ref=$VCS_REF \ - org.label-schema.vcs-url="https://github.com/ledgerwatch/erigon.git" \ - org.label-schema.vendor="Torquem" \ + org.label-schema.vcs-url="https://github.com/bobanetwork/v3-erigon.git" \ org.label-schema.version=$VERSION   ENTRYPOINT ["erigon"]
diff --git ledgerwatch/erigon/Makefile bobanetwork/v3-erigon/Makefile index 7ab3fb4248d9761ec3e821694c033c959c08b82c..39cd47ef31a17473966bdbf7ed82a88c176776fe 100644 --- ledgerwatch/erigon/Makefile +++ bobanetwork/v3-erigon/Makefile @@ -11,6 +11,7 @@ # if using volume-mounting data dir, then must exist on host OS DOCKER_UID ?= $(shell id -u) DOCKER_GID ?= $(shell id -g) DOCKER_TAG ?= thorax/erigon:latest +DOCKER_REPO ?= bobanetwork/op-erigon:latest   # Variables below for building on host OS, and are ignored for docker # @@ -82,7 +83,7 @@ --build-arg GID=${DOCKER_GID} \ ${DOCKER_FLAGS} \ .   -xdg_data_home := ~/.local/share +xdg_data_home := ~/.local/share ifdef XDG_DATA_HOME xdg_data_home = $(XDG_DATA_HOME) endif @@ -195,6 +196,9 @@ ## clean: cleans the go cache, build dir, libmdbx db dir clean: go clean -cache rm -fr build/* + +format: + @find ./ -type f -name "*.go" -exec gofmt -w {} \;   # The devtools target installs tools required for 'go generate'. # You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'. @@ -229,7 +233,7 @@ cd $(path) && go test -gcflags "-m -m" -run none -bench=BenchmarkJumpdest* -benchmem -memprofile mem.out   ## git-submodules: update git submodules git-submodules: - @[ -d ".git" ] || (echo "Not a git repository" && exit 1) + @[ -d ".git" ] || [ -f ".gitmodules" ] || (echo "Not a git repository" && exit 1) @echo "Updating git submodules" @# Dockerhub using ./hooks/post-checkout to set submodules, so this line will fail on Dockerhub @# these lines will also fail if ran as root in a non-root user's checked out repository @@ -279,8 +283,8 @@ -w /go/src/$(PACKAGE_NAME) \ ghcr.io/goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \ --clean --skip-validate   - @docker image push --all-tags thorax/erigon - @docker image push --all-tags ghcr.io/ledgerwatch/erigon + @docker image push --all-tags ${DOCKER_REPO} + #@docker image push --all-tags ghcr.io/ledgerwatch/erigon   # since DOCKER_UID, DOCKER_GID are default initialized to the current user uid/gid, # we need separate envvars to facilitate creation of the erigon user on the host OS.
diff --git ledgerwatch/erigon/OP.md bobanetwork/v3-erigon/OP.md new file mode 100644 index 0000000000000000000000000000000000000000..52a707ab6841536dc9c44cc2c61c083084bd6dae --- /dev/null +++ bobanetwork/v3-erigon/OP.md @@ -0,0 +1,120 @@ +# Running an OP Mainnet or Testnet node + +## Non-docker configuration + +Here are instructions if you want to run boba erigon version as the replica node for OP Mainnet or Testnet via binary files. + +### Build erigon + +1. Clone [boba erigon](https://github.com/bobanetwork/v3-erigon) repo + + ```bash + cd ~ + git clone https://github.com/bobanetwork/v3-erigon.git + ``` + +2. Build [boba erigon](https://github.com/bobanetwork/v3-erigon) + + ```bash + cd v3-erigon + make erigon + ``` + +### Build op-node + +1. Clone [boba anchorage](https://github.com/bobanetwork/v3-anchorage) repo + + ```bash + cd ~ + git clone https://github.com/bobanetwork/v3-anchorage.git + ``` + +2. Build [op-node](https://github.com/bobanetwork/v3-anchorage/tree/boba-develop/op-node) + + ```bash + cd v3-anchorage/op-node + make + ``` + +### Get the data dir + +The next step is to download the initial data for `op-erigon`. Thanks for the contribution from [Test in Prod](https://www.testinprod.io). + +1. Download the correct data directory snapshot. + * [OP Mainnet](https://op-erigon-backup.mainnet.testinprod.io) + * [OP Goerli](https://op-erigon-backup.goerli.testinprod.io) + +2. Create the data directory in `op-erigon` and fill it. + + ```bash + mkdir op-erigon + cd ./op-erigon + mkdir erigon + cd ./erigon + tar xvf ~/[DIR]/op-erigon-goerli.tar + ``` + +3. Create a shared secret (JWT token) + + ```bash + cd op-erigon + openssl rand -hex 32 > jwt.txt + ``` + +### Scripts to start the different components + +`op-erigon` + +```bash +cd v3-erigon +./build/bin/erigon \ +--datadir=DATA_DIRECTORY \ +--private.api.addr=localhost:9090 \ +--http.addr=0.0.0.0 \ +--http.port=9545 \ +--http.corsdomain="*" \ +--http.vhosts="*" \ +--authrpc.addr=0.0.0.0 \ +--authrpc.port=8551 \ +--authrpc.vhosts="*" \ +--authrpc.jwtsecret=JWT_TOKEN_PATH \ +--rollup.disabletxpoolgossip=true \ +--chain=optimism-goerli \ +--nodiscover \ +``` + +`op-node` + +```bash +cd v3-anchorage/op-node +./bin/op-node \ +--l1=https://ethereum-goerli.publicnode.com \ +--l2=http://localhost:8551 \ +--l2.jwt-secret=JWT_TOKEN_PATH \ +--network=goerli \ +--rpc.addr=localhost \ +--rpc.port=8547 \ +--l1.http-poll-interval=500ms \ +--l1.trustrpc=true \ +--p2p.disable=true \ +``` + +### The initial synchornization + +During the initial synchonization, you get log messages from `op-node`, and nothing else appears to happen. + +```bash +INFO [08-04|16:36:07.150] Advancing bq origin origin=df76ff..48987e:8301316 originBehind=false +``` + +After a few minutes, `op-node` finds the right batch and then it starts synchronizing. During this synchonization process, you get log messags from `op-node`. + +```bash +INFO [08-04|16:36:01.204] Found next batch epoch=44e203..fef9a5:8301309 batch_epoch=8301309 batch_timestamp=1,673,567,518 +INFO [08-04|16:36:01.205] generated attributes in payload queue txs=2 timestamp=1,673,567,518 +INFO [08-04|16:36:01.265] inserted block hash=ee61ee..256300 number=4,069,725 state_root=a582ae..33a7c5 timestamp=1,673,567,518 parent=5b102e..13196c prev_randao=4758ca..11ff3a fee_recipient=0x4200000000000000000000000000000000000011 txs=2 update_safe=true +``` + +### Note + +It must run `boba-erigon` first and shut it down last. \ No newline at end of file
diff --git ledgerwatch/erigon/fork.yaml bobanetwork/v3-erigon/fork.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b67aa653f19e95609194bc48e22d1bf609c98b43 --- /dev/null +++ bobanetwork/v3-erigon/fork.yaml @@ -0,0 +1,203 @@ +title: "Boba Network op-erigon" # Define the HTML page title +footer: | # define the footer with markdown + Fork-diff overview of [op-erigon](https://github.com/bobanetwork/v3-erigon), a fork of [erigon](https://github.com/ledgerwatch/erigon). and execution-engine of the [OP Stack](https://github.com/ethereum-optimism/optimism) for [Boba Network](https://github.com/bobanetwork/v3-anchorage). +base: + name: ledgerwatch/erigon + url: https://github.com/ledgerwatch/erigon + hash: 3040e2576c29512addaf8ce50528609b4ff9a8e0 +fork: + name: bobanetwork/v3-erigon + url: https://github.com/bobanetwork/v3-erigon + ref: refs/heads/boba-develop +def: + title: "op-erigon" + description: | # description in markdown + This is an overview of the changes in [op-erigon](https://github.com/bobanetwork/v3-erigon), a fork of [erigon](https://github.com/ledgerwatch/erigon), part of the Boba Network OP Stack. + + There is one more fork of erigon dependencies: + + - [op-erigon-interfaces](./erigon-interfaces.html) + sub: + - title: "Core modifications" + sub: + - title: "State-transition modifications" + sub: + - title: "Deposit transaction type" + description: | + The Bedrock upgrade introduces a Deposit transaction-type (0x7E) to enable both users and the rollup system itself to change the L2 state based on L1 events and system rules as [specified](https://github.com/ethereum-optimism/optimism/blob/develop/specs/deposits.md). + globs: + - "core/types/deposit_tx.go" + - "core/types/transaction_marshalling.go" + - "core/types/transaction_signing.go" + - "erigon-lib/types/txn.go" + - "turbo/adapter/ethapi/api_test.go" + - title: "Transaction properties" + description: | + The Transaction type now exposes the deposit-transaction and L1-cost properties required for the rollup. + globs: + - "core/types/access_list_tx.go" + - "core/types/dynamic_fee_tx.go" + - "core/types/legacy_tx.go" + - title: "L1 cost computation" + description: | + Transactions must pay an additional L1 cost based on the amount of rollup-data-gas they consume, estimated based on gas-price-oracle information and encoded tx size. + globs: + - "core/types/rollup_l1_cost.go" + - "core/types/transaction.go" + - "core/vm/evmtypes/evmtypes.go" + - "turbo/jsonrpc/trace_adhoc.go" + - "turbo/jsonrpc/trace_filtering.go" + - "turbo/jsonrpc/tracing.go" + - "turbo/transactions/call.go" + - "turbo/transactions/tracing.go" + - title: "Transaction processing" + description: | + Deposit transactions have special processing rules: gas is pre-paid on L1, and deposits with EVM-failure are included with rolled back changes (except mint). For regular transactions, at the end of the transition, the 1559 burn and L1 cost are routed to vaults. + globs: + - "core/state_transition.go" + - title: "Gaslimit" + description: | + Deposit transactions have special processing rules: gas is pre-paid on L1, and deposits with EVM-failure are included with rolled back changes (except mint). For regular transactions, at the end of the transition, the 1559 burn and L1 cost are routed to vaults. + globs: + - "consensus/misc/eip1559.go" + - title: "Regolith upgrade" + globs: + - "core/state_processor.go" + - "core/error.go" + - title: "Chain config" + description: | + The rollup functionality is enabled with the optimism field in the chain config. The EIP-1559 parameters are configurable to adjust for faster more frequent and smaller blocks. The parameters can be overriden for testing. + globs: + - "params/protocol_params.go" + - "erigon-lib/chain/chain_config.go" + - title: "Engine API modifications" + description: | + The Engine API is extended to insert transactions into the block and optionally exclude the tx-pool, to reproduce the exact block of the sequencer from just the inputs, as derived from L1 by the rollup-node. See [L2 execution engine specs](https://github.com/ethereum-optimism/optimism/blob/develop/specs/exec-engine.md). + globs: + - "turbo/engineapi/engine_server.go" + - "turbo/engineapi/engine_types/jsonrpc.go" + - "ethdb/privateapi/ethbackend.go" + - title: "Block-building modifications" + description: | + The block-building code (in the “mining” stages because of Proof-Of-Work legacy of ethereum) implements the changes to support the transaction-inclusion, tx-pool toggle and gaslimit parameters of the Engine API. + globs: + - "turbo/execution/eth1/block_building.go" + - "turbo/execution/eth1/forkchoice.go" + - "cmd/integration/commands/stages.go" + - "eth/stagedsync/default_stages.go" + - "eth/stagedsync/stage_mining_create_block.go" + - "eth/stagedsync/stage_mining_exec.go" + - "eth/stagedsync/stagebuilder.go" + - "core/block_builder_parameters.go" + - "params/mining.go" + - "core/chain_makers.go" + - title: "Tx-pool tx cost updates" + description: | + Transaction queueing and inclusion needs to account for the L1 cost component. + globs: + - "cmd/txpool/main.go" + + - title: "Node modifications" + description: | + Changes to the node configuration and services. + sub: + - title: "CLI" + sub: + - title: "Flags" + description: | + Flag changes: - Transactions can be forwarded to an RPC for sequencing. - Historical calls can be forwarded to a legacy node. - The tx pool propagation can be enabled/disabled. - The Optimism bedrock fork activation can be changed for testing. + globs: + - "cmd/utils/flags.go" + - "turbo/cli/default_flags.go" + - title: "Versioning" + description: | + List the op-geth and upstream go-ethereum versions. + globs: + - "params/version.go" + - title: "Node config" + globs: + - "eth/ethconfig/config.go" + - title: "Tx gossip disable option" + - title: "Goerli testnet configs" + globs: + - "params/config.go" + - "core/allocs/optimism_goerli.json" + - "params/networkname/network_name.go" + - "params/chainspecs/optimism-goerli.json" + - "core/allocs/optimism-goerli.json" + - title: "Mainnet configs" + globs: + - "params/chainspecs/optimism-mainnet.json" + - title: "User API enhancements" + description: | + Encode the Deposit Tx properties, the L1 costs, and daisy-chain RPC-calls for pre-Bedrock historical data + sub: + - title: "Receipts metadata" + description: | + Pre-Bedrock L1-cost receipt data is loaded from the database if available, and post-Bedrock the L1-cost metadata is hydrated on-the-fly based on the L1 fee information in the corresponding block. + globs: + - "core/types/receipt.go" + - "core/types/receipt_test.go" + - "turbo/jsonrpc/eth_receipts.go" + - "turbo/jsonrpc/eth_receipts_test.go" + - "turbo/jsonrpc/erigon_receipts_test.go" + - "accounts/abi/bind/backends/simulated.go" + - "core/rawdb/accessors_chain.go" + - "core/rawdb/accessors_chain_test.go" + - "core/rawdb/accessors_indexes.go" + - "ethdb/cbor/pool.go" + - title: "API Backend" + description: | + Forward transactions to the sequencer or historical node if configured. + globs: + - "cmd/rpcdaemon/main.go" + - "cmd/rpcdaemon/cli/config.go" + - "cmd/rpcdaemon/cli/httpcfg/http_cfg.go" + - "rpc/rpccfg/rpccfg.go" + - "turbo/jsonrpc/daemon.go" + - "eth/backend.go" + - "turbo/jsonrpc/eth_accounts.go" + - "turbo/jsonrpc/eth_call.go" + - "turbo/jsonrpc/eth_call_test.go" + - "turbo/jsonrpc/send_transaction.go" + - "rpc/errors.go" + - "turbo/jsonrpc/eth_accounts_test.go" + - title: "Transaction & Block response" + description: | + Format deposit and L1-cost data in transaction responses. + globs: + - "turbo/jsonrpc/eth_api.go" + - "turbo/adapter/ethapi/api.go" + - "turbo/adapter/ethapi/internal.go" + - "turbo/jsonrpc/erigon_block.go" + - "turbo/jsonrpc/eth_block.go" + - "turbo/jsonrpc/eth_txs.go" + - "turbo/jsonrpc/eth_uncles.go" + - title: "Otterscan API" + globs: + - "turbo/jsonrpc/otterscan_api.go" + - "turbo/jsonrpc/otterscan_block_details.go" + - "turbo/jsonrpc/otterscan_contract_creator.go" + - "turbo/jsonrpc/otterscan_generic_tracer.go" + - "turbo/jsonrpc/otterscan_search_trace.go" + - title: "Generated files" + globs: + - "core/types/receipt_codecgen_gen.go" + - "core/types/gen_receipt_json.go" + - "erigon-lib/gointerfaces/*/*.pb.go" +# files can be ignored globally, these will be listed in a separate grayed-out section, +# and do not count towards the total line count. +ignore: + - "fork.yaml" + - ".circleci/*" + - "*.sum" + - ".gitignore" + - ".github/**/*" + - "Dockerfile" + - "Dockerfile.debian" + - "docker-compose.yaml" + - "cmd/downloader/recompress.sh" + - "cmd/downloader/torrent_hashes_update.sh" + - "README.md" + - "OP.md" + - "Makefile"
diff --git ledgerwatch/erigon/go.sum bobanetwork/v3-erigon/go.sum index 5484d069ca92288d9b5597991bc90f0b7d335077..fd4392a2637c1b31451c3980e3a5ba4d58a63318 100644 --- ledgerwatch/erigon/go.sum +++ bobanetwork/v3-erigon/go.sum @@ -46,6 +46,7 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= +filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= gfx.cafe/util/go/generic v0.0.0-20230721185457-c559e86c829c h1:alCfDKmPC0EC0KGlZWrNF0hilVWBkzMz+aAYTJ/2hY4= gfx.cafe/util/go/generic v0.0.0-20230721185457-c559e86c829c/go.mod h1:WvSX4JsCRBuIXj0FRBFX9YLg+2SoL3w8Ww19uZO9yNE= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= @@ -75,11 +76,13 @@ github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 h1:byYvvbfSo3+9efR4IeReh77gVs4PnNDR3AMOE9NJ7a0= github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0/go.mod h1:q37NoqncT41qKc048STsifIt69LfUJ8SrWWcz/yam5k= github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0= +github.com/alecthomas/assert/v2 v2.1.0/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA= github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= github.com/alecthomas/atomic v0.1.0-alpha2/go.mod h1:zD6QGEyw49HIq19caJDc2NMXAy8rNi9ROrxtMXATfyI= github.com/alecthomas/kong v0.8.0 h1:ryDCzutfIqJPnNn0omnrgHLbAggDQM2VWHikE1xqK7s= github.com/alecthomas/kong v0.8.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE= +github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -142,6 +145,7 @@ github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96/go.mod h1:Wa6n8cYIdaG35x15aH3Zy6d03f7P728QfdcDeD/IEOs= github.com/anacrolix/utp v0.1.0 h1:FOpQOmIwYsnENnz7tAGohA+r6iXpRjrq8ssKSre2Cp4= github.com/anacrolix/utp v0.1.0/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= @@ -202,13 +206,15 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bobanetwork/superchain-registry/superchain v0.0.0-20240223212802-3cf921f7ab5c h1:IU4ydQNQcDZTms37yPy97jinnOgQ6fTvkd5Dgzz24Dw= +github.com/bobanetwork/superchain-registry/superchain v0.0.0-20240223212802-3cf921f7ab5c/go.mod h1:7xh2awFQqsiZxFrHKTgEd+InVfDRrkKVUIuK8SAFHp0= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8= github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og= -github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE= -github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= +github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= +github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= @@ -260,6 +266,7 @@ github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A= github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= @@ -308,6 +315,7 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= @@ -483,6 +491,7 @@ github.com/hashicorp/golang-lru/arc/v2 v2.0.6/go.mod h1:cfdDIX05DWvYV6/shsxDfa/OVcRieOt+q4FnM8x+Xno= github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM= github.com/hashicorp/golang-lru/v2 v2.0.6/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= @@ -556,7 +565,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758 h1:0D5M2HQSGD3PYPwICLl+/9oulQauOuETfgFvhBDffs0= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/ledgerwatch/erigon-snapshot v1.3.1-0.20240115083615-b5feeb63e191 h1:X/mHEyh0xEuhixj6hKCNQl04NuNDToYWJ08vr66e6L0= @@ -580,6 +590,7 @@ github.com/libp2p/go-libp2p-mplex v0.9.0/go.mod h1:ro1i4kuwiFT+uMPbIDIFkcLs1KRbNp0QwnUXM+P64Og= github.com/libp2p/go-libp2p-pubsub v0.9.3 h1:ihcz9oIBMaCK9kcx+yHWm3mLAFBMAUsM4ux42aikDxo= github.com/libp2p/go-libp2p-pubsub v0.9.3/go.mod h1:RYA7aM9jIic5VV47WXu4GkcRxRhrdElWf8xtyli+Dzc= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= @@ -607,6 +618,7 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= @@ -690,6 +702,7 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= +github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -825,6 +838,7 @@ github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= @@ -902,11 +916,10 @@ github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/ugorji/go v1.1.13/go.mod h1:jxau1n+/wyTGLQoCkjok9r5zFa/FxT6eI5HiHKQszjc= -github.com/ugorji/go/codec v1.1.13 h1:013LbFhocBoIqgHeIHKlV4JWYhqogATYWZhIcH0WHn4= -github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU= -github.com/ugorji/go/codec/codecgen v1.1.13 h1:rGpZ4Q63VcWA3DMBbIHvg+SQweUkfXBBa/f9X0W+tFg= -github.com/ugorji/go/codec/codecgen v1.1.13/go.mod h1:EhCxlc7Crov+HLygD4+hBCitXNrrGKRrRWj+pRsyJGg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec/codecgen v1.2.12 h1:BWbVmWOPwNT9RcRR+WTPYzJeA4WXBSb1O6XJgl4Te0U= +github.com/ugorji/go/codec/codecgen v1.2.12/go.mod h1:JgbiBomDZo5t1eXffkNLgSu+qeuKWCNWxJBvTG4riRI= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= @@ -945,6 +958,7 @@ go.opentelemetry.io/otel/trace v1.8.0 h1:cSy0DF9eGI5WIfNwZ1q2iUyGj00tGzP24dE1lOlHrfY= go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI= go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU= go.uber.org/fx v1.20.0 h1:ZMC/pnRvhsthOZh9MZjMq5U8Or3mA9zBSPaLnzs3ihQ= @@ -952,6 +966,7 @@ go.uber.org/fx v1.20.0/go.mod h1:qCUj0btiR3/JnanEr1TYEePfSw6o/4qYJscgvzQ5Ub0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -980,9 +995,10 @@ golang.org/x/crypto v0.0.0-20220516162934-403b01795ae8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -993,8 +1009,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1023,6 +1039,7 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1080,6 +1097,7 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1107,6 +1125,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1182,6 +1202,7 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= @@ -1192,6 +1213,7 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1204,6 +1226,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1270,6 +1293,7 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1435,7 +1459,9 @@ modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0= modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI= modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v1.29.0 h1:tTFRFq69YKCF2QyGNuRUQxKBm1uZZLubf6Cjh/pVHXs= modernc.org/libc v1.29.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= @@ -1449,9 +1475,11 @@ modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= +modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= +modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE= pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=