op-erigon

+3471
-383

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

There are two more forks 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 testinprod-io/erigon/core/types/deposit_tx.go new file mode 100644 index 0000000000000000000000000000000000000000..1387a819cbd929d8ef16c14625038dbf442ba1a3 --- /dev/null +++ testinprod-io/erigon/core/types/deposit_tx.go @@ -0,0 +1,477 @@ +// 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" + "github.com/ledgerwatch/erigon/common" +) + +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) 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) Size() common.StorageSize { + if size := tx.size.Load(); size != nil { + return size.(common.StorageSize) + } + c := tx.EncodingSize() + tx.size.Store(common.StorageSize(c)) + return common.StorageSize(c) +} + +// 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 += (bits.Len(uint(payloadSize)) + 7) / 8 + } + envelopeSize += 2 + return envelopeSize +} + +// MarshalBinary returns the canonical encoding of the transaction. +// For legacy transactions, it returns the RLP encoding. For EIP-2718 typed +// transactions, it returns the type and payload. +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 +} + +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 +} + +// not sure ab this one lol +func (tx DepositTx) Protected() bool { + return true +} + +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 { + if baseFee == nil { + return tx.GetTip() + } + gasFeeCap := tx.GetFeeCap() + // return 0 because effectiveFee cant be < 0 + if gasFeeCap.Lt(baseFee) { + return uint256.NewInt(0) + } + effectiveFee := new(uint256.Int).Sub(gasFeeCap, baseFee) + if tx.GetTip().Lt(effectiveFee) { + return tx.GetTip() + } else { + return effectiveFee + } +} + +func (tx DepositTx) Cost() *uint256.Int { + return tx.Value.Clone() +} + +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: common.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, baseFee *big.Int, rules *chain.Rules) (Message, error) { + msg := Message{ + nonce: 0, + gasLimit: tx.Gas, + gasPrice: *uint256.NewInt(0), + tip: *uint256.NewInt(0), + feeCap: *uint256.NewInt(0), + from: tx.From, + to: tx.To, + amount: *tx.Value, + data: tx.Data, + accessList: nil, + checkNonce: true, + isSystemTx: tx.IsSystemTransaction, + isDepositTx: true, + mint: tx.Mint, + } + return msg, nil +} + +func (tx *DepositTx) Sender(signer Signer) (libcommon.Address, error) { + return tx.From, nil +} + +func (tx DepositTx) RollupDataGas() RollupGasData { + return RollupGasData{} +} + +func (tx *DepositTx) GetDataHashes() []libcommon.Hash { + // Only blob txs have data hashes + return []libcommon.Hash{} +}
diff --git ledgerwatch/erigon/core/types/transaction_marshalling.go testinprod-io/erigon/core/types/transaction_marshalling.go index f66134f6fd41fe7a264ae8b4d7ce47f989f5dc43..efd894a900a00b3bfad3ce15563639f232b3a337 100644 --- ledgerwatch/erigon/core/types/transaction_marshalling.go +++ testinprod-io/erigon/core/types/transaction_marshalling.go @@ -32,6 +32,12 @@ 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"` AccessList *types2.AccessList `json:"accessList,omitempty"` @@ -96,6 +102,27 @@ enc.S = (*hexutil.Big)(tx.S.ToBig()) return json.Marshal(&enc) }   +func (tx DepositTx) MarshalJSON() ([]byte, error) { + var enc txJSON + + 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 + // DepositTx fields + 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 UnmarshalTransactionFromJSON(input []byte) (Transaction, error) { var p fastjson.Parser v, err := p.ParseBytes(input) @@ -125,6 +152,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 } @@ -360,3 +393,56 @@ } } 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 testinprod-io/erigon/core/types/transaction_signing.go index e21d2e2ef49ea11ea5e9be7bd0b2ebe16ddd07b1..0ccf0b39cb9d6547b6dbab5b8322088b1d0e2169 100644 --- ledgerwatch/erigon/core/types/transaction_signing.go +++ testinprod-io/erigon/core/types/transaction_signing.go @@ -192,6 +192,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 { @@ -272,6 +274,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") default: return nil, nil, nil, ErrTxTypeNotSupported }

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 testinprod-io/erigon/core/types/access_list_tx.go index 91302cefe367da8189bf528a1fc68344c9df130c..8523b508e0151038f4bbcca38666cef9dc4ee3e0 100644 --- ledgerwatch/erigon/core/types/access_list_tx.go +++ testinprod-io/erigon/core/types/access_list_tx.go @@ -461,6 +461,7 @@ amount: *tx.Value, data: tx.Data, accessList: tx.AccessList, checkNonce: true, + l1CostGas: tx.RollupDataGas(), }   if !rules.IsBerlin { @@ -469,6 +470,9 @@ }   var err error msg.from, err = tx.Sender(s) + if err != nil { + return msg, err + } return msg, err }   @@ -549,3 +553,7 @@ } tx.from.Store(addr) return addr, nil } + +func (tx *AccessListTx) RollupDataGas() RollupGasData { + return tx.computeRollupGas(tx) +}
diff --git ledgerwatch/erigon/core/types/dynamic_fee_tx.go testinprod-io/erigon/core/types/dynamic_fee_tx.go index e941c8dfe8d216c0897aa165b34b93270d057da2..01f762d4f5f7c69a45aa8dffab0eda6c5b3e77f6 100644 --- ledgerwatch/erigon/core/types/dynamic_fee_tx.go +++ testinprod-io/erigon/core/types/dynamic_fee_tx.go @@ -387,6 +387,7 @@ amount: *tx.Value, data: tx.Data, accessList: tx.AccessList, checkNonce: true, + l1CostGas: tx.RollupDataGas(), } if !rules.IsLondon { return msg, errors.New("eip-1559 transactions require London") @@ -404,6 +405,9 @@ }   var err error msg.from, err = tx.Sender(s) + if err != nil { + return msg, err + } return msg, err }   @@ -478,3 +482,9 @@ Tip: gasTip, FeeCap: gasFeeCap, } } + +func (tx *DynamicFeeTransaction) IsDepositTx() bool { return false } + +func (tx *DynamicFeeTransaction) RollupDataGas() RollupGasData { + return tx.computeRollupGas(tx) +}
diff --git ledgerwatch/erigon/core/types/legacy_tx.go testinprod-io/erigon/core/types/legacy_tx.go index 03b2b351ba0b31dbf0f4ef5eba15f147e0f90471..ffd241e35725033f7e21b5de386fd809bcdb8d51 100644 --- ledgerwatch/erigon/core/types/legacy_tx.go +++ testinprod-io/erigon/core/types/legacy_tx.go @@ -371,10 +371,14 @@ amount: *tx.Value, data: tx.Data, accessList: nil, checkNonce: true, + l1CostGas: tx.RollupDataGas(), }   var err error msg.from, err = tx.Sender(s) + if err != nil { + return msg, err + } return msg, err }   @@ -460,3 +464,9 @@ } tx.from.Store(addr) return addr, nil } + +func (tx *LegacyTx) IsDepositTx() bool { return false } + +func (tx *LegacyTx) RollupDataGas() RollupGasData { + 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/rollup_l1_cost.go testinprod-io/erigon/core/types/rollup_l1_cost.go new file mode 100644 index 0000000000000000000000000000000000000000..75f010804d547707fdf67ad68ef0b4f553864b73 --- /dev/null +++ testinprod-io/erigon/core/types/rollup_l1_cost.go @@ -0,0 +1,89 @@ +// 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/>. + +package types + +import ( + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/chain" + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon/params" + "math/big" +) + +type RollupGasData struct { + Zeroes, Ones uint64 +} + +func (r RollupGasData) DataGas(time uint64, cfg *chain.Config) (gas uint64) { + gas = r.Zeroes * params.TxDataZeroGas + if cfg.IsRegolith(time) { + gas += r.Ones * params.TxDataNonZeroGasEIP2028 + } else { + gas += (r.Ones + 68) * params.TxDataNonZeroGasEIP2028 + } + return gas +} + +type RollupMessage interface { + RollupDataGas() RollupGasData + IsDepositTx() bool +} + +type StateGetter interface { + GetState(addr libcommon.Address, key *libcommon.Hash, value *uint256.Int) +} + +// L1CostFunc is used in the state transition to determine the cost of a rollup message. +// Returns nil if there is no cost. +type L1CostFunc func(blockNum uint64, blockTime uint64, msg RollupMessage) *uint256.Int + +var ( + L1BaseFeeSlot = libcommon.BigToHash(big.NewInt(1)) + OverheadSlot = libcommon.BigToHash(big.NewInt(5)) + ScalarSlot = libcommon.BigToHash(big.NewInt(6)) +) + +var L1BlockAddr = libcommon.HexToAddress("0x4200000000000000000000000000000000000015") + +// NewL1CostFunc returns a function used for calculating L1 fee cost. +// This depends on the oracles because gas costs can change over time. +// It returns nil if there is no applicable cost function. +func NewL1CostFunc(config *chain.Config, statedb StateGetter) L1CostFunc { + cacheBlockNum := ^uint64(0) + var l1BaseFee, overhead, scalar uint256.Int + return func(blockNum uint64, blockTime uint64, msg RollupMessage) *uint256.Int { + rollupDataGas := msg.RollupDataGas().DataGas(blockTime, config) // Only fake txs for RPC view-calls are 0. + if config.Optimism == nil || msg.IsDepositTx() || rollupDataGas == 0 { + return nil + } + if blockNum != cacheBlockNum { + statedb.GetState(L1BlockAddr, &L1BaseFeeSlot, &l1BaseFee) + statedb.GetState(L1BlockAddr, &OverheadSlot, &overhead) + statedb.GetState(L1BlockAddr, &ScalarSlot, &scalar) + cacheBlockNum = blockNum + } + return L1Cost(rollupDataGas, &l1BaseFee, &overhead, &scalar) + } +} + +func L1Cost(rollupDataGas uint64, l1BaseFee, overhead, scalar *uint256.Int) *uint256.Int { + l1GasUsed := new(uint256.Int).SetUint64(rollupDataGas) + l1GasUsed = l1GasUsed.Add(l1GasUsed, overhead) + l1Cost := l1GasUsed.Mul(l1GasUsed, l1BaseFee) + l1Cost = l1Cost.Mul(l1Cost, scalar) + return l1Cost.Div(l1Cost, uint256.NewInt(1_000_000)) +}
diff --git ledgerwatch/erigon/core/types/transaction.go testinprod-io/erigon/core/types/transaction.go index a556964d0323513e4b1800a7825fcc564c23ffe4..94dd790cc1d02a78bd5ac25844f90b4294861aca 100644 --- ledgerwatch/erigon/core/types/transaction.go +++ testinprod-io/erigon/core/types/transaction.go @@ -53,6 +53,7 @@ LegacyTxType = iota AccessListTxType DynamicFeeTxType BlobTxType + DepositTxType = 0x7E )   // Transaction is an Ethereum transaction. @@ -93,6 +94,7 @@ Sender(Signer) (libcommon.Address, error) GetSender() (libcommon.Address, bool) SetSender(libcommon.Address) IsContractDeploy() bool + RollupDataGas() RollupGasData }   // TransactionMisc is collection of miscelaneous fields for transaction that is supposed to be embedded into concrete @@ -103,6 +105,49 @@ // 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 +}) RollupGasData { + if tx.Type() == DepositTxType { + return RollupGasData{} + } + if v := tm.rollupGas.Load(); v != nil { + return v.(RollupGasData) + } + 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 := RollupGasData{ + 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 @@ -156,6 +201,12 @@ } tx = t case DynamicFeeTxType: t := &DynamicFeeTransaction{} + if err = t.DecodeRLP(s); err != nil { + return nil, err + } + tx = t + case DepositTxType: + t := &DepositTx{} if err = t.DecodeRLP(s); err != nil { return nil, err } @@ -471,9 +522,15 @@ accessList types2.AccessList checkNonce bool isFree bool dataHashes []libcommon.Hash + isFake bool + + isSystemTx bool + isDepositTx bool + mint *uint256.Int + l1CostGas RollupGasData }   -func NewMessage(from libcommon.Address, to *libcommon.Address, nonce uint64, amount *uint256.Int, gasLimit uint64, gasPrice *uint256.Int, feeCap, tip *uint256.Int, data []byte, accessList types2.AccessList, checkNonce bool, isFree bool, maxFeePerDataGas *uint256.Int) Message { +func NewMessage(from libcommon.Address, to *libcommon.Address, nonce uint64, amount *uint256.Int, gasLimit uint64, gasPrice *uint256.Int, feeCap, tip *uint256.Int, data []byte, accessList types2.AccessList, checkNonce bool, isFree bool, isFake bool, maxFeePerDataGas *uint256.Int) Message { m := Message{ from: from, to: to, @@ -484,6 +541,7 @@ data: data, accessList: accessList, checkNonce: checkNonce, isFree: isFree, + isFake: isFake, } if gasPrice != nil { m.gasPrice.Set(gasPrice) @@ -518,6 +576,7 @@ func (m Message) IsFree() bool { return m.isFree } func (m *Message) SetIsFree(isFree bool) { m.isFree = isFree } +func (m Message) IsFake() bool { return m.isFake }   func (m *Message) ChangeGas(globalGasCap, desiredGas uint64) { gas := globalGasCap @@ -535,7 +594,11 @@ m.gasLimit = gas }   -func (m Message) DataGas() uint64 { return params.DataGasPerBlob * uint64(len(m.dataHashes)) } +func (m Message) IsSystemTx() bool { return m.isSystemTx } +func (m Message) IsDepositTx() bool { return m.isDepositTx } +func (m Message) Mint() *uint256.Int { return m.mint } +func (m Message) RollupDataGas() RollupGasData { return m.l1CostGas } +func (m Message) DataGas() uint64 { return params.DataGasPerBlob * uint64(len(m.dataHashes)) } func (m Message) MaxFeePerDataGas() *uint256.Int { return &m.maxFeePerDataGas }
diff --git ledgerwatch/erigon/core/vm/evmtypes/evmtypes.go testinprod-io/erigon/core/vm/evmtypes/evmtypes.go index efc59612021f76092c3406b858cd3d8f16613e9f..488f4ba8d17c02083434dd8702231d27d3223660 100644 --- ledgerwatch/erigon/core/vm/evmtypes/evmtypes.go +++ testinprod-io/erigon/core/vm/evmtypes/evmtypes.go @@ -31,6 +31,9 @@ Difficulty *big.Int // Provides information for DIFFICULTY BaseFee *uint256.Int // Provides information for BASEFEE PrevRanDao *libcommon.Hash // Provides information for PREVRANDAO ExcessDataGas *big.Int // Provides information for handling data blobs + + // L1CostFunc returns the L1 cost of the rollup message, the function may be nil, or return nil + L1CostFunc types.L1CostFunc }   // TxContext provides the EVM with information about a transaction.
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/trace_adhoc.go testinprod-io/erigon/cmd/rpcdaemon/commands/trace_adhoc.go index 79988b862fab9359f06bf3d1b0794beba0c9be3d..207dbac842f20408b08741294122fd4e5566c747 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/trace_adhoc.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/trace_adhoc.go @@ -221,7 +221,7 @@ var accessList types2.AccessList if args.AccessList != nil { accessList = *args.AccessList } - msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, false /* checkNonce */, false /* isFree */, maxFeePerDataGas) + msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, false /* checkNonce */, false /* isFree */, true /* isFake */, maxFeePerDataGas) return msg, nil }   @@ -961,6 +961,7 @@ txCtx := core.NewEVMTxContext(msg)   blockCtx.GasLimit = math.MaxUint64 blockCtx.MaxGasLimit = true + blockCtx.L1CostFunc = types.NewL1CostFunc(chainConfig, ibs)   evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vm.Config{Debug: traceTypeTrace, Tracer: &ot})   @@ -1139,6 +1140,7 @@ header = parentHeader useParent = true }   + l1CostFunc := types.NewL1CostFunc(chainConfig, ibs) for txIndex, msg := range msgs { if err := libcommon.Stopped(ctx.Done()); err != nil { return nil, err @@ -1183,6 +1185,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/cmd/rpcdaemon/commands/trace_filtering.go testinprod-io/erigon/cmd/rpcdaemon/commands/trace_filtering.go index c96d3c0eeaa3b66dd0b53508810f12a9786fe9a7..489f091195d550fc01946a733b51b4dd49314aa5 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/trace_filtering.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/trace_filtering.go @@ -833,6 +833,7 @@ ibs := state.New(cachedReader)   blockCtx := transactions.NewEVMBlockContext(engine, lastHeader, true /* requireCanonical */, dbtx, api._blockReader) txCtx := core.NewEVMTxContext(msg) + blockCtx.L1CostFunc = types.NewL1CostFunc(chainConfig, ibs) evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vmConfig)   gp := new(core.GasPool).AddGas(msg.Gas())
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/tracing.go testinprod-io/erigon/cmd/rpcdaemon/commands/tracing.go index 3d84f6aadb238af5906824fe8bbc07b0262ab505..c43fcc8c48d028d85fb8951be308ea91ffaf728f 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/tracing.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/tracing.go @@ -2,6 +2,7 @@ package commands   import ( "context" + "encoding/json" "fmt" "math/big" "time" @@ -199,6 +200,22 @@ if !ok { stream.WriteNil() return nil } + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return rpc.ErrNoHistoricalFallback + } + treeResult := &GethTrace{} + if err := api.relayToHistoricalBackend(ctx, treeResult, "debug_traceTransaction", hash, config); err != nil { + return fmt.Errorf("historical backend error: %w", err) + } + // stream out relayed response + result, err := json.Marshal(treeResult) + 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) @@ -320,6 +337,7 @@ }   blockCtx := transactions.NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, dbtx, api._blockReader) txCtx := core.NewEVMTxContext(msg) + blockCtx.L1CostFunc = types.NewL1CostFunc(chainConfig, ibs) // Trace the transaction and return return transactions.TraceTx(ctx, msg, blockCtx, txCtx, ibs, config, chainConfig, stream, api.evmCallTimeout) }
diff --git ledgerwatch/erigon/turbo/transactions/call.go testinprod-io/erigon/turbo/transactions/call.go index f2399e8c5d80f5638c8dbf31b5a5985c1efce63b..51a48e5de92331cada64e75d8ca3eb59d33cb13b 100644 --- ledgerwatch/erigon/turbo/transactions/call.go +++ testinprod-io/erigon/turbo/transactions/call.go @@ -84,6 +84,7 @@ return nil, err } blockCtx := NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, tx, headerReader) txCtx := core.NewEVMTxContext(msg) + blockCtx.L1CostFunc = types.NewL1CostFunc(chainConfig, state)   evm := vm.NewEVM(blockCtx, txCtx, state, chainConfig, vm.Config{NoBaseFee: true})   @@ -223,6 +224,7 @@ return nil, err }   blockCtx := NewEVMBlockContext(engine, header, blockNrOrHash.RequireCanonical, tx, headerReader) + blockCtx.L1CostFunc = types.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 testinprod-io/erigon/turbo/transactions/tracing.go index a1ac24d56a6a46737985acc7e7376429eac3c654..d64e1a1c400c267c65729e6b36c4415fd415a681 100644 --- ledgerwatch/erigon/turbo/transactions/tracing.go +++ testinprod-io/erigon/turbo/transactions/tracing.go @@ -65,6 +65,7 @@ if parentHeader != nil { excessDataGas = parentHeader.ExcessDataGas } BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil, excessDataGas) + BlockContext.L1CostFunc = types.NewL1CostFunc(cfg, statedb)   // Recompute transactions up to the target index. signer := types.MakeSigner(cfg, block.NumberU64())

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 testinprod-io/erigon/core/state_transition.go index 419769d0b7d8848ed32c54f4b7c362a63ca4f2ef..7bd6ef87b666b41bebc5fa6ee20d51762391eaf7 100644 --- ledgerwatch/erigon/core/state_transition.go +++ testinprod-io/erigon/core/state_transition.go @@ -24,11 +24,11 @@ libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/txpool" types2 "github.com/ledgerwatch/erigon-lib/types" - "github.com/ledgerwatch/erigon/common" cmath "github.com/ledgerwatch/erigon/common/math" "github.com/ledgerwatch/erigon/common/u256" "github.com/ledgerwatch/erigon/consensus/misc" + "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/core/vm" "github.com/ledgerwatch/erigon/core/vm/evmtypes" "github.com/ledgerwatch/erigon/crypto" @@ -89,6 +89,12 @@ DataGas() uint64 MaxFeePerDataGas() *uint256.Int Value() *uint256.Int   + // Mint is nil if there is no minting + Mint() *uint256.Int + IsSystemTx() bool + IsDepositTx() bool + RollupDataGas() types.RollupGasData + Nonce() uint64 CheckNonce() bool Data() []byte @@ -96,6 +102,7 @@ AccessList() types2.AccessList DataHashes() []libcommon.Hash   IsFree() bool + IsFake() bool }   // ExecutionResult includes all output after executing given evm @@ -201,6 +208,13 @@ mgval, overflow := mgval.MulOverflow(mgval, 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 && !st.msg.IsFake() { + l1Cost = fn(st.evm.Context().BlockNumber, st.evm.Context().Time, st.msg) + } + if l1Cost != nil { + mgval = mgval.Add(mgval, l1Cost) + } balanceCheck := mgval if st.gasFeeCap != nil { balanceCheck = st.sharedBuyGasBalance.SetUint64(st.msg.Gas()) @@ -211,6 +225,9 @@ } balanceCheck, overflow = balanceCheck.AddOverflow(balanceCheck, st.value) if overflow { return fmt.Errorf("%w: address %v", ErrInsufficientFunds, st.msg.From().Hex()) + } + if l1Cost != nil { + balanceCheck.Add(balanceCheck, l1Cost) } } var subBalance = false @@ -249,8 +266,38 @@ }   // 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) + } + } + // 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.ChainConfig().IsOptimismRegolith(st.evm.Context().Time) { + return fmt.Errorf("%w: address %v", ErrSystemTxNotSupported, + st.msg.From().Hex()) + } + return nil + } + // gas used by deposits may not be used by other txs + if err := st.gp.SubGas(st.msg.Gas()); err != nil { + if !gasBailout { + return err + } + } + return nil + } // Make sure this transaction's nonce is correct. - if st.msg.CheckNonce() { + if st.msg.CheckNonce() && !st.msg.IsFake() { stNonce := st.state.GetNonce(st.msg.From()) if msgNonce := st.msg.Nonce(); stNonce < msgNonce { return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh, @@ -299,13 +346,44 @@ // // 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) { + if mint := st.msg.Mint(); mint != nil { + st.state.AddBalance(st.msg.From(), mint) + } + 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() + // Regolith changes this behaviour so the actual gas used is reported. + // In this case the tx is invalid so is recorded as using all gas. + if st.msg.IsSystemTx() && !st.evm.ChainConfig().IsRegolith(st.evm.Context().Time) { + gasUsed = 0 + } + result = &ExecutionResult{ + UsedGas: gasUsed, + Err: fmt.Errorf("failed deposit: %w", err), + ReturnData: nil, + } + err = nil + } + return result, err + +} + +func (st *StateTransition) innerTransitionDb(refunds bool, gasBailout bool) (*ExecutionResult, error) { var input1 *uint256.Int var input2 *uint256.Int if st.isBor { input1 = st.state.GetBalance(st.msg.From()).Clone() input2 = st.state.GetBalance(st.evm.Context().Coinbase).Clone() } - // First check this message satisfies all consensus rules before // applying the message. The rules include these clauses // @@ -381,6 +459,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 @@ -390,6 +486,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) { @@ -423,6 +527,15 @@ input2, output1.Sub(output1, amount), output2.Add(output2, amount), ) + } + if optimismConfig := st.evm.ChainConfig().Optimism; optimismConfig != nil { + 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.evm.Context().BlockNumber, st.evm.Context().Time, st.msg); 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 testinprod-io/erigon/consensus/misc/eip1559.go index bf9490961960b45af218afafdd886655c801c98c..0fd9ce71fd791328003e3424b45029d63772d599 100644 --- ledgerwatch/erigon/consensus/misc/eip1559.go +++ testinprod-io/erigon/consensus/misc/eip1559.go @@ -35,10 +35,12 @@ func VerifyEip1559Header(config *chain.Config, parent, header *types.Header) error { // 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 if header.BaseFee == nil { @@ -61,9 +63,9 @@ 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())) ) // If the parent gasUsed is the same as the target, the baseFee remains unchanged. if parent.GasUsed == parentGasTarget { @@ -94,12 +96,12 @@ ) } }   -func getBaseFeeChangeDenominator(borConfig *chain.BorConfig, number uint64) uint64 { +func getBaseFeeChangeDenominator(config *chain.Config, number uint64) uint64 { // If we're running bor based chain post delhi hardfork, return the new value - if borConfig != nil && borConfig.IsDelhi(number) { + if config.Bor != nil && config.Bor.IsDelhi(number) { return params.BaseFeeChangeDenominatorPostDelhi }   // Return the original once for other chains and pre-fork cases - return params.BaseFeeChangeDenominator + return config.BaseFeeChangeDenominator(params.BaseFeeChangeDenominator) }
diff --git ledgerwatch/erigon/core/state_processor.go testinprod-io/erigon/core/state_processor.go index 8faa4e370748b4e647fcba4db52d2d6f805b5357..53cada04a2f9c340a29e439ae64677d1c82724f6 100644 --- ledgerwatch/erigon/core/state_processor.go +++ testinprod-io/erigon/core/state_processor.go @@ -58,6 +58,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 @@ -81,9 +86,16 @@ 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. + // Before the Regolith fork the DepositNonce must remain nil + receipt.DepositNonce = &nonce + } + // if the transaction created a contract, store the creation address in the receipt. if msg.To() == nil { - receipt.ContractAddress = crypto.CreateAddress(evm.TxContext().Origin, tx.GetNonce()) + receipt.ContractAddress = crypto.CreateAddress(evm.TxContext().Origin, nonce) } // Set the receipt logs and create a bloom for filtering receipt.Logs = ibs.GetLogs(tx.Hash()) @@ -107,6 +119,7 @@ // about the transaction and calling mechanisms. cfg.SkipAnalysis = SkipAnalysis(config, header.Number.Uint64())   blockContext := NewEVMBlockContext(header, blockHashFunc, engine, author, excessDataGas) + blockContext.L1CostFunc = types.NewL1CostFunc(config, ibs) vmenv := vm.NewEVM(blockContext, evmtypes.TxContext{}, ibs, config, cfg)   return applyTransaction(config, engine, gp, ibs, stateWriter, header, tx, usedGas, vmenv, cfg)

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 testinprod-io/erigon/params/protocol_params.go index e4cc0669c4729aba256c1c17ae813e2cd81ed871..6e8ad8b6d1704f95382285fe1fa66e9b3e2a926f 100644 --- ledgerwatch/erigon/params/protocol_params.go +++ testinprod-io/erigon/params/protocol_params.go @@ -16,7 +16,17 @@ // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.   package params   -import "math/big" +import ( + libcommon "github.com/ledgerwatch/erigon-lib/common" + "math/big" +) + +var ( + // The base fee portion of the transaction fee accumulates at this predeploy + OptimismBaseFeeRecipient = libcommon.HexToAddress("0x4200000000000000000000000000000000000019") + // The L1 portion of the transaction fee accumulates at this predeploy + OptimismL1FeeRecipient = libcommon.HexToAddress("0x420000000000000000000000000000000000001A") +)   const ( GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations.

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/cmd/rpcdaemon/commands/engine_api.go testinprod-io/erigon/cmd/rpcdaemon/commands/engine_api.go index 3ad639e507f9637d05b50634173462c0d4026a91..d6c0a12a11744eefdb118e24af3474aeb9687aac 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/engine_api.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/engine_api.go @@ -71,6 +71,11 @@ Timestamp hexutil.Uint64 `json:"timestamp" gencodec:"required"` PrevRandao common.Hash `json:"prevRandao" gencodec:"required"` SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"` Withdrawals []*types.Withdrawal `json:"withdrawals"` + + // optimism + NoTxPool bool `json:"noTxPool,omitempty" gencodec:"optional"` + Transactions []hexutility.Bytes `json:"transactions,omitempty" gencodec:"optional"` + GasLimit *hexutil.Uint64 `json:"gasLimit,omitempty" gencodec:"optional"` }   // TransitionConfiguration represents the correct configurations of the CL and the EL @@ -198,11 +203,18 @@ }   var attributes *remote.EnginePayloadAttributes if payloadAttributes != nil { + txs := make([][]byte, 0, len(payloadAttributes.Transactions)) + for _, tx := range payloadAttributes.Transactions { + txs = append(txs, tx) + } attributes = &remote.EnginePayloadAttributes{ Version: 1, Timestamp: uint64(payloadAttributes.Timestamp), PrevRandao: gointerfaces.ConvertHashToH256(payloadAttributes.PrevRandao), SuggestedFeeRecipient: gointerfaces.ConvertAddressToH160(payloadAttributes.SuggestedFeeRecipient), + NoTxPool: &payloadAttributes.NoTxPool, + Transactions: txs, + GasLimit: (*uint64)(payloadAttributes.GasLimit), } if version >= 2 && payloadAttributes.Withdrawals != nil { attributes.Version = 2
diff --git ledgerwatch/erigon/ethdb/privateapi/ethbackend.go testinprod-io/erigon/ethdb/privateapi/ethbackend.go index f85422f03339a9c31b728e5cc507b5133df745cb..531cc9e4f6043c1e96e1c88f1547046cb577f4d1 100644 --- ledgerwatch/erigon/ethdb/privateapi/ethbackend.go +++ testinprod-io/erigon/ethdb/privateapi/ethbackend.go @@ -707,11 +707,18 @@ return nil, err } defer tx2.Rollback() headHash := rawdb.ReadHeadBlockHash(tx2) + if s.config.Optimism != nil { + headHash = forkChoice.HeadBlockHash + } headNumber := rawdb.ReadHeaderNumber(tx2, headHash) + if headNumber == nil { + log.Warn("unknown parent hash in block building", "parent", headHash) + return nil, &InvalidPayloadAttributesErr + } headHeader := rawdb.ReadHeader(tx2, headHash, *headNumber) tx2.Rollback()   - if headHeader.Hash() != forkChoice.HeadBlockHash { + if headHeader.Hash() != forkChoice.HeadBlockHash && 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. @@ -724,7 +731,7 @@ "forkChoice.HeadBlockHash", forkChoice.HeadBlockHash, "headHeader.Hash", headHeader.Hash()) return &remote.EngineForkChoiceUpdatedResponse{PayloadStatus: convertPayloadStatus(status)}, nil }   - if headHeader.Time >= payloadAttributes.Timestamp { + if headHeader.Time >= payloadAttributes.Timestamp && s.config.Optimism == nil { return nil, &InvalidPayloadAttributesErr }   @@ -734,6 +741,9 @@ Timestamp: payloadAttributes.Timestamp, PrevRandao: gointerfaces.ConvertH256ToHash(payloadAttributes.PrevRandao), SuggestedFeeRecipient: gointerfaces.ConvertH160toAddress(payloadAttributes.SuggestedFeeRecipient), PayloadId: s.payloadId, + Transactions: payloadAttributes.Transactions, + NoTxPool: payloadAttributes.NoTxPool != nil && *req.PayloadAttributes.NoTxPool, + GasLimit: payloadAttributes.GasLimit, } if payloadAttributes.Version >= 2 { param.Withdrawals = ConvertWithdrawalsFromRpc(payloadAttributes.Withdrawals)

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/cmd/integration/commands/stages.go testinprod-io/erigon/cmd/integration/commands/stages.go index 1d62853f02c6e097a54b50fcd0466cdaba26eae5..aedb899d7700ed26ceda471c4f8660614133c47c 100644 --- ledgerwatch/erigon/cmd/integration/commands/stages.go +++ testinprod-io/erigon/cmd/integration/commands/stages.go @@ -1376,7 +1376,7 @@ }() miningSync := stagedsync.New( stagedsync.MiningStages(ctx, stagedsync.StageMiningCreateBlockCfg(db, miner, *chainConfig, engine, nil, nil, nil, dirs.Tmp), - stagedsync.StageMiningExecCfg(db, miner, events, *chainConfig, engine, &vm.Config{}, dirs.Tmp, nil, 0, nil, nil, allSn, cfg.TransactionsV3), + stagedsync.StageMiningExecCfg(db, miner, events, *chainConfig, engine, &vm.Config{}, dirs.Tmp, nil, 0, nil, nil, false, allSn, cfg.TransactionsV3), stagedsync.StageHashStateCfg(db, dirs, historyV3, agg), stagedsync.StageTrieCfg(db, false, true, false, dirs.Tmp, br, nil, historyV3, agg), stagedsync.StageMiningFinishCfg(db, *chainConfig, engine, miner, miningCancel),
diff --git ledgerwatch/erigon/eth/stagedsync/default_stages.go testinprod-io/erigon/eth/stagedsync/default_stages.go index 952fe6fca9ee542cdfc9c34e9d1fee71dae8ca39..4389e5e0c0e194833b4e2e46e61d833c931a4f29 100644 --- ledgerwatch/erigon/eth/stagedsync/default_stages.go +++ testinprod-io/erigon/eth/stagedsync/default_stages.go @@ -387,5 +387,9 @@ stages.BlockHashes, stages.Headers, }   -var MiningUnwindOrder = UnwindOrder{} // nothing to unwind in mining - because mining does not commit db changes -var MiningPruneOrder = PruneOrder{} // nothing to unwind in mining - because mining does not commit db changes +var MiningUnwindOrder = UnwindOrder{ + stages.HashState, + stages.IntermediateHashes, + stages.MiningExecution, +} +var MiningPruneOrder = PruneOrder{} // nothing to unwind in mining - because mining does not commit db changes
diff --git ledgerwatch/erigon/eth/stagedsync/stage_mining_create_block.go testinprod-io/erigon/eth/stagedsync/stage_mining_create_block.go index 90993e898c587d7867869015e73e2d45f9cb9fdc..b75c6f981a64a12c6693857d0406b6996a396f57 100644 --- ledgerwatch/erigon/eth/stagedsync/stage_mining_create_block.go +++ testinprod-io/erigon/eth/stagedsync/stage_mining_create_block.go @@ -3,6 +3,7 @@ import ( "errors" "fmt" + "github.com/ledgerwatch/erigon/eth/stagedsync/stages" "math/big" "time"   @@ -31,6 +32,10 @@ Txs types.Transactions Receipts types.Receipts Withdrawals []*types.Withdrawal PreparedTxs types.TransactionsStream + + ForceTxs types.TransactionsStream + LocalTxs types.TransactionsStream + RemoteTxs types.TransactionsStream }   type MiningState struct { @@ -110,7 +115,32 @@ return fmt.Errorf("empty block %d", executionAt) }   if cfg.blockBuilderParameters != nil && cfg.blockBuilderParameters.ParentHash != parent.Hash() { - return fmt.Errorf("wrong head block: %x (current) vs %x (requested)", parent.Hash(), cfg.blockBuilderParameters.ParentHash) + if cfg.chainConfig.IsOptimism() { + // In Optimism, self re-org via engine_forkchoiceUpdatedV1 is allowed + log.Warn("wrong head block", "current", parent.Hash(), "requested", cfg.blockBuilderParameters.ParentHash, "executionAt", executionAt) + exectedParent, err := rawdb.ReadHeaderByHash(tx, cfg.blockBuilderParameters.ParentHash) + if err != nil { + return err + } + expectedExecutionAt := exectedParent.Number.Uint64() + hashStateProgress, err := stages.GetStageProgress(tx, stages.HashState) + if err != nil { + return err + } + // Trigger unwinding to target block + if hashStateProgress > expectedExecutionAt { + // MiningExecution stage progress should be updated to trigger unwinding + if err = stages.SaveStageProgress(tx, stages.MiningExecution, executionAt); err != nil { + return err + } + s.state.UnwindTo(expectedExecutionAt, libcommon.Hash{}) + return nil + } + executionAt = expectedExecutionAt + parent = exectedParent + } else { + return fmt.Errorf("wrong head block: %x (current) vs %x (requested)", parent.Hash(), cfg.blockBuilderParameters.ParentHash) + } }   if cfg.miner.MiningConfig.Etherbase == (libcommon.Address{}) { @@ -123,9 +153,14 @@ }   blockNum := executionAt + 1   - localUncles, remoteUncles, err := readNonCanonicalHeaders(tx, blockNum, cfg.engine, coinbase, txPoolLocals) - if err != nil { - return err + // TODO: uncles should also be ignored in PoS, not just Optimism. + // There are no uncles after the Merge. Erigon miner bug? + var localUncles, remoteUncles map[libcommon.Hash]*types.Header + if cfg.chainConfig.Optimism == nil { + localUncles, remoteUncles, err = readNonCanonicalHeaders(tx, blockNum, cfg.engine, coinbase, txPoolLocals) + if err != nil { + return err + } } chain := ChainReader{Cfg: cfg.chainConfig, Db: tx} var GetBlocksFromHash = func(hash libcommon.Hash, n int) (blocks []*types.Block) { @@ -170,7 +205,11 @@ // If we are on proof-of-stake timestamp should be already set for us timestamp = cfg.blockBuilderParameters.Timestamp }   - header := core.MakeEmptyHeader(parent, &cfg.chainConfig, timestamp, &cfg.miner.MiningConfig.GasLimit) + targetGasLimit := &cfg.miner.MiningConfig.GasLimit + if cfg.chainConfig.IsOptimism() { + targetGasLimit = cfg.blockBuilderParameters.GasLimit + } + header := core.MakeEmptyHeader(parent, &cfg.chainConfig, timestamp, targetGasLimit) header.Coinbase = coinbase header.Extra = cfg.miner.MiningConfig.ExtraData
diff --git ledgerwatch/erigon/eth/stagedsync/stage_mining_exec.go testinprod-io/erigon/eth/stagedsync/stage_mining_exec.go index a5525ad4135aa51309a799a708729cf533801866..8f982674740df44ac997c88e0de9fc54619f9a4b 100644 --- ledgerwatch/erigon/eth/stagedsync/stage_mining_exec.go +++ testinprod-io/erigon/eth/stagedsync/stage_mining_exec.go @@ -9,6 +9,12 @@ "math/big" "sync/atomic" "time"   + "github.com/ledgerwatch/erigon-lib/common/length" + "github.com/ledgerwatch/erigon-lib/etl" + "github.com/ledgerwatch/erigon-lib/kv/temporal/historyv2" + "github.com/ledgerwatch/erigon/common/changeset" + "github.com/ledgerwatch/erigon/common/dbutils" + mapset "github.com/deckarep/golang-set/v2" "github.com/holiman/uint256" "github.com/ledgerwatch/erigon-lib/chain" @@ -52,6 +58,7 @@ interrupt *int32 payloadId uint64 txPool2 *txpool.TxPool txPool2DB kv.RoDB + noTxPool bool }   func StageMiningExecCfg( @@ -66,6 +73,7 @@ interrupt *int32, payloadId uint64, txPool2 *txpool.TxPool, txPool2DB kv.RoDB, + noTxPool bool, snapshots *snapshotsync.RoSnapshots, transactionsV3 bool, ) MiningExecCfg { @@ -82,6 +90,7 @@ interrupt: interrupt, payloadId: payloadId, txPool2: txPool2, txPool2DB: txPool2DB, + noTxPool: noTxPool, } }   @@ -94,6 +103,7 @@ chainID, _ := uint256.FromBig(cfg.chainConfig.ChainID) logPrefix := s.LogPrefix() current := cfg.miningState.MiningBlock txs := current.PreparedTxs + forceTxs := current.ForceTxs noempty := true   stateReader := state.NewPlainStateReader(tx) @@ -117,13 +127,20 @@ // 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 { + if !forceTxs.Empty() { + logs, _, err := addTransactionsToMiningBlock(logPrefix, current, cfg.chainConfig, cfg.vmConfig, getHeader, cfg.engine, forceTxs, cfg.miningState.MiningConfig.Etherbase, ibs, quit, cfg.interrupt, cfg.payloadId, true) + if err != nil { + return err + } + NotifyPendingLogs(logPrefix, cfg.notifier, logs) + } 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) + logs, _, err := addTransactionsToMiningBlock(logPrefix, current, cfg.chainConfig, cfg.vmConfig, getHeader, cfg.engine, txs, cfg.miningState.MiningConfig.Etherbase, ibs, quit, cfg.interrupt, cfg.payloadId, false) if err != nil { return err } NotifyPendingLogs(logPrefix, cfg.notifier, logs) - } else { + } else if !cfg.noTxPool {   yielded := mapset.NewSet[[32]byte]() simulationTx := memdb.NewMemoryBatch(tx, cfg.tmpdir) @@ -140,7 +157,7 @@ return err }   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) + logs, stop, err := addTransactionsToMiningBlock(logPrefix, current, cfg.chainConfig, cfg.vmConfig, getHeader, cfg.engine, txs, cfg.miningState.MiningConfig.Etherbase, ibs, quit, cfg.interrupt, cfg.payloadId, false) if err != nil { return err } @@ -371,7 +388,7 @@ log.Debug("Filtration", "initial", initialCnt, "no sender", noSenderCnt, "no account", noAccountCnt, "nonce too low", nonceTooLowCnt, "nonceTooHigh", missedTxs, "sender not EOA", notEOACnt, "fee too low", feeTooLowCnt, "overflow", overflowCnt, "balance too low", balanceTooLowCnt, "filtered", len(filtered)) return filtered, nil }   -func addTransactionsToMiningBlock(logPrefix string, current *MiningBlock, chainConfig chain.Config, vmConfig *vm.Config, getHeader func(hash libcommon.Hash, number uint64) *types.Header, engine consensus.Engine, txs types.TransactionsStream, coinbase libcommon.Address, ibs *state.IntraBlockState, quit <-chan struct{}, interrupt *int32, payloadId uint64) (types.Logs, bool, error) { +func addTransactionsToMiningBlock(logPrefix string, current *MiningBlock, chainConfig chain.Config, vmConfig *vm.Config, getHeader func(hash libcommon.Hash, number uint64) *types.Header, engine consensus.Engine, txs types.TransactionsStream, coinbase libcommon.Address, ibs *state.IntraBlockState, quit <-chan struct{}, interrupt *int32, payloadId uint64, allowDeposits bool) (types.Logs, bool, error) { header := current.Header tcount := 0 gasPool := new(core.GasPool).AddGas(header.GasLimit - header.GasUsed) @@ -459,6 +476,12 @@ continue }   // Start executing the transaction + ibs.Prepare(txn.Hash(), libcommon.Hash{}, tcount) + if !allowDeposits && txn.Type() == types.DepositTxType { + log.Warn(fmt.Sprintf("[%s] Ignoring deposit tx that made its way through mempool", logPrefix), "hash", txn.Hash()) + txs.Pop() + continue + } logs, err := miningCommitTx(txn, coinbase, vmConfig, chainConfig, ibs, current)   if errors.Is(err, core.ErrGasLimitReached) { @@ -509,3 +532,110 @@ return } notifier.OnNewPendingLogs(logs) } + +// implemented by tweaking UnwindExecutionStage +func UnwindMiningExecutionStage(u *UnwindState, s *StageState, tx kv.RwTx, ctx context.Context, cfg MiningExecCfg) (err error) { + if u.UnwindPoint >= s.BlockNumber { + return nil + } + useExternalTx := tx != nil + if !useExternalTx { + tx, err = cfg.db.BeginRw(context.Background()) + if err != nil { + return err + } + defer tx.Rollback() + } + logPrefix := u.LogPrefix() + log.Info(fmt.Sprintf("[%s] Unwind Mining Execution", logPrefix), "from", s.BlockNumber, "to", u.UnwindPoint) + + if err = unwindMiningExecutionStage(u, s, tx, ctx, cfg); err != nil { + return err + } + if err = u.Done(tx); err != nil { + return err + } + + if !useExternalTx { + if err = tx.Commit(); err != nil { + return err + } + } + return nil +} + +func unwindMiningExecutionStage(u *UnwindState, s *StageState, tx kv.RwTx, ctx context.Context, cfg MiningExecCfg) error { + logPrefix := s.LogPrefix() + stateBucket := kv.PlainState + storageKeyLength := length.Addr + length.Incarnation + length.Hash + + changes := etl.NewCollector(logPrefix, cfg.tmpdir, etl.NewOldestEntryBuffer(etl.BufferOptimalSize)) + defer changes.Close() + errRewind := changeset.RewindData(tx, s.BlockNumber, u.UnwindPoint, changes, ctx.Done()) + if errRewind != nil { + return fmt.Errorf("getting rewind data: %w", errRewind) + } + + if err := changes.Load(tx, stateBucket, func(k, v []byte, table etl.CurrentTableReader, next etl.LoadNextFunc) error { + if len(k) == 20 { + if len(v) > 0 { + var acc accounts.Account + if err := acc.DecodeForStorage(v); err != nil { + return err + } + + // Fetch the code hash + recoverCodeHashPlain(&acc, tx, k) + var address libcommon.Address + copy(address[:], k) + + // cleanup contract code bucket + original, err := state.NewPlainStateReader(tx).ReadAccountData(address) + if err != nil { + return fmt.Errorf("read account for %x: %w", address, err) + } + if original != nil { + // clean up all the code incarnations original incarnation and the new one + for incarnation := original.Incarnation; incarnation > acc.Incarnation && incarnation > 0; incarnation-- { + err = tx.Delete(kv.PlainContractCode, dbutils.PlainGenerateStoragePrefix(address[:], incarnation)) + if err != nil { + return fmt.Errorf("writeAccountPlain for %x: %w", address, err) + } + } + } + + newV := make([]byte, acc.EncodingLengthForStorage()) + acc.EncodeForStorage(newV) + if err := next(k, k, newV); err != nil { + return err + } + } else { + if err := next(k, k, nil); err != nil { + return err + } + } + return nil + } + if len(v) > 0 { + if err := next(k, k[:storageKeyLength], v); err != nil { + return err + } + } else { + if err := next(k, k[:storageKeyLength], nil); err != nil { + return err + } + } + return nil + + }, etl.TransformArgs{Quit: ctx.Done()}); err != nil { + return err + } + + if err := historyv2.Truncate(tx, u.UnwindPoint+1); err != nil { + return err + } + + // we do not have to delete receipt, epoch, callTraceSet because + // mining stage does not write anything to db. + return nil +}
diff --git ledgerwatch/erigon/eth/stagedsync/stage_mining_force_txs.go testinprod-io/erigon/eth/stagedsync/stage_mining_force_txs.go new file mode 100644 index 0000000000000000000000000000000000000000..bed1f12db6b85077d77ebf250a01e892e6c32ad8 --- /dev/null +++ testinprod-io/erigon/eth/stagedsync/stage_mining_force_txs.go @@ -0,0 +1,28 @@ +package stagedsync + +import ( + "fmt" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/log/v3" +) + +func SpawnMiningForceTxsStage(s *StageState, tx kv.RwTx, cfg MiningCreateBlockCfg, quit <-chan struct{}) (err error) { + var forceTxs []types.Transaction + if cfg.blockBuilderParameters != nil { + log.Info("stage running - force txs, with params", + "txs", len(cfg.blockBuilderParameters.Transactions), + "notxpool", cfg.blockBuilderParameters.NoTxPool) + for i, otx := range cfg.blockBuilderParameters.Transactions { + tx, err := types.UnmarshalTransactionFromBinary(otx) + if err != nil { + return fmt.Errorf("tx %d is invalid: %v", i, err) + } + forceTxs = append(forceTxs, tx) + } + } else { + log.Info("stage running - force txs, nil params") + } + cfg.miner.MiningBlock.ForceTxs = types.NewTransactionsFixedOrder(forceTxs) + return nil +}
diff --git ledgerwatch/erigon/eth/stagedsync/stagebuilder.go testinprod-io/erigon/eth/stagedsync/stagebuilder.go index e0800d8475d0eea9c30a0e12a8a1f67730c90a3f..ced6e36902dcc7f7c2e24e418f688c46432635e8 100644 --- ledgerwatch/erigon/eth/stagedsync/stagebuilder.go +++ testinprod-io/erigon/eth/stagedsync/stagebuilder.go @@ -27,6 +27,15 @@ ) []*Stage { return []*Stage{ { ID: stages.MiningCreateBlock, + Description: "Mining: add force-txs", + Forward: func(firstCycle bool, badBlockUnwind bool, s *StageState, u Unwinder, tx kv.RwTx, quite bool) error { + return SpawnMiningForceTxsStage(s, tx, createBlockCfg, ctx.Done()) + }, + Unwind: func(firstCycle bool, u *UnwindState, s *StageState, tx kv.RwTx) error { return nil }, + Prune: func(firstCycle bool, u *PruneState, tx kv.RwTx) error { return nil }, + }, + { + ID: stages.MiningCreateBlock, Description: "Mining: construct new block from tx pool", Forward: func(firstCycle bool, badBlockUnwind bool, s *StageState, u Unwinder, tx kv.RwTx, quiet bool) error { return SpawnMiningCreateBlockStage(s, tx, createBlockCfg, ctx.Done()) @@ -40,8 +49,10 @@ Description: "Mining: construct new block from tx pool", Forward: func(firstCycle bool, badBlockUnwind bool, s *StageState, u Unwinder, tx kv.RwTx, quiet bool) error { return SpawnMiningExecStage(s, tx, execCfg, ctx.Done()) }, - Unwind: func(firstCycle bool, u *UnwindState, s *StageState, tx kv.RwTx) error { return nil }, - Prune: func(firstCycle bool, u *PruneState, tx kv.RwTx) error { return nil }, + Unwind: func(firstCycle bool, u *UnwindState, s *StageState, tx kv.RwTx) error { + return UnwindMiningExecutionStage(u, s, tx, ctx, execCfg) + }, + Prune: func(firstCycle bool, u *PruneState, tx kv.RwTx) error { return nil }, }, { ID: stages.HashState, @@ -49,8 +60,10 @@ Description: "Hash the key in the state", Forward: func(firstCycle bool, badBlockUnwind bool, s *StageState, u Unwinder, tx kv.RwTx, quiet bool) error { return SpawnHashStateStage(s, tx, hashStateCfg, ctx, quiet) }, - Unwind: func(firstCycle bool, u *UnwindState, s *StageState, tx kv.RwTx) error { return nil }, - Prune: func(firstCycle bool, u *PruneState, tx kv.RwTx) error { return nil }, + Unwind: func(firstCycle bool, u *UnwindState, s *StageState, tx kv.RwTx) error { + return UnwindHashStateStage(u, s, tx, hashStateCfg, ctx) + }, + Prune: func(firstCycle bool, u *PruneState, tx kv.RwTx) error { return nil }, }, { ID: stages.IntermediateHashes, @@ -63,8 +76,10 @@ } createBlockCfg.miner.MiningBlock.Header.Root = stateRoot return nil }, - Unwind: func(firstCycle bool, u *UnwindState, s *StageState, tx kv.RwTx) error { return nil }, - Prune: func(firstCycle bool, u *PruneState, tx kv.RwTx) error { return nil }, + Unwind: func(firstCycle bool, u *UnwindState, s *StageState, tx kv.RwTx) error { + return UnwindIntermediateHashesStage(u, s, tx, trieCfg, ctx) + }, + Prune: func(firstCycle bool, u *PruneState, tx kv.RwTx) error { return nil }, }, { ID: stages.MiningFinish,
diff --git ledgerwatch/erigon/core/block_builder_parameters.go testinprod-io/erigon/core/block_builder_parameters.go index 4fc477410f1be6bc421019d748fb941ee978d9d1..37452158b03f178061c239b51731816f5cfcc6db 100644 --- ledgerwatch/erigon/core/block_builder_parameters.go +++ testinprod-io/erigon/core/block_builder_parameters.go @@ -15,4 +15,7 @@ PrevRandao libcommon.Hash SuggestedFeeRecipient libcommon.Address Withdrawals []*types.Withdrawal PayloadId uint64 + Transactions [][]byte + NoTxPool bool + GasLimit *uint64 }
diff --git ledgerwatch/erigon/params/mining.go testinprod-io/erigon/params/mining.go index d5e0d8cc868e1df3bd259d552ddfb34d9a2fa2f6..31db69264d2c280e939e950f71fb8f9c9a6e718d 100644 --- ledgerwatch/erigon/params/mining.go +++ testinprod-io/erigon/params/mining.go @@ -11,14 +11,16 @@ )   // MiningConfig is the configuration parameters of mining. type MiningConfig struct { - Enabled bool - EnabledPOS bool - Noverify bool // Disable remote mining solution verification(only useful in ethash). - Etherbase libcommon.Address `toml:",omitempty"` // Public address for block mining rewards - SigKey *ecdsa.PrivateKey // ECDSA private key for signing blocks - Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages(only useful in ethash). - ExtraData hexutility.Bytes `toml:",omitempty"` // Block extra data set by the miner - GasLimit uint64 // Target gas limit for mined blocks. - GasPrice *big.Int // Minimum gas price for mining a transaction - Recommit time.Duration // The time interval for miner to re-create mining work. + Enabled bool + EnabledPOS bool + Noverify bool // Disable remote mining solution verification(only useful in ethash). + Etherbase libcommon.Address `toml:",omitempty"` // Public address for block mining rewards + SigKey *ecdsa.PrivateKey // ECDSA private key for signing blocks + Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages(only useful in ethash). + ExtraData hexutility.Bytes `toml:",omitempty"` // Block extra data set by the miner + GasLimit uint64 // Target gas limit for mined blocks. + GasPrice *big.Int // Minimum gas price for mining a transaction + Recommit time.Duration // The time interval for miner to re-create mining work. + Transactions [][]byte `toml:",omitempty"` + NoTxPool bool `toml:",omitempty"` }
diff --git ledgerwatch/erigon/core/chain_makers.go testinprod-io/erigon/core/chain_makers.go index 959f78073d15e0deb5f52a7e12a65281ad7669d0..c47bb59de034479131f1be937d29e4ba0b9c922f 100644 --- ledgerwatch/erigon/core/chain_makers.go +++ testinprod-io/erigon/core/chain_makers.go @@ -493,11 +493,15 @@ // Set baseFee and GasLimit if we are on an EIP-1559 chain if chainConfig.IsLondon(header.Number.Uint64()) { header.BaseFee = misc.CalcBaseFee(chainConfig, parent) 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 }
diff --git ledgerwatch/erigon/eth/stagedsync/stage_mining_exec_test.go testinprod-io/erigon/eth/stagedsync/stage_mining_exec_test.go new file mode 100644 index 0000000000000000000000000000000000000000..0e9ec0d8c1e620ae3926489850b9bf2e70575393 --- /dev/null +++ testinprod-io/erigon/eth/stagedsync/stage_mining_exec_test.go @@ -0,0 +1,67 @@ +package stagedsync + +import ( + "context" + "testing" + + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/kv/memdb" + "github.com/ledgerwatch/erigon/eth/stagedsync/stages" + "github.com/stretchr/testify/require" +) + +func TestMiningExec(t *testing.T) { + ctx, db1, db2 := context.Background(), memdb.NewTestDB(t), memdb.NewTestDB(t) + cfg := MiningExecCfg{} + + t.Run("UnwindMiningExecutionStagePlainStatic", func(t *testing.T) { + require, tx1, tx2 := require.New(t), memdb.BeginRw(t, db1), memdb.BeginRw(t, db2) + + generateBlocks(t, 1, 25, plainWriterGen(tx1), staticCodeStaticIncarnations) + generateBlocks(t, 1, 50, plainWriterGen(tx2), staticCodeStaticIncarnations) + + err := stages.SaveStageProgress(tx2, stages.MiningExecution, 50) + require.NoError(err) + + u := &UnwindState{ID: stages.MiningExecution, UnwindPoint: 25} + s := &StageState{ID: stages.MiningExecution, BlockNumber: 50} + err = UnwindMiningExecutionStage(u, s, tx2, ctx, cfg) + require.NoError(err) + + compareCurrentState(t, newAgg(t), tx1, tx2, kv.PlainState, kv.PlainContractCode, kv.ContractTEVMCode) + }) + t.Run("UnwindMiningExecutionStagePlainWithIncarnationChanges", func(t *testing.T) { + require, tx1, tx2 := require.New(t), memdb.BeginRw(t, db1), memdb.BeginRw(t, db2) + + generateBlocks(t, 1, 25, plainWriterGen(tx1), changeCodeWithIncarnations) + generateBlocks(t, 1, 50, plainWriterGen(tx2), changeCodeWithIncarnations) + + err := stages.SaveStageProgress(tx2, stages.MiningExecution, 50) + require.NoError(err) + + u := &UnwindState{ID: stages.MiningExecution, UnwindPoint: 25} + s := &StageState{ID: stages.MiningExecution, BlockNumber: 50} + err = UnwindMiningExecutionStage(u, s, tx2, ctx, cfg) + require.NoError(err) + + compareCurrentState(t, newAgg(t), tx1, tx2, kv.PlainState, kv.PlainContractCode) + }) + t.Run("UnwindMiningExecutionStagePlainWithCodeChanges", func(t *testing.T) { + t.Skip("not supported yet, to be restored") + require, tx1, tx2 := require.New(t), memdb.BeginRw(t, db1), memdb.BeginRw(t, db2) + + generateBlocks(t, 1, 25, plainWriterGen(tx1), changeCodeIndepenentlyOfIncarnations) + generateBlocks(t, 1, 50, plainWriterGen(tx2), changeCodeIndepenentlyOfIncarnations) + + err := stages.SaveStageProgress(tx2, stages.MiningExecution, 50) + if err != nil { + t.Errorf("error while saving progress: %v", err) + } + u := &UnwindState{ID: stages.MiningExecution, UnwindPoint: 25} + s := &StageState{ID: stages.MiningExecution, BlockNumber: 50} + err = UnwindMiningExecutionStage(u, s, tx2, ctx, cfg) + require.NoError(err) + + compareCurrentState(t, newAgg(t), tx1, tx2, kv.PlainState, kv.PlainContractCode) + }) +}

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

diff --git ledgerwatch/erigon/cmd/txpool/main.go testinprod-io/erigon/cmd/txpool/main.go index 138d871b7c25b6a0c9657118233c3b263d98d091..a12796d66a188d053735720d94784076b8351b5e 100644 --- ledgerwatch/erigon/cmd/txpool/main.go +++ testinprod-io/erigon/cmd/txpool/main.go @@ -53,6 +53,8 @@ priceLimit uint64 accountSlots uint64 priceBump uint64   + optimism bool + commitEvery time.Duration )   @@ -76,6 +78,7 @@ rootCmd.PersistentFlags().Uint64Var(&priceLimit, "txpool.pricelimit", txpoolcfg.DefaultConfig.MinFeeCap, "Minimum gas price (fee cap) limit to enforce for acceptance into the pool") rootCmd.PersistentFlags().Uint64Var(&accountSlots, "txpool.accountslots", txpoolcfg.DefaultConfig.AccountSlots, "Minimum number of executable transaction slots guaranteed per account") rootCmd.PersistentFlags().Uint64Var(&priceBump, "txpool.pricebump", txpoolcfg.DefaultConfig.PriceBump, "Price bump percentage to replace an already existing 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.Flags().StringSliceVar(&traceSenders, utils.TxPoolTraceSendersFlag.Name, []string{}, utils.TxPoolTraceSendersFlag.Usage) }

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 testinprod-io/erigon/cmd/utils/flags.go index 7632a637f07180416b354f7f90ef0bf7572cf208..cde9eb89d5023f4a046cb0e0ffe188698da4a245 100644 --- ledgerwatch/erigon/cmd/utils/flags.go +++ testinprod-io/erigon/cmd/utils/flags.go @@ -19,12 +19,16 @@ package utils   import ( "crypto/ecdsa" + "encoding/json" "fmt" "math/big" + "os" "path/filepath" "runtime" "strconv" "strings" + + "golang.org/x/exp/slices"   "github.com/c2h5oh/datasize" libcommon "github.com/ledgerwatch/erigon-lib/common" @@ -46,6 +50,7 @@ "github.com/ledgerwatch/erigon/cl/clparams" "github.com/ledgerwatch/erigon/cmd/downloader/downloadernat" "github.com/ledgerwatch/erigon/common/paths" "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/crypto" "github.com/ledgerwatch/erigon/eth/ethconfig" "github.com/ledgerwatch/erigon/eth/protocols/eth" @@ -592,6 +597,23 @@ Usage: "Maximum gas price will be recommended by gpo", Value: ethconfig.Defaults.GPO.MaxPrice.Int64(), }   + // Rollup Flags + RollupSequencerHTTPFlag = cli.StringFlag{ + Name: "rollup.sequencerhttp", + Usage: "HTTP endpoint for the sequencer mempool", + } + + RollupHistoricalRPCFlag = cli.StringFlag{ + Name: "rollup.historicalrpc", + Usage: "RPC endpoint for historical data.", + } + + RollupHistoricalRPCTimeoutFlag = cli.StringFlag{ + Name: "rollup.historicalrpctimeout", + Usage: "Timeout for historical RPC requests.", + Value: "5s", + } + // Metrics flags MetricsEnabledFlag = cli.BoolFlag{ Name: "metrics", @@ -773,6 +795,11 @@ SentinelPortFlag = cli.Uint64Flag{ Name: "sentinel.port", Usage: "Port for sentinel", Value: 7777, + } + GenesisPathFlag = cli.StringFlag{ + Name: "genesis.path", + Usage: "Genesis JSON file path", + Value: "/genesis.json", } )   @@ -1053,7 +1080,7 @@ cfg.Miner.SigKey = key } }   - if ctx.String(ChainFlag.Name) == networkname.DevChainName || ctx.String(ChainFlag.Name) == networkname.BorDevnetChainName { + if slices.Contains([]string{networkname.DevChainName, networkname.BorDevnetChainName, networkname.OptimismDevnetChainName}, ctx.String(ChainFlag.Name)) { if etherbase == "" { cfg.Miner.SigKey = core.DevnetSignPrivateKey cfg.Miner.Etherbase = core.DevnetEtherbase @@ -1450,6 +1477,31 @@ Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", ")) } }   +// readGenesis will read the given JSON format genesis file and return +// the initialized Genesis structure +func readGenesis(genesisPath string) *types.Genesis { + // Make sure we have a valid genesis JSON + if len(genesisPath) == 0 { + Fatalf("Must supply path to genesis JSON file") + } + file, err := os.Open(genesisPath) + if err != nil { + Fatalf("Failed to read genesis file: %v", err) + } + defer func(file *os.File) { + closeErr := file.Close() + if closeErr != nil { + log.Warn("Failed to close file", "err", closeErr) + } + }(file) + + genesis := new(types.Genesis) + if err := json.NewDecoder(file).Decode(genesis); err != nil { + Fatalf("invalid genesis file: %v", err) + } + return genesis +} + // SetEthConfig applies eth-related command line flags to the config. func SetEthConfig(ctx *cli.Context, nodeConfig *nodecfg.Config, cfg *ethconfig.Config) { cfg.LightClientDiscoveryAddr = ctx.String(LightClientDiscoveryAddrFlag.Name) @@ -1540,6 +1592,16 @@ } else { cfg.EthDiscoveryURLs = SplitAndTrim(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) + } + if ctx.IsSet(RollupHistoricalRPCTimeoutFlag.Name) { + cfg.RollupHistoricalRPCTimeout = ctx.Duration(RollupHistoricalRPCTimeoutFlag.Name) + } // Override any default configs for hard coded networks. chain := ctx.String(ChainFlag.Name)   @@ -1578,6 +1640,17 @@ log.Info("Using custom developer period", "seconds", cfg.Genesis.Config.Clique.Period) if !ctx.IsSet(MinerGasPriceFlag.Name) { cfg.Miner.GasPrice = big.NewInt(1) } + case networkname.OptimismDevnetChainName: + // Create new developer account or reuse existing one + developer := cfg.Miner.Etherbase + if developer == (libcommon.Address{}) { + Fatalf("Please specify developer account address using --miner.etherbase") + } + log.Info("Using developer account", "address", developer) + + // Create a new developer genesis block or reuse existing one + cfg.Genesis = readGenesis(ctx.String(GenesisPathFlag.Name)) + //log.Info("Using custom developer period", "seconds", cfg.Genesis.Config.Clique.Period) }   if ctx.IsSet(OverrideShanghaiTime.Name) {
diff --git ledgerwatch/erigon/turbo/cli/default_flags.go testinprod-io/erigon/turbo/cli/default_flags.go index 29ebc26b1f7de6f3a7fc55732a24983418ea8745..405d3de16b1a5549616b7578350f0249c6904ba9 100644 --- ledgerwatch/erigon/turbo/cli/default_flags.go +++ testinprod-io/erigon/turbo/cli/default_flags.go @@ -63,6 +63,7 @@ &utils.AuthRpcVirtualHostsFlag, &utils.HTTPApiFlag, &utils.WSEnabledFlag, &utils.WsCompressionFlag, + &utils.WSPortFlag, &utils.HTTPTraceFlag, &utils.StateCacheFlag, &utils.RpcBatchConcurrencyFlag, @@ -149,6 +150,9 @@ &utils.WithoutHeimdallFlag, &utils.HeimdallgRPCAddressFlag, &utils.EthStatsURLFlag, &utils.OverrideShanghaiTime, + &utils.RollupSequencerHTTPFlag, + &utils.RollupHistoricalRPCFlag, + &utils.RollupHistoricalRPCTimeoutFlag,   &utils.ConfigFlag, &logging.LogConsoleVerbosityFlag, @@ -163,4 +167,6 @@ &utils.LightClientDiscoveryPortFlag, &utils.LightClientDiscoveryTCPPortFlag, &utils.SentinelAddrFlag, &utils.SentinelPortFlag, + + &utils.GenesisPathFlag, }

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

diff --git ledgerwatch/erigon/params/version.go testinprod-io/erigon/params/version.go index e2723fb47f029189684863c21a17b3756766f700..eeb44db035c0892d76cfa99f0f282c03d3813766 100644 --- ledgerwatch/erigon/params/version.go +++ testinprod-io/erigon/params/version.go @@ -29,6 +29,7 @@ GitBranch string GitTag string )   +// Version is the version of upstream erigon // see https://calver.org const ( VersionMajor = 2 // Major version component of the current release @@ -37,38 +38,60 @@ VersionMicro = 0 // Patch version component of the current release VersionModifier = "stable" // Modifier component of the current release VersionKeyCreated = "ErigonVersionCreated" VersionKeyFinished = "ErigonVersionFinished" +) + +// OPVersion is the version of op-erigon +const ( + OPVersionMajor = 0 // Major version component of the current release + OPVersionMinor = 1 // 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 )   func withModifier(vsn string) string { if !isStable() { - vsn += "-" + VersionModifier + vsn += "-" + OPVersionModifier } return vsn }   func isStable() bool { - return VersionModifier == "stable" + return OPVersionModifier == "stable" }   func isRelease() bool { - return isStable() || VersionModifier == "alpha" || VersionModifier == "beta" + return isStable() || OPVersionModifier == "alpha" || OPVersionModifier == "beta" }   // 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 } return v }()   -// ArchiveVersion holds the textual version string used for Geth archives. +// ArchiveVersion holds the textual version string used for op-erigon archives. // e.g. "1.8.11-dea1ce05" for stable releases, or // // "1.8.13-unstable-21c059b6" for unstable releases
diff --git ledgerwatch/erigon/eth/ethconfig/config.go testinprod-io/erigon/eth/ethconfig/config.go index f3882fcb28c01d6ec853c47d0e7bad2f88695e1b..d3f37aeddc5cd5232e02269c17c5e54eb66b8984 100644 --- ledgerwatch/erigon/eth/ethconfig/config.go +++ testinprod-io/erigon/eth/ethconfig/config.go @@ -251,6 +251,10 @@ OverrideShanghaiTime *big.Int `toml:",omitempty"`   DropUselessPeers bool + + RollupSequencerHTTP string + RollupHistoricalRPC string + RollupHistoricalRPCTimeout time.Duration }   type Sync struct {
diff --git ledgerwatch/erigon/params/config.go testinprod-io/erigon/params/config.go index 281173c4cdc7a6e78da02dab2322b05aa493788b..c249d360a793f011cbebac925c5a2feafc947f83 100644 --- ledgerwatch/erigon/params/config.go +++ testinprod-io/erigon/params/config.go @@ -50,15 +50,16 @@ }   // Genesis hashes to enforce below configs on. var ( - MainnetGenesisHash = libcommon.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") - SepoliaGenesisHash = libcommon.HexToHash("0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9") - RinkebyGenesisHash = libcommon.HexToHash("0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177") - GoerliGenesisHash = libcommon.HexToHash("0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a") - MumbaiGenesisHash = libcommon.HexToHash("0x7b66506a9ebdbf30d32b43c5f15a3b1216269a1ec3a75aa3182b86176a2b1ca7") - BorMainnetGenesisHash = libcommon.HexToHash("0xa9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b") - BorDevnetGenesisHash = libcommon.HexToHash("0x5a06b25b0c6530708ea0b98a3409290e39dce6be7f558493aeb6e4b99a172a87") - GnosisGenesisHash = libcommon.HexToHash("0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756") - ChiadoGenesisHash = libcommon.HexToHash("0xada44fd8d2ecab8b08f256af07ad3e777f17fb434f8f8e678b312f576212ba9a") + MainnetGenesisHash = libcommon.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") + SepoliaGenesisHash = libcommon.HexToHash("0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9") + RinkebyGenesisHash = libcommon.HexToHash("0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177") + GoerliGenesisHash = libcommon.HexToHash("0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a") + MumbaiGenesisHash = libcommon.HexToHash("0x7b66506a9ebdbf30d32b43c5f15a3b1216269a1ec3a75aa3182b86176a2b1ca7") + BorMainnetGenesisHash = libcommon.HexToHash("0xa9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b") + BorDevnetGenesisHash = libcommon.HexToHash("0x5a06b25b0c6530708ea0b98a3409290e39dce6be7f558493aeb6e4b99a172a87") + GnosisGenesisHash = libcommon.HexToHash("0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756") + ChiadoGenesisHash = libcommon.HexToHash("0xada44fd8d2ecab8b08f256af07ad3e777f17fb434f8f8e678b312f576212ba9a") + OptimismGoerliGenesisHash = libcommon.HexToHash("0xc1fc15cd51159b1f1e5cbc4b82e85c1447ddfa33c52cf1d98d14fba0d6354be1") )   var ( @@ -125,6 +126,8 @@ BorMainnetChainConfig = readChainSpec("chainspecs/bor-mainnet.json")   BorDevnetChainConfig = readChainSpec("chainspecs/bor-devnet.json") + + OptimismGoerliChainConfig = readChainSpec("chainspecs/optimism-goerli.json")   GnosisChainConfig = readChainSpec("chainspecs/gnosis.json")   @@ -206,6 +209,8 @@ case networkname.BorMainnetChainName: return BorMainnetChainConfig case networkname.BorDevnetChainName: return BorDevnetChainConfig + case networkname.OptimismGoerliChainName: + return OptimismGoerliChainConfig case networkname.GnosisChainName: return GnosisChainConfig case networkname.ChiadoChainName: @@ -231,6 +236,8 @@ case networkname.BorMainnetChainName: return &BorMainnetGenesisHash case networkname.BorDevnetChainName: return &BorDevnetGenesisHash + case networkname.OptimismGoerliChainName: + return &OptimismGoerliGenesisHash case networkname.GnosisChainName: return &GnosisGenesisHash case networkname.ChiadoChainName: @@ -256,6 +263,8 @@ case genesisHash == BorMainnetGenesisHash: return BorMainnetChainConfig case genesisHash == BorDevnetGenesisHash: return BorDevnetChainConfig + case genesisHash == OptimismGoerliGenesisHash: + return OptimismGoerliChainConfig case genesisHash == GnosisGenesisHash: return GnosisChainConfig case genesisHash == ChiadoGenesisHash:
diff --git ledgerwatch/erigon/params/networkname/network_name.go testinprod-io/erigon/params/networkname/network_name.go index 13a9b873b7f3437652cec680e358a7c1dd8513d9..af8274d5055befba941bca7cfa828efdeddc8a0a 100644 --- ledgerwatch/erigon/params/networkname/network_name.go +++ testinprod-io/erigon/params/networkname/network_name.go @@ -1,16 +1,18 @@ package networkname   const ( - MainnetChainName = "mainnet" - SepoliaChainName = "sepolia" - RinkebyChainName = "rinkeby" - GoerliChainName = "goerli" - DevChainName = "dev" - MumbaiChainName = "mumbai" - BorMainnetChainName = "bor-mainnet" - BorDevnetChainName = "bor-devnet" - GnosisChainName = "gnosis" - ChiadoChainName = "chiado" + MainnetChainName = "mainnet" + SepoliaChainName = "sepolia" + RinkebyChainName = "rinkeby" + GoerliChainName = "goerli" + DevChainName = "dev" + MumbaiChainName = "mumbai" + BorMainnetChainName = "bor-mainnet" + BorDevnetChainName = "bor-devnet" + GnosisChainName = "gnosis" + ChiadoChainName = "chiado" + OptimismDevnetChainName = "op-dev" + OptimismGoerliChainName = "optimism-goerli" )   var All = []string{ @@ -21,6 +23,7 @@ GoerliChainName, MumbaiChainName, BorMainnetChainName, BorDevnetChainName, + OptimismGoerliChainName, GnosisChainName, ChiadoChainName, }
diff --git ledgerwatch/erigon/params/chainspecs/optimism-goerli.json testinprod-io/erigon/params/chainspecs/optimism-goerli.json new file mode 100644 index 0000000000000000000000000000000000000000..78387861502c59468fb0d6856bf904582e0b3cce --- /dev/null +++ testinprod-io/erigon/params/chainspecs/optimism-goerli.json @@ -0,0 +1,27 @@ +{ + "ChainName": "optimism-goerli", + "chainId": 420, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 4061224, + "arrowGlacierBlock": 4061224, + "grayGlacierBlock": 4061224, + "mergeNetsplitBlock": 4061224, + "bedrockBlock": 4061224, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, + "optimism": { + "eip1559Elasticity": 10, + "eip1559Denominator": 50 + }, + "regolithTime": 1679079600 +} \ No newline at end of file
diff --git ledgerwatch/erigon/core/allocs/optimism-goerli.json testinprod-io/erigon/core/allocs/optimism-goerli.json new file mode 100644 index 0000000000000000000000000000000000000000..d902fcf53200ebe0818de6910a576be054ec64f2 --- /dev/null +++ testinprod-io/erigon/core/allocs/optimism-goerli.json @@ -0,0 +1,79 @@ +{ + "0x4200000000000000000000000000000000000000": { + "balance": "00", + "storage": {}, + "code": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806382e3702d1461003b578063cafa81dc14610072575b600080fd5b61005e610049366004610112565b60006020819052908152604090205460ff1681565b604051901515815260200160405180910390f35b61008561008036600461015a565b610087565b005b6001600080833360405160200161009f929190610229565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301208352908201929092520160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905550565b60006020828403121561012457600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561016c57600080fd5b813567ffffffffffffffff8082111561018457600080fd5b818401915084601f83011261019857600080fd5b8135818111156101aa576101aa61012b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101f0576101f061012b565b8160405282815287602084870101111561020957600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000835160005b8181101561024a5760208187018101518583015201610230565b81811115610259576000828501525b5060609390931b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016919092019081526014019291505056fea26469706673582212209ffc0b44ce8a27c46cae74a3b3b620a72f10aaea97ed37c15b5d36792abd2aa464736f6c63430008090033" + }, + "0x4200000000000000000000000000000000000002": { + "balance": "00", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100725760003560e01c80639b19251a116100505780639b19251a146100e9578063b1540a011461011c578063bdc7b54f1461012f57600080fd5b806308fd63221461007757806313af40351461008c5780638da5cb5b1461009f575b600080fd5b61008a610085366004610614565b610137565b005b61008a61009a366004610650565b610271565b6000546100bf9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61010c6100f7366004610650565b60016020526000908152604090205460ff1681565b60405190151581526020016100e0565b61010c61012a366004610650565b61047c565b61008a6104cd565b60005473ffffffffffffffffffffffffffffffffffffffff1633146101e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f46756e6374696f6e2063616e206f6e6c792062652063616c6c6564206279207460448201527f6865206f776e6572206f66207468697320636f6e74726163742e00000000000060648201526084015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660008181526001602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527f8daaf060c3306c38e068a75c054bf96ecd85a3db1252712c4d93632744c42e0d910160405180910390a15050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610318576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f46756e6374696f6e2063616e206f6e6c792062652063616c6c6564206279207460448201527f6865206f776e6572206f66207468697320636f6e74726163742e00000000000060648201526084016101da565b73ffffffffffffffffffffffffffffffffffffffff81166103e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605160248201527f4f564d5f4465706c6f79657257686974656c6973743a2063616e206f6e6c792060448201527f62652064697361626c65642076696120656e61626c654172626974726172794360648201527f6f6e74726163744465706c6f796d656e74000000000000000000000000000000608482015260a4016101da565b6000546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a1600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000805473ffffffffffffffffffffffffffffffffffffffff1615806104c7575073ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090205460ff165b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610574576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f46756e6374696f6e2063616e206f6e6c792062652063616c6c6564206279207460448201527f6865206f776e6572206f66207468697320636f6e74726163742e00000000000060648201526084016101da565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681527fc0e106cf568e50698fdbde1eff56f5a5c966cc7958e37e276918e9e4ccdf8cd49060200160405180910390a1600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b803573ffffffffffffffffffffffffffffffffffffffff8116811461060f57600080fd5b919050565b6000806040838503121561062757600080fd5b610630836105eb565b91506020830135801515811461064557600080fd5b809150509250929050565b60006020828403121561066257600080fd5b61066b826105eb565b939250505056fea264697066735822122045a02b3906eca00a51b37c2965ab13be381f71f60af681951849865fb2daa75f64736f6c63430008090033" + }, + "0x4200000000000000000000000000000000000007": { + "balance": "00", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x000000000000000000000000000000000000000000000000000000000000dead", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000000005086d1eef304eb5284a0f6720f79403b4e9be294", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x00000000000000000000000000000000000000000000000000000000000186a0" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100885760003560e01c8063a71198691161005b578063a71198691461012a578063b1b1b2091461014a578063cbd4ece91461016d578063ecc704281461018057600080fd5b806321d800ec1461008d5780633dbb202b146100c55780636e296e45146100da57806382e3702d14610107575b600080fd5b6100b061009b366004610826565b60006020819052908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6100d86100d3366004610942565b610197565b005b6100e26102e2565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100bc565b6100b0610115366004610826565b60026020526000908152604090205460ff1681565b6005546100e29073ffffffffffffffffffffffffffffffffffffffff1681565b6100b0610158366004610826565b60016020526000908152604090205460ff1681565b6100d861017b3660046109ad565b61038b565b61018960035481565b6040519081526020016100bc565b60006101a784338560035461078d565b80516020808301919091206000908152600290915260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fcafa81dc0000000000000000000000000000000000000000000000000000000081529091507342000000000000000000000000000000000000009063cafa81dc9061023c908490600401610a89565b600060405180830381600087803b15801561025657600080fd5b505af115801561026a573d6000803e3d6000fd5b505050508373ffffffffffffffffffffffffffffffffffffffff167fcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a3385600354866040516102bc9493929190610aa3565b60405180910390a26001600360008282546102d79190610aef565b909155505050505050565b60045460009073ffffffffffffffffffffffffffffffffffffffff1661dead141561036e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f78446f6d61696e4d65737361676553656e646572206973206e6f74207365740060448201526064015b60405180910390fd5b5060045473ffffffffffffffffffffffffffffffffffffffff1690565b60055473ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffeeeeffffffffffffffffffffffffffffffffeeef330173ffffffffffffffffffffffffffffffffffffffff161461046a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f50726f7669646564206d65737361676520636f756c64206e6f7420626520766560448201527f7269666965642e000000000000000000000000000000000000000000000000006064820152608401610365565b60006104788585858561078d565b8051602080830191909120600081815260019092526040909120549192509060ff1615610527576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f50726f7669646564206d6573736167652068617320616c72656164792062656560448201527f6e2072656365697665642e0000000000000000000000000000000000000000006064820152608401610365565b73ffffffffffffffffffffffffffffffffffffffff8616734200000000000000000000000000000000000000141561059957600090815260016020819052604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905550610787565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff878116919091179091556040516000918816906105f2908790610b2e565b6000604051808303816000865af19150503d806000811461062f576040519150601f19603f3d011682016040523d82523d6000602084013e610634565b606091505b5050600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead1790559050801515600114156106d557600082815260016020819052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555183917f4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c91a2610701565b60405182907f99d0e048484baa1b1540b1367cb128acd7ab2946d1ed91ec10e3c85e4bf51b8f90600090a25b600083334360405160200161071893929190610b4a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181528151602092830120600090815291829052902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055505050505b50505050565b6060848484846040516024016107a69493929190610b9c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fcbd4ece9000000000000000000000000000000000000000000000000000000001790529050949350505050565b60006020828403121561083857600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461086357600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126108a857600080fd5b813567ffffffffffffffff808211156108c3576108c3610868565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561090957610909610868565b8160405283815286602085880101111561092257600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060006060848603121561095757600080fd5b6109608461083f565b9250602084013567ffffffffffffffff81111561097c57600080fd5b61098886828701610897565b925050604084013563ffffffff811681146109a257600080fd5b809150509250925092565b600080600080608085870312156109c357600080fd5b6109cc8561083f565b93506109da6020860161083f565b9250604085013567ffffffffffffffff8111156109f657600080fd5b610a0287828801610897565b949793965093946060013593505050565b60005b83811015610a2e578181015183820152602001610a16565b838111156107875750506000910152565b60008151808452610a57816020860160208601610a13565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610a9c6020830184610a3f565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff85168152608060208201526000610ad26080830186610a3f565b905083604083015263ffffffff8316606083015295945050505050565b60008219821115610b29577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b60008251610b40818460208701610a13565b9190910192915050565b60008451610b5c818460208901610a13565b60609490941b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001691909301908152601481019190915260340192915050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525060806040830152610bd56080830185610a3f565b90508260608301529594505050505056fea26469706673582212200afb9537c52292543adecf37773b8e4d795c984adf4e80970731e434679b4ec264736f6c63430008090033" + }, + "0x420000000000000000000000000000000000000F": { + "balance": "00", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000a693b8f8207ff043f6bbc2e2120bbe4c2251efe9", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000000000000000000abe", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x000000000000000000000000000000000000000000000000000000000016e360", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000000000000000000000000000000000000000000000006" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100f55760003560e01c80638c8885c811610097578063de26c4a111610066578063de26c4a1146101cc578063f2fde38b146101df578063f45e65d8146101f2578063fe173b97146101fb57600080fd5b80638c8885c81461016b5780638da5cb5b1461017e578063bede39b5146101a6578063bf1fe420146101b957600080fd5b806349948e0e116100d357806349948e0e14610134578063519b4bd3146101475780637046559714610150578063715018a61461016357600080fd5b80630c18c162146100fa578063313ce567146101165780633577afc51461011f575b600080fd5b61010360035481565b6040519081526020015b60405180910390f35b61010360055481565b61013261012d3660046108d0565b610204565b005b610103610142366004610918565b6102c6565b61010360025481565b61013261015e3660046108d0565b610322565b6101326103d8565b6101326101793660046108d0565b610465565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010d565b6101326101b43660046108d0565b61051b565b6101326101c73660046108d0565b6105d1565b6101036101da366004610918565b610687565b6101326101ed3660046109e7565b61072b565b61010360045481565b61010360015481565b60005473ffffffffffffffffffffffffffffffffffffffff16331461028a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b60038190556040518181527f32740b35c0ea213650f60d44366b4fb211c9033b50714e4a1d34e65d5beb9bb4906020015b60405180910390a150565b6000806102d283610687565b90506000600254826102e49190610a53565b90506000600554600a6102f79190610bb2565b90506000600454836103099190610a53565b905060006103178383610bbe565b979650505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610281565b60048190556040518181527f3336cd9708eaf2769a0f0dc0679f30e80f15dcd88d1921b5a16858e8b85c591a906020016102bb565b60005473ffffffffffffffffffffffffffffffffffffffff163314610459576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610281565b610463600061085b565b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610281565b60058190556040518181527fd68112a8707e326d08be3656b528c1bcc5bbbfc47f4177e2179b14d8640838c1906020016102bb565b60005473ffffffffffffffffffffffffffffffffffffffff16331461059c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610281565b60028190556040518181527f351fb23757bb5ea0546c85b7996ddd7155f96b939ebaa5ff7bc49c75f27f2c44906020016102bb565b60005473ffffffffffffffffffffffffffffffffffffffff163314610652576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610281565b60018190556040518181527ffcdccc6074c6c42e4bd578aa9870c697dc976a270968452d2b8c8dc369fae396906020016102bb565b600080805b8351811015610704578381815181106106a7576106a7610bf9565b01602001517fff00000000000000000000000000000000000000000000000000000000000000166106e4576106dd600483610c28565b91506106f2565b6106ef601083610c28565b91505b806106fc81610c40565b91505061068c565b506000600354826107159190610c28565b905061072381610440610c28565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146107ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610281565b73ffffffffffffffffffffffffffffffffffffffff811661084f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610281565b6108588161085b565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156108e257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561092a57600080fd5b813567ffffffffffffffff8082111561094257600080fd5b818401915084601f83011261095657600080fd5b813581811115610968576109686108e9565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156109ae576109ae6108e9565b816040528281528760208487010111156109c757600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000602082840312156109f957600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610a1d57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610a8b57610a8b610a24565b500290565b600181815b80851115610ae957817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610acf57610acf610a24565b80851615610adc57918102915b93841c9390800290610a95565b509250929050565b600082610b0057506001610bac565b81610b0d57506000610bac565b8160018114610b235760028114610b2d57610b49565b6001915050610bac565b60ff841115610b3e57610b3e610a24565b50506001821b610bac565b5060208310610133831016604e8410600b8410161715610b6c575081810a610bac565b610b768383610a90565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610ba857610ba8610a24565b0290505b92915050565b6000610a1d8383610af1565b600082610bf4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008219821115610c3b57610c3b610a24565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610c7257610c72610a24565b506001019056fea2646970667358221220b949ef5f9defd6c0aab6259672d00d239cb8854c9972ba1866af1c6ec6433d4c64736f6c63430008090033" + }, + "0x4200000000000000000000000000000000000010": { + "balance": "00", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000636af16bf2f682dd3109e60102b8e1a089fedaa8", + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000004200000000000000000000000000000000000007" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100675760003560e01c80633cb747bf116100505780633cb747bf146100ca578063662a633a146100ea578063a3a79548146100fd57600080fd5b806332b7006d1461006c57806336c717c114610081575b600080fd5b61007f61007a366004610d0f565b610110565b005b6001546100a19073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6000546100a19073ffffffffffffffffffffffffffffffffffffffff1681565b61007f6100f8366004610d80565b610126565b61007f61010b366004610e18565b6106c1565b61011f853333878787876106d8565b5050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1661015e60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461021d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4f564d5f58434841494e3a206d657373656e67657220636f6e7472616374207560448201527f6e61757468656e7469636174656400000000000000000000000000000000000060648201526084015b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1661025360005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16636e296e456040518163ffffffff1660e01b815260040160206040518083038186803b15801561029857600080fd5b505afa1580156102ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102d09190610e9b565b73ffffffffffffffffffffffffffffffffffffffff1614610373576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4f564d5f58434841494e3a2077726f6e672073656e646572206f662063726f7360448201527f732d646f6d61696e206d657373616765000000000000000000000000000000006064820152608401610214565b61039d877f1d1d8b6300000000000000000000000000000000000000000000000000000000610a32565b801561045357508673ffffffffffffffffffffffffffffffffffffffff1663c01e1bd66040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156103ec57600080fd5b505af1158015610400573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104249190610e9b565b73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16145b15610567576040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152602482018690528816906340c10f1990604401600060405180830381600087803b1580156104c857600080fd5b505af11580156104dc573d6000803e3d6000fd5b505050508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff167fb0444523268717a02698be47d0803aa7468c00acbed2f8bd93a0459cde61dd898888888860405161055a9493929190610f08565b60405180910390a46106b7565b600063a9f9e67560e01b8989888a89898960405160240161058e9796959493929190610f3e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526001549091506106339073ffffffffffffffffffffffffffffffffffffffff16600083610a57565b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff167f7ea89a4591614515571c2b51f5ea06494056f261c10ab1ed8c03c7590d87bce0898989896040516106ad9493929190610f08565b60405180910390a4505b5050505050505050565b6106d0863387878787876106d8565b505050505050565b6040517f9dc29fac0000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff881690639dc29fac90604401600060405180830381600087803b15801561074657600080fd5b505af115801561075a573d6000803e3d6000fd5b5050505060008773ffffffffffffffffffffffffffffffffffffffff1663c01e1bd66040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156107a857600080fd5b505af11580156107bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e09190610e9b565b9050606073ffffffffffffffffffffffffffffffffffffffff891673deaddeaddeaddeaddeaddeaddeaddeaddead000014156108d5576040517f1532ec340000000000000000000000000000000000000000000000000000000090610851908a908a908a9089908990602401610f9b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050610994565b6040517fa9f9e67500000000000000000000000000000000000000000000000000000000906109149084908c908c908c908c908b908b90602401610f3e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290505b6001546109b89073ffffffffffffffffffffffffffffffffffffffff168683610a57565b3373ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f73d170910aba9e6d50b102db522b1dbcd796216f5128b445aa2135272886497e8a8a89896040516106ad9493929190610f08565b6000610a3d83610ae8565b8015610a4e5750610a4e8383610b4c565b90505b92915050565b6000546040517f3dbb202b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690633dbb202b90610ab190869085908790600401611016565b600060405180830381600087803b158015610acb57600080fd5b505af1158015610adf573d6000803e3d6000fd5b50505050505050565b6000610b14827f01ffc9a700000000000000000000000000000000000000000000000000000000610b4c565b8015610a515750610b45827fffffffff00000000000000000000000000000000000000000000000000000000610b4c565b1592915050565b604080517fffffffff00000000000000000000000000000000000000000000000000000000831660248083019190915282518083039091018152604490910182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a7000000000000000000000000000000000000000000000000000000001790529051600091908290819073ffffffffffffffffffffffffffffffffffffffff87169061753090610c06908690611092565b6000604051808303818686fa925050503d8060008114610c42576040519150601f19603f3d011682016040523d82523d6000602084013e610c47565b606091505b5091509150602081511015610c625760009350505050610a51565b818015610c7e575080806020019051810190610c7e91906110ae565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610caa57600080fd5b50565b803563ffffffff81168114610cc157600080fd5b919050565b60008083601f840112610cd857600080fd5b50813567ffffffffffffffff811115610cf057600080fd5b602083019150836020828501011115610d0857600080fd5b9250929050565b600080600080600060808688031215610d2757600080fd5b8535610d3281610c88565b945060208601359350610d4760408701610cad565b9250606086013567ffffffffffffffff811115610d6357600080fd5b610d6f88828901610cc6565b969995985093965092949392505050565b600080600080600080600060c0888a031215610d9b57600080fd5b8735610da681610c88565b96506020880135610db681610c88565b95506040880135610dc681610c88565b94506060880135610dd681610c88565b93506080880135925060a088013567ffffffffffffffff811115610df957600080fd5b610e058a828b01610cc6565b989b979a50959850939692959293505050565b60008060008060008060a08789031215610e3157600080fd5b8635610e3c81610c88565b95506020870135610e4c81610c88565b945060408701359350610e6160608801610cad565b9250608087013567ffffffffffffffff811115610e7d57600080fd5b610e8989828a01610cc6565b979a9699509497509295939492505050565b600060208284031215610ead57600080fd5b8151610eb881610c88565b9392505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000610c7e606083018486610ebf565b600073ffffffffffffffffffffffffffffffffffffffff808a1683528089166020840152808816604084015280871660608401525084608083015260c060a0830152610f8e60c083018486610ebf565b9998505050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152610fdb608083018486610ebf565b979650505050505050565b60005b83811015611001578181015183820152602001610fe9565b83811115611010576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff841681526060602082015260008351806060840152611051816080850160208801610fe6565b63ffffffff93909316604083015250601f919091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160160800192915050565b600082516110a4818460208701610fe6565b9190910192915050565b6000602082840312156110c057600080fd5b81518015158114610eb857600080fdfea2646970667358221220df892c82e9ba0fc965240aa38614ff1bd6af4d227ce2c0e9933d7f50711a886264736f6c63430008090033" + }, + "0x4200000000000000000000000000000000000011": { + "balance": "00", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000fd1d2e729ae8eee2e146c033bf4400fe75284301" + }, + "code": "0x6080604052600436106100385760003560e01c80633ccfd60b14610044578063d3e5792b1461005b578063d4ff92181461008a57600080fd5b3661003f57005b600080fd5b34801561005057600080fd5b506100596100dc565b005b34801561006757600080fd5b5061007767d02ab486cedc000081565b6040519081526020015b60405180910390f35b34801561009657600080fd5b506000546100b79073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610081565b67d02ab486cedc000047101561019e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605760248201527f4f564d5f53657175656e6365724665655661756c743a2077697468647261776160448201527f6c20616d6f756e74206d7573742062652067726561746572207468616e206d6960648201527f6e696d756d207769746864726177616c20616d6f756e74000000000000000000608482015260a40160405180910390fd5b600080546040805160208101825283815290517fa3a795480000000000000000000000000000000000000000000000000000000081527342000000000000000000000000000000000000109363a3a79548936102309373deaddeaddeaddeaddeaddeaddeaddeaddead00009373ffffffffffffffffffffffffffffffffffffffff909216924792909190600401610264565b600060405180830381600087803b15801561024a57600080fd5b505af115801561025e573d6000803e3d6000fd5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835260208188168185015286604085015263ffffffff8616606085015260a06080850152845191508160a085015260005b828110156102cb5785810182015185820160c0015281016102af565b828111156102dd57600060c084870101525b5050601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160c001969550505050505056fea2646970667358221220387a6116dde263ea48767352a397053c8cffa776aecb43cded2f25a4a9cfbdc264736f6c63430008090033" + }, + "0x4200000000000000000000000000000000000012": { + "balance": "00", + "storage": {}, + "code": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063896f93d114610030575b600080fd5b61004361003e36600461025f565b610045565b005b73ffffffffffffffffffffffffffffffffffffffff83166100c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d7573742070726f76696465204c3120746f6b656e2061646472657373000000604482015260640160405180910390fd5b60007342000000000000000000000000000000000000108484846040516100ec90610178565b6100f99493929190610359565b604051809103906000f080158015610115573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fceeb8e7d520d7f3b65fc11a262b91066940193b05d4f93df07cfdced0eb551cf60405160405180910390a350505050565b6113d7806103b083390190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126101c557600080fd5b813567ffffffffffffffff808211156101e0576101e0610185565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561022657610226610185565b8160405283815286602085880101111561023f57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060006060848603121561027457600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461029857600080fd5b9250602084013567ffffffffffffffff808211156102b557600080fd5b6102c1878388016101b4565b935060408601359150808211156102d757600080fd5b506102e4868287016101b4565b9150509250925092565b6000815180845260005b81811015610314576020818501810151868301820152016102f8565b81811115610326576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600073ffffffffffffffffffffffffffffffffffffffff80871683528086166020840152506080604083015261039260808301856102ee565b82810360608401526103a481856102ee565b97965050505050505056fe60806040523480156200001157600080fd5b50604051620013d7380380620013d783398101604081905262000034916200022f565b8151829082906200004d9060039060208501906200009f565b508051620000639060049060208401906200009f565b5050600580546001600160a01b039586166001600160a01b031991821617909155600680549690951695169490941790925550620002fc915050565b828054620000ad90620002bf565b90600052602060002090601f016020900481019282620000d157600085556200011c565b82601f10620000ec57805160ff19168380011785556200011c565b828001600101855582156200011c579182015b828111156200011c578251825591602001919060010190620000ff565b506200012a9291506200012e565b5090565b5b808211156200012a57600081556001016200012f565b80516001600160a01b03811681146200015d57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200018a57600080fd5b81516001600160401b0380821115620001a757620001a762000162565b604051601f8301601f19908116603f01168101908282118183101715620001d257620001d262000162565b81604052838152602092508683858801011115620001ef57600080fd5b600091505b83821015620002135785820183015181830184015290820190620001f4565b83821115620002255760008385830101525b9695505050505050565b600080600080608085870312156200024657600080fd5b620002518562000145565b9350620002616020860162000145565b60408601519093506001600160401b03808211156200027f57600080fd5b6200028d8883890162000178565b93506060870151915080821115620002a457600080fd5b50620002b38782880162000178565b91505092959194509250565b600181811c90821680620002d457607f821691505b60208210811415620002f657634e487b7160e01b600052602260045260246000fd5b50919050565b6110cb806200030c6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c806370a0823111610097578063a9059cbb11610066578063a9059cbb14610215578063ae1f6aaf14610228578063c01e1bd61461026d578063dd62ed3e1461028d57600080fd5b806370a08231146101b157806395d89b41146101e75780639dc29fac146101ef578063a457c2d71461020257600080fd5b806323b872dd116100d357806323b872dd14610167578063313ce5671461017a578063395093511461018957806340c10f191461019c57600080fd5b806301ffc9a71461010557806306fdde031461012d578063095ea7b31461014257806318160ddd14610155575b600080fd5b610118610113366004610e4a565b6102d3565b60405190151581526020015b60405180910390f35b610135610393565b6040516101249190610e93565b610118610150366004610f2f565b610425565b6002545b604051908152602001610124565b610118610175366004610f59565b61043b565b60405160128152602001610124565b610118610197366004610f2f565b61050c565b6101af6101aa366004610f2f565b610555565b005b6101596101bf366004610f95565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61013561061a565b6101af6101fd366004610f2f565b610629565b610118610210366004610f2f565b6106e2565b610118610223366004610f2f565b6107a0565b6006546102489073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610124565b6005546102489073ffffffffffffffffffffffffffffffffffffffff1681565b61015961029b366004610fb0565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b60007f01ffc9a7a5cef8baa21ed3c5c0d7e23accb804b619e9333b597f47a0d84076e27f1d1d8b63000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000084167f01ffc9a700000000000000000000000000000000000000000000000000000000148061038b57507fffffffff00000000000000000000000000000000000000000000000000000000848116908216145b949350505050565b6060600380546103a290610fe3565b80601f01602080910402602001604051908101604052809291908181526020018280546103ce90610fe3565b801561041b5780601f106103f05761010080835404028352916020019161041b565b820191906000526020600020905b8154815290600101906020018083116103fe57829003601f168201915b5050505050905090565b60006104323384846107ad565b50600192915050565b600061044884848461092d565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600160209081526040808320338452909152902054828110156104f45760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206160448201527f6c6c6f77616e636500000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61050185338584036107ad565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091610432918590610550908690611066565b6107ad565b60065473ffffffffffffffffffffffffffffffffffffffff1633146105bc5760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79204c32204272696467652063616e206d696e7420616e64206275726e60448201526064016104eb565b6105c68282610b93565b8173ffffffffffffffffffffffffffffffffffffffff167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858260405161060e91815260200190565b60405180910390a25050565b6060600480546103a290610fe3565b60065473ffffffffffffffffffffffffffffffffffffffff1633146106905760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79204c32204272696467652063616e206d696e7420616e64206275726e60448201526064016104eb565b61069a8282610c99565b8173ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca58260405161060e91815260200190565b33600090815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152812054828110156107895760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084016104eb565b61079633858584036107ad565b5060019392505050565b600061043233848461092d565b73ffffffffffffffffffffffffffffffffffffffff83166108355760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f726573730000000000000000000000000000000000000000000000000000000060648201526084016104eb565b73ffffffffffffffffffffffffffffffffffffffff82166108be5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f737300000000000000000000000000000000000000000000000000000000000060648201526084016104eb565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff83166109b65760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f647265737300000000000000000000000000000000000000000000000000000060648201526084016104eb565b73ffffffffffffffffffffffffffffffffffffffff8216610a3f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f657373000000000000000000000000000000000000000000000000000000000060648201526084016104eb565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610adb5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e6365000000000000000000000000000000000000000000000000000060648201526084016104eb565b73ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220858503905591851681529081208054849290610b1f908490611066565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610b8591815260200190565b60405180910390a350505050565b73ffffffffffffffffffffffffffffffffffffffff8216610bf65760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016104eb565b8060026000828254610c089190611066565b909155505073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054839290610c42908490611066565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216610d225760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f730000000000000000000000000000000000000000000000000000000000000060648201526084016104eb565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015610dbe5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016104eb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290610dfa90849061107e565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001610920565b600060208284031215610e5c57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610e8c57600080fd5b9392505050565b600060208083528351808285015260005b81811015610ec057858101830151858201604001528201610ea4565b81811115610ed2576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610f2a57600080fd5b919050565b60008060408385031215610f4257600080fd5b610f4b83610f06565b946020939093013593505050565b600080600060608486031215610f6e57600080fd5b610f7784610f06565b9250610f8560208501610f06565b9150604084013590509250925092565b600060208284031215610fa757600080fd5b610e8c82610f06565b60008060408385031215610fc357600080fd5b610fcc83610f06565b9150610fda60208401610f06565b90509250929050565b600181811c90821680610ff757607f821691505b60208210811415611031577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561107957611079611037565b500190565b60008282101561109057611090611037565b50039056fea264697066735822122069a2d33039157f3f2f180571262ca2a5d0a3a24d33bf9448f3b7c2ce9ff757f964736f6c63430008090033a2646970667358221220d2e13f28319115807ec7308d1cd88642a8542d0b838e00b8769f8a85d696f26764736f6c63430008090033" + }, + "0x4200000000000000000000000000000000000013": { + "balance": "00", + "storage": {}, + "code": "0x4B60005260206000F3" + }, + "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000": { + "balance": "00", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000004200000000000000000000000000000000000010", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x457468657200000000000000000000000000000000000000000000000000000a", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x4554480000000000000000000000000000000000000000000000000000000006" + }, + "code": "0x608060405234801561001057600080fd5b50600436106101005760003560e01c806370a0823111610097578063a9059cbb11610066578063a9059cbb14610215578063ae1f6aaf14610228578063c01e1bd61461026d578063dd62ed3e1461028d57600080fd5b806370a08231146101b157806395d89b41146101e75780639dc29fac146101ef578063a457c2d71461020257600080fd5b806323b872dd116100d357806323b872dd14610167578063313ce5671461017a578063395093511461018957806340c10f191461019c57600080fd5b806301ffc9a71461010557806306fdde031461012d578063095ea7b31461014257806318160ddd14610155575b600080fd5b610118610113366004610c6d565b6102d3565b60405190151581526020015b60405180910390f35b610135610393565b6040516101249190610cb6565b610118610150366004610d52565b610425565b6002545b604051908152602001610124565b610118610175366004610d7c565b6104db565b60405160128152602001610124565b610118610197366004610d52565b61058c565b6101af6101aa366004610d52565b61063d565b005b6101596101bf366004610db8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61013561071c565b6101af6101fd366004610d52565b61072b565b610118610210366004610d52565b6107fe565b610118610223366004610d52565b6108af565b6006546102489073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610124565b6005546102489073ffffffffffffffffffffffffffffffffffffffff1681565b61015961029b366004610dd3565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b60007f01ffc9a7a5cef8baa21ed3c5c0d7e23accb804b619e9333b597f47a0d84076e27f1d1d8b63000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000084167f01ffc9a700000000000000000000000000000000000000000000000000000000148061038b57507fffffffff00000000000000000000000000000000000000000000000000000000848116908216145b949350505050565b6060600380546103a290610e06565b80601f01602080910402602001604051908101604052809291908181526020018280546103ce90610e06565b801561041b5780601f106103f05761010080835404028352916020019161041b565b820191906000526020600020905b8154815290600101906020018083116103fe57829003601f168201915b5050505050905090565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f4f564d5f4554483a20617070726f76652069732064697361626c65642070656e60448201527f64696e67206675727468657220636f6d6d756e6974792064697363757373696f60648201527f6e2e000000000000000000000000000000000000000000000000000000000000608482015260009060a4015b60405180910390fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604760248201527f4f564d5f4554483a207472616e7366657246726f6d2069732064697361626c6560448201527f642070656e64696e67206675727468657220636f6d6d756e697479206469736360648201527f757373696f6e2e00000000000000000000000000000000000000000000000000608482015260009060a4016104d2565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f4f564d5f4554483a20696e637265617365416c6c6f77616e636520697320646960448201527f7361626c65642070656e64696e67206675727468657220636f6d6d756e69747960648201527f2064697363757373696f6e2e0000000000000000000000000000000000000000608482015260009060a4016104d2565b60065473ffffffffffffffffffffffffffffffffffffffff1633146106be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f6e6c79204c32204272696467652063616e206d696e7420616e64206275726e60448201526064016104d2565b6106c88282610960565b8173ffffffffffffffffffffffffffffffffffffffff167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858260405161071091815260200190565b60405180910390a25050565b6060600480546103a290610e06565b60065473ffffffffffffffffffffffffffffffffffffffff1633146107ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f6e6c79204c32204272696467652063616e206d696e7420616e64206275726e60448201526064016104d2565b6107b68282610a80565b8173ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca58260405161071091815260200190565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604c60248201527f4f564d5f4554483a206465637265617365416c6c6f77616e636520697320646960448201527f7361626c65642070656e64696e67206675727468657220636f6d6d756e69747960648201527f2064697363757373696f6e2e0000000000000000000000000000000000000000608482015260009060a4016104d2565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604360248201527f4f564d5f4554483a207472616e736665722069732064697361626c656420706560448201527f6e64696e67206675727468657220636f6d6d756e69747920646973637573736960648201527f6f6e2e0000000000000000000000000000000000000000000000000000000000608482015260009060a4016104d2565b73ffffffffffffffffffffffffffffffffffffffff82166109dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016104d2565b80600260008282546109ef9190610e89565b909155505073ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604081208054839290610a29908490610e89565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216610b23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f730000000000000000000000000000000000000000000000000000000000000060648201526084016104d2565b73ffffffffffffffffffffffffffffffffffffffff821660009081526020819052604090205481811015610bd9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016104d2565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120838303905560028054849290610c15908490610ea1565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b600060208284031215610c7f57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610caf57600080fd5b9392505050565b600060208083528351808285015260005b81811015610ce357858101830151858201604001528201610cc7565b81811115610cf5576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d4d57600080fd5b919050565b60008060408385031215610d6557600080fd5b610d6e83610d29565b946020939093013593505050565b600080600060608486031215610d9157600080fd5b610d9a84610d29565b9250610da860208501610d29565b9150604084013590509250925092565b600060208284031215610dca57600080fd5b610caf82610d29565b60008060408385031215610de657600080fd5b610def83610d29565b9150610dfd60208401610d29565b90509250929050565b600181811c90821680610e1a57607f821691505b60208210811415610e54577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115610e9c57610e9c610e5a565b500190565b600082821015610eb357610eb3610e5a565b50039056fea2646970667358221220b71535a5111461b42945e5d842957b3a5926f7ed07d271872f6da21952b5f8b464736f6c63430008090033" + }, + "0x4200000000000000000000000000000000000006": { + "balance": "00", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x577261707065642045746865720000000000000000000000000000000000001a", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x5745544800000000000000000000000000000000000000000000000000000008", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000012" + }, + "code": "0x6080604052600436106100bc5760003560e01c8063313ce56711610074578063a9059cbb1161004e578063a9059cbb146102cb578063d0e30db0146100bc578063dd62ed3e14610311576100bc565b8063313ce5671461024b57806370a082311461027657806395d89b41146102b6576100bc565b806318160ddd116100a557806318160ddd146101aa57806323b872dd146101d15780632e1a7d4d14610221576100bc565b806306fdde03146100c6578063095ea7b314610150575b6100c4610359565b005b3480156100d257600080fd5b506100db6103a8565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101155781810151838201526020016100fd565b50505050905090810190601f1680156101425780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015c57600080fd5b506101966004803603604081101561017357600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610454565b604080519115158252519081900360200190f35b3480156101b657600080fd5b506101bf6104c7565b60408051918252519081900360200190f35b3480156101dd57600080fd5b50610196600480360360608110156101f457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013590911690604001356104cb565b34801561022d57600080fd5b506100c46004803603602081101561024457600080fd5b503561066b565b34801561025757600080fd5b50610260610700565b6040805160ff9092168252519081900360200190f35b34801561028257600080fd5b506101bf6004803603602081101561029957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610709565b3480156102c257600080fd5b506100db61071b565b3480156102d757600080fd5b50610196600480360360408110156102ee57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610793565b34801561031d57600080fd5b506101bf6004803603604081101561033457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169160200135166107a7565b33600081815260036020908152604091829020805434908101909155825190815291517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9281900390910190a2565b6000805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561044c5780601f106104215761010080835404028352916020019161044c565b820191906000526020600020905b81548152906001019060200180831161042f57829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b4790565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120548211156104fd57600080fd5b73ffffffffffffffffffffffffffffffffffffffff84163314801590610573575073ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14155b156105ed5773ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020548211156105b557600080fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020805483900390555b73ffffffffffffffffffffffffffffffffffffffff808516600081815260036020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060019392505050565b3360009081526003602052604090205481111561068757600080fd5b33600081815260036020526040808220805485900390555183156108fc0291849190818181858888f193505050501580156106c6573d6000803e3d6000fd5b5060408051828152905133917f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65919081900360200190a250565b60025460ff1681565b60036020526000908152604090205481565b60018054604080516020600284861615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152929183018282801561044c5780601f106104215761010080835404028352916020019161044c565b60006107a03384846104cb565b9392505050565b60046020908152600092835260408084209091529082529020548156fea265627a7a7231582091c18790e0cca5011d2518024840ee00fecc67e11f56fd746f2cf84d5b583e0064736f6c63430005110032" + } +} \ No newline at end of file

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 testinprod-io/erigon/core/types/receipt.go index a8605e5676ecde05ca6b730bb769bdd3697acdb5..5aeb8def4da4018cb826e6997b7d36c7e48777c8 100644 --- ledgerwatch/erigon/core/types/receipt.go +++ testinprod-io/erigon/core/types/receipt.go @@ -23,6 +23,9 @@ "fmt" "io" "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/hexutility"   @@ -69,6 +72,20 @@ // 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"` + + // 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. }   type receiptMarshaling struct { @@ -79,6 +96,12 @@ CumulativeGasUsed hexutil.Uint64 GasUsed hexutil.Uint64 BlockNumber *hexutil.Big TransactionIndex hexutil.Uint + + // Optimism: extend receipts with their L1 price (if a rollup tx) + L1GasPrice *hexutil.Big + L1GasUsed *hexutil.Big + L1Fee *hexutil.Big + FeeScalar *big.Float }   // receiptRLP is the consensus encoding of a receipt. @@ -89,11 +112,24 @@ 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"` +} + // 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"` }   // v4StoredReceiptRLP is the storage encoding of a receipt used in database version 4. @@ -132,6 +168,10 @@ } return r }   +func (r Receipt) IsDepositTxReceipt() bool { + return r.Type == DepositTxType +} + // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt // into an RLP stream. If no post state is present, byzantium fork is assumed. func (r Receipt) EncodeRLP(w io.Writer) error { @@ -141,8 +181,15 @@ 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 { + withNonce := &depositReceiptRlp{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs, r.DepositNonce} + if err := rlp.Encode(buf, withNonce); err != nil { + return err + } + } else { + if err := rlp.Encode(buf, data); err != nil { + return err + } } return rlp.Encode(w, buf.Bytes()) } @@ -215,6 +262,17 @@ } 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 + } + } if err := s.ListEnd(); err != nil { return fmt.Errorf("close receipt payload: %w", err) } @@ -247,7 +305,7 @@ return fmt.Errorf("%w, got %d bytes", rlp.ErrWrongTxTypePrefix, len(b)) } r.Type = b[0] switch r.Type { - case AccessListTxType, DynamicFeeTxType: + case AccessListTxType, DynamicFeeTxType, DepositTxType: if err := r.decodePayload(s); err != nil { return err } @@ -333,6 +391,7 @@ enc := &storedReceiptRLP{ PostStateOrStatus: (*Receipt)(r).statusEncoding(), CumulativeGasUsed: r.CumulativeGasUsed, Logs: make([]*LogForStorage, len(r.Logs)), + DepositNonce: r.DepositNonce, } for i, log := range r.Logs { enc.Logs[i] = (*LogForStorage)(log) @@ -374,6 +433,9 @@ 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 + }   return nil } @@ -443,6 +505,11 @@ w.WriteByte(DynamicFeeTxType) if err := rlp.Encode(w, data); err != nil { panic(err) } + case DepositTxType: + w.WriteByte(DepositTxType) + if err := rlp.Encode(w, data); err != nil { + panic(err) + } default: // For unsupported types, write nothing. Since this is for // DeriveSha, the error will be caught matching the derived hash @@ -452,7 +519,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)) @@ -475,7 +542,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 { @@ -491,6 +562,28 @@ 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 + if data := txs[0].GetData(); len(data) >= 4+32*8 { // function selector + 8 arguments to setL1BlockValues + l1Basefee := new(uint256.Int).SetBytes(data[4+32*2 : 4+32*3]) // arg index 2 + overhead := new(uint256.Int).SetBytes(data[4+32*6 : 4+32*7]) // arg index 6 + scalar := new(uint256.Int).SetBytes(data[4+32*7 : 4+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) + for i := 0; i < len(r); i++ { + if tx, ok := txs[i].(RollupMessage); ok && !tx.IsDepositTx() { + rollupDataGas := tx.RollupDataGas().DataGas(time, config) // Only fake txs for RPC view-calls are 0. + + r[i].L1GasPrice = l1Basefee.ToBig() + r[i].L1GasUsed = new(big.Int).SetUint64(rollupDataGas) + r[i].L1Fee = L1Cost(rollupDataGas, l1Basefee, overhead, scalar).ToBig() + r[i].FeeScalar = feeScalar + } + } + } else { + return fmt.Errorf("L1 info tx only has %d bytes, cannot read gas price parameters", len(data)) } } return nil
diff --git ledgerwatch/erigon/core/types/receipt_test.go testinprod-io/erigon/core/types/receipt_test.go index 07304a222579440af57ed4701c3928f2ed17789d..007ea72f654a09f770325727b75410daeea3e178 100644 --- ledgerwatch/erigon/core/types/receipt_test.go +++ testinprod-io/erigon/core/types/receipt_test.go @@ -19,6 +19,8 @@ import ( "bytes" "errors" + "fmt" + "github.com/stretchr/testify/require" "math" "math/big" "reflect" @@ -34,6 +36,95 @@ "github.com/ledgerwatch/erigon/params" "github.com/ledgerwatch/erigon/rlp" )   +var ( + 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, + 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, + } +) + func TestDecodeEmptyTypedReceipt(t *testing.T) { input := []byte{0x80} var r Receipt @@ -158,7 +249,12 @@ }, GasPrice: uint256.NewInt(3), }, }, + &DepositTx{ + Value: uint256.NewInt(3), + Gas: 4, + }, } + depNonce := uint64(7) // Create the corresponding receipts receipts := Receipts{ &Receipt{ @@ -194,14 +290,35 @@ }, 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, + DepositNonce: &depNonce, }, } + + nonces := []uint64{ + txs[0].GetNonce(), + txs[1].GetNonce(), + txs[2].GetNonce(), + *receipts[3].DepositNonce, // Deposit tx should use deposit nonce + } // 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})}); err != nil { t.Fatalf("DeriveFields(...) = %v, want <nil>", err) } // Iterate over all the computed fields and check that they're correct @@ -231,7 +348,7 @@ 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()) } @@ -327,3 +444,99 @@ 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) +} + +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}, + } + 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) + }) + + 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}, + } + 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) + }) + } +}
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_receipts.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_receipts.go index bb9cd66eea9c1f5fac4aa10607330580e44eba6b..249714aaf7012c129523f0867a6810fa299f3955 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_receipts.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_receipts.go @@ -37,7 +37,7 @@ "github.com/ledgerwatch/erigon/turbo/transactions" )   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(api._chainConfig.Load(), tx, block, senders); cached != nil { return cached, nil } engine := api.engine() @@ -764,6 +764,18 @@ // 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) + fields["l1FeeScalar"] = receipt.FeeScalar + } else if receipt.DepositNonce != nil { + fields["depositNonce"] = hexutil.Uint64(*receipt.DepositNonce) + } + } + return fields }
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/erigon_receipts_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/erigon_receipts_test.go index 92415eda21c12abb4c6088bb27e1c61e18c6881f..200600ebf4adbbc587cb688d9c6e7bfd865b1356 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/erigon_receipts_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/erigon_receipts_test.go @@ -32,7 +32,7 @@ assert := assert.New(t) m, _, _ := rpcdaemontest.CreateTestSentry(t) br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) agg := m.HistoryV3Components() - baseApi := NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + baseApi := NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) { ethApi := NewEthAPI(baseApi, m.DB, nil, nil, nil, 5000000, 100_000)   @@ -67,7 +67,7 @@ br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) db := m.DB agg := m.HistoryV3Components() - api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), db, nil) + api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), db, nil) expectedLogs, _ := api.GetLogs(m.Ctx, filters.FilterCriteria{FromBlock: big.NewInt(0), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())})   expectedErigonLogs := make([]*types.ErigonLog, 0) @@ -102,7 +102,7 @@ br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) db := m.DB agg := m.HistoryV3Components() - api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), db, nil) + api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), db, nil) expectedLogs, _ := api.GetLogs(m.Ctx, filters.FilterCriteria{FromBlock: big.NewInt(0), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())})   expectedErigonLogs := make([]*types.ErigonLog, 0) @@ -192,7 +192,7 @@ m := mockWithGenerator(t, 4, generator) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil) + api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil)   expect := map[uint64]string{ 0: `[]`,
diff --git ledgerwatch/erigon/accounts/abi/bind/backends/simulated.go testinprod-io/erigon/accounts/abi/bind/backends/simulated.go index 3c401323422f4ed1891f4940ad86c775e8035584..a9f7cef5d6c9d602796201adef43a9aa362b14e6 100644 --- ledgerwatch/erigon/accounts/abi/bind/backends/simulated.go +++ testinprod-io/erigon/accounts/abi/bind/backends/simulated.go @@ -84,6 +84,8 @@ rmLogsFeed event.Feed chainFeed event.Feed logsFeed event.Feed + + chainCfg *chain.Config }   // NewSimulatedBackend creates a new binding backend using a simulated blockchain @@ -104,6 +106,7 @@ panic(err) } return h }, + chainCfg: config, } backend.emptyPendingBlock() return backend @@ -264,7 +267,7 @@ if err != nil { return nil, err } defer tx.Rollback() - receipt, _, _, _, err := rawdb.ReadReceipt(tx, txHash) + receipt, _, _, _, err := rawdb.ReadReceipt(b.chainCfg, tx, txHash) return receipt, err }   @@ -690,6 +693,7 @@ txContext := core.NewEVMTxContext(msg) header := block.Header() excessDataGas := header.ParentExcessDataGas(b.getHeader) evmContext := core.NewEVMBlockContext(header, core.GetHashFn(header, b.getHeader), b.m.Engine, nil, excessDataGas) + evmContext.L1CostFunc = types.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{}) @@ -792,18 +796,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) RollupDataGas() types.RollupGasData { return types.RollupGasData{} } +func (m callMsg) IsDepositTx() bool { return false } +func (m callMsg) IsSystemTx() bool { return false }   func (m callMsg) DataGas() uint64 { return params.DataGasPerBlob * uint64(len(m.CallMsg.DataHashes)) } func (m callMsg) MaxFeePerDataGas() *uint256.Int { return m.CallMsg.MaxFeePerDataGas } @@ -846,7 +855,7 @@ b, senders, err := rawdb.ReadBlockWithSenders(tx, hash, *number) if err != nil { return nil, err } - return rawdb.ReadReceipts(tx, b, senders), nil + return rawdb.ReadReceipts(fb.b.chainCfg, tx, b, senders), nil }   func (fb *filterBackend) GetLogs(ctx context.Context, hash libcommon.Hash) ([][]*types.Log, error) { @@ -867,7 +876,7 @@ b, senders, err := rawdb.ReadBlockWithSenders(tx, hash, *number) if err != nil { return nil, err } - receipts := rawdb.ReadReceipts(tx, b, senders) + receipts := rawdb.ReadReceipts(fb.b.chainCfg, tx, b, senders) if receipts == nil { return nil, nil }
diff --git ledgerwatch/erigon/core/rawdb/accessors_chain.go testinprod-io/erigon/core/rawdb/accessors_chain.go index 6cfe67ea4b6c4bc8a3df3789dd38e2106a1f31a5..3b8a2c9681d14fce6f1a8ebd1ffe481f2413294d 100644 --- ledgerwatch/erigon/core/rawdb/accessors_chain.go +++ testinprod-io/erigon/core/rawdb/accessors_chain.go @@ -22,6 +22,7 @@ "context" "encoding/binary" "encoding/json" "fmt" + "github.com/ledgerwatch/erigon-lib/chain" "math" "math/big" "time" @@ -1027,7 +1028,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 []libcommon.Address) types.Receipts { +func ReadReceipts(config *chain.Config, db kv.Tx, block *types.Block, senders []libcommon.Address) types.Receipts { if block == nil { return nil } @@ -1039,14 +1040,14 @@ } if len(senders) > 0 { block.SendersToTxs(senders) } - 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 } return receipts }   -func ReadReceiptsByHash(db kv.Tx, hash libcommon.Hash) (types.Receipts, error) { +func ReadReceiptsByHash(config *chain.Config, db kv.Tx, hash libcommon.Hash) (types.Receipts, error) { number := ReadHeaderNumber(db, hash) if number == nil { return nil, nil @@ -1062,11 +1063,23 @@ } if b == nil { return nil, nil } - receipts := ReadReceipts(db, b, s) + receipts := ReadReceipts(config, db, b, s) if receipts == nil { return nil, nil } return receipts, nil +} + +func ReadDepositNonces(db kv.Tx, blockNumber uint64) []*uint64 { + receipts := ReadRawReceipts(db, blockNumber) + if receipts == nil { + return nil + } + depositNonces := make([]*uint64, len(receipts)) + for i, r := range receipts { + depositNonces[i] = r.DepositNonce + } + return depositNonces }   // WriteReceipts stores all the transaction receipts belonging to a block.
diff --git ledgerwatch/erigon/core/rawdb/accessors_chain_test.go testinprod-io/erigon/core/rawdb/accessors_chain_test.go index d032ee01056e8c1ce3db551bf68abb288734af6a..8e1f23ef9ea5f69283674d57d86f316454663080 100644 --- ledgerwatch/erigon/core/rawdb/accessors_chain_test.go +++ testinprod-io/erigon/core/rawdb/accessors_chain_test.go @@ -388,7 +388,7 @@ hash := header.Hash() //libcommon.BytesToHash([]byte{0x03, 0x14}) b, senders, err := ReadBlockWithSenders(tx, hash, 0) require.NoError(err) //require.NotNil(t, b) - if rs := ReadReceipts(tx, b, senders); len(rs) != 0 { + if rs := ReadReceipts(params.TestChainConfig, tx, b, senders); len(rs) != 0 { t.Fatalf("non existent receipts returned: %v", rs) }   @@ -403,7 +403,7 @@ b, senders, err = ReadBlockWithSenders(tx, hash, 0) require.NoError(err) require.NotNil(b) - if rs := ReadReceipts(tx, b, senders); len(rs) == 0 { + if rs := ReadReceipts(params.TestChainConfig, tx, b, senders); len(rs) == 0 { t.Fatalf("no receipts returned") } else { if err := checkReceiptsRLP(rs, receipts); err != nil { @@ -416,7 +416,7 @@ deleteBody(tx, hash, 0) b, senders, err = ReadBlockWithSenders(tx, hash, 0) require.NoError(err) require.Nil(b) - if rs := ReadReceipts(tx, b, senders); rs != nil { + if rs := 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 @@ -430,7 +430,7 @@ require.NoError(TruncateReceipts(tx, 0)) b, senders, err = ReadBlockWithSenders(tx, hash, 0) require.NoError(err) require.NotNil(b) - if rs := ReadReceipts(tx, b, senders); len(rs) != 0 { + if rs := ReadReceipts(params.TestChainConfig, tx, b, senders); len(rs) != 0 { t.Fatalf("deleted receipts returned: %v", rs) } }
diff --git ledgerwatch/erigon/core/rawdb/accessors_indexes.go testinprod-io/erigon/core/rawdb/accessors_indexes.go index bf7c504b945a4e6f72102d2fa839d192787901e7..06d15ad756dd33c9b62c92b7ae8ab345329739cf 100644 --- ledgerwatch/erigon/core/rawdb/accessors_indexes.go +++ testinprod-io/erigon/core/rawdb/accessors_indexes.go @@ -17,6 +17,7 @@ package rawdb   import ( + "github.com/ledgerwatch/erigon-lib/chain" "math/big"   libcommon "github.com/ledgerwatch/erigon-lib/common" @@ -129,7 +130,7 @@ log.Error("Transaction not found", "number", blockNumber, "hash", blockHash, "txhash", hash) return nil, libcommon.Hash{}, 0, 0, nil }   -func ReadReceipt(db kv.Tx, txHash libcommon.Hash) (*types.Receipt, libcommon.Hash, uint64, uint64, error) { +func ReadReceipt(config *chain.Config, db kv.Tx, txHash libcommon.Hash) (*types.Receipt, libcommon.Hash, uint64, uint64, error) { // Retrieve the context of the receipt based on the transaction hash blockNumber, err := ReadTxLookupEntry(db, txHash) if err != nil { @@ -150,7 +151,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 := ReadReceipts(db, b, senders) + receipts := ReadReceipts(config, db, b, senders) for receiptIndex, receipt := range receipts { if receipt.TxHash == txHash { return receipt, blockHash, *blockNumber, uint64(receiptIndex), nil
diff --git ledgerwatch/erigon/ethdb/cbor/pool.go testinprod-io/erigon/ethdb/cbor/pool.go index 8e483d5bbb6eb3b9e37fd283a4bb14ebdb34239d..ac1ca00f60b686300dae3bc0efb9b6f4e144d44d 100644 --- ledgerwatch/erigon/ethdb/cbor/pool.go +++ testinprod-io/erigon/ethdb/cbor/pool.go @@ -3,6 +3,8 @@ import ( "fmt" "io" + "math/big" + "reflect"   "github.com/ledgerwatch/log/v3" "github.com/ugorji/go/codec" @@ -23,6 +25,8 @@ { var handle codec.CborHandle handle.ReaderBufferSize = 64 * 1024 handle.ZeroCopy = true // if you need access to object outside of db transaction - please copy bytes before deserialization + handle.SetInterfaceExt(bigIntType, 1, BigIntExt{}) + handle.SetInterfaceExt(bigFloatType, 2, BigFloatExt{}) d = codec.NewDecoder(r, &handle) } } @@ -39,6 +43,8 @@ { var handle codec.CborHandle handle.ReaderBufferSize = 64 * 1024 handle.ZeroCopy = true // if you need access to object outside of db transaction - please copy bytes before deserialization + handle.SetInterfaceExt(bigIntType, 1, BigIntExt{}) + handle.SetInterfaceExt(bigFloatType, 2, BigFloatExt{}) d = codec.NewDecoderBytes(r, &handle) } } @@ -68,6 +74,8 @@ handle.WriterBufferSize = 64 * 1024 handle.StructToArray = true handle.OptimumSize = true handle.StringToRaw = true + handle.SetInterfaceExt(bigIntType, 1, BigIntExt{}) + handle.SetInterfaceExt(bigFloatType, 2, BigFloatExt{})   e = codec.NewEncoder(w, &handle) } @@ -87,6 +95,8 @@ handle.WriterBufferSize = 64 * 1024 handle.StructToArray = true handle.OptimumSize = true handle.StringToRaw = true + handle.SetInterfaceExt(bigIntType, 1, BigIntExt{}) + handle.SetInterfaceExt(bigFloatType, 2, BigFloatExt{})   e = codec.NewEncoderBytes(w, &handle) } @@ -112,3 +122,28 @@ default: panic(fmt.Sprintf("unexpected type: %T", d)) } } + +var bigIntType = reflect.TypeOf(big.NewInt(0)) +var bigFloatType = reflect.TypeOf(big.NewFloat(0)) + +type BigIntExt struct{} + +func (x BigIntExt) ConvertExt(v interface{}) interface{} { + v2 := v.(*big.Int) + return v2.Bytes() +} +func (x BigIntExt) UpdateExt(dest interface{}, v interface{}) { + d := dest.(*big.Int) + d.SetBytes(v.([]byte)) +} + +type BigFloatExt struct{} + +func (x BigFloatExt) ConvertExt(v interface{}) interface{} { + v2 := v.(*big.Float) + return v2.String() +} +func (x BigFloatExt) UpdateExt(dest interface{}, v interface{}) { + d := dest.(*big.Float) + d.SetString(v.(string)) +}

Forward transactions to the sequencer or historical node if configured.

diff --git ledgerwatch/erigon/cmd/erigon-el/backend/backend.go testinprod-io/erigon/cmd/erigon-el/backend/backend.go index abed37224b8043345eee0d3699eebebecd84888a..4cf6bbd6619679602361577b30653a71d2b53d41 100644 --- ledgerwatch/erigon/cmd/erigon-el/backend/backend.go +++ testinprod-io/erigon/cmd/erigon-el/backend/backend.go @@ -119,12 +119,14 @@ etherbase libcommon.Address   networkID uint64   - lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) - chainConfig *chain.Config - genesisHash libcommon.Hash - miningSealingQuit chan struct{} - pendingBlocks chan *types.Block - minedBlocks chan *types.Block + lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) + chainConfig *chain.Config + genesisHash libcommon.Hash + seqRPCService *rpc.Client + historicalRPCService *rpc.Client + miningSealingQuit chan struct{} + pendingBlocks chan *types.Block + minedBlocks chan *types.Block   // downloader fields sentryCtx context.Context @@ -442,6 +444,26 @@ 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) + 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) + cancel() + if err != nil { + return nil, err + } + backend.historicalRPCService = client + } + var miningRPC txpool_proto.MiningServer stateDiffClient := direct.NewStateDiffClientDirect(kvRPC) if config.DeprecatedTxPool.Disable { @@ -473,7 +495,7 @@ // proof-of-work mining mining := stagedsync.New( stagedsync.MiningStages(backend.sentryCtx, stagedsync.StageMiningCreateBlockCfg(backend.chainDB, miner, *backend.chainConfig, backend.engine, backend.txPool2, backend.txPool2DB, nil, tmpdir), - stagedsync.StageMiningExecCfg(backend.chainDB, miner, backend.notifications.Events, *backend.chainConfig, backend.engine, &vm.Config{}, tmpdir, nil, 0, backend.txPool2, backend.txPool2DB, allSnapshots, config.TransactionsV3), + stagedsync.StageMiningExecCfg(backend.chainDB, miner, backend.notifications.Events, *backend.chainConfig, backend.engine, &vm.Config{}, tmpdir, nil, 0, backend.txPool2, backend.txPool2DB, false, allSnapshots, config.TransactionsV3), stagedsync.StageHashStateCfg(backend.chainDB, dirs, config.HistoryV3, backend.agg), stagedsync.StageTrieCfg(backend.chainDB, false, true, true, tmpdir, backend.blockReader, nil, config.HistoryV3, backend.agg), stagedsync.StageMiningFinishCfg(backend.chainDB, *backend.chainConfig, backend.engine, miner, backend.miningSealingQuit), @@ -491,7 +513,7 @@ miningStatePos.MiningConfig.Etherbase = param.SuggestedFeeRecipient proposingSync := stagedsync.New( stagedsync.MiningStages(backend.sentryCtx, stagedsync.StageMiningCreateBlockCfg(backend.chainDB, miningStatePos, *backend.chainConfig, backend.engine, backend.txPool2, backend.txPool2DB, param, tmpdir), - stagedsync.StageMiningExecCfg(backend.chainDB, miningStatePos, backend.notifications.Events, *backend.chainConfig, backend.engine, &vm.Config{}, tmpdir, interrupt, param.PayloadId, backend.txPool2, backend.txPool2DB, allSnapshots, config.TransactionsV3), + stagedsync.StageMiningExecCfg(backend.chainDB, miningStatePos, backend.notifications.Events, *backend.chainConfig, backend.engine, &vm.Config{}, tmpdir, interrupt, param.PayloadId, backend.txPool2, backend.txPool2DB, param.NoTxPool, allSnapshots, config.TransactionsV3), stagedsync.StageHashStateCfg(backend.chainDB, dirs, config.HistoryV3, backend.agg), stagedsync.StageTrieCfg(backend.chainDB, false, true, true, tmpdir, backend.blockReader, nil, config.HistoryV3, backend.agg), stagedsync.StageMiningFinishCfg(backend.chainDB, *backend.chainConfig, backend.engine, miningStatePos, backend.miningSealingQuit), @@ -656,8 +678,8 @@ var borDb kv.RoDB if casted, ok := backend.engine.(*bor.Bor); ok { borDb = casted.DB } - apiList := commands.APIList(chainKv, borDb, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, backend.blockReader, backend.agg, httpRpcCfg, backend.engine) - authApiList := commands.AuthAPIList(chainKv, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, backend.blockReader, backend.agg, httpRpcCfg, backend.engine) + apiList := commands.APIList(chainKv, borDb, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, backend.blockReader, backend.agg, httpRpcCfg, backend.engine, backend.seqRPCService, backend.historicalRPCService) + authApiList := commands.AuthAPIList(chainKv, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, backend.blockReader, backend.agg, httpRpcCfg, backend.engine, backend.seqRPCService, backend.historicalRPCService) go func() { if err := cli.StartRpcServer(ctx, httpRpcCfg, apiList, authApiList); err != nil { log.Error(err.Error()) @@ -978,6 +1000,15 @@ } if s.agg != nil { s.agg.Close() } + + // Stop RPC services to sequencer and historical nodes + if s.seqRPCService != nil { + s.seqRPCService.Close() + } + if s.historicalRPCService != nil { + s.historicalRPCService.Close() + } + s.chainDB.Close() return nil }
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/daemon.go testinprod-io/erigon/cmd/rpcdaemon/commands/daemon.go index 0d62fe5165614d3df3566180481d37c6038e7c07..9c39c93d9f3caebb15e16fcba12673a50a572c62 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/daemon.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/daemon.go @@ -16,8 +16,9 @@ // APIList describes the list of available RPC apis func APIList(db kv.RoDB, borDb 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, + seqRPCService *rpc.Client, historicalRPCService *rpc.Client, ) (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) erigonImpl := NewErigonAPI(base, db, eth) txpoolImpl := NewTxPoolAPI(base, db, txPool) @@ -137,8 +138,9 @@ func AuthAPIList(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, + seqRPCService *rpc.Client, historicalRPCService *rpc.Client, ) (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) engineImpl := NewEngineAPI(base, db, eth, cfg.InternalCL)
diff --git ledgerwatch/erigon/eth/backend.go testinprod-io/erigon/eth/backend.go index a9d46f87c57f37a2c3c2b983fd1087a0ff1ff002..0edf2aae64012b1d8b85aae82ff58c1bafb55270 100644 --- ledgerwatch/erigon/eth/backend.go +++ testinprod-io/erigon/eth/backend.go @@ -132,9 +132,11 @@ chainConfig *chain.Config genesisBlock *types.Block genesisHash libcommon.Hash   - ethBackendRPC *privateapi.EthBackendServer - miningRPC txpool_proto.MiningServer - stateChangesClient txpool2.StateChangesClient + ethBackendRPC *privateapi.EthBackendServer + seqRPCService *rpc.Client + historicalRPCService *rpc.Client + miningRPC txpool_proto.MiningServer + stateChangesClient txpool2.StateChangesClient   miningSealingQuit chan struct{} pendingBlocks chan *types.Block @@ -235,6 +237,9 @@ config.Snapshot.Enabled = config.Sync.UseSnapshots   log.Info("Initialised chain configuration", "config", chainConfig, "genesis", genesis.Hash()) + if chainConfig.IsOptimism() && chainConfig.RegolithTime == nil { + log.Warn("Optimism RegolithTime has not been set") + }   if err := chainKv.Update(context.Background(), func(tx kv.RwTx) error { if err = stagedsync.UpdateMetrics(tx); err != nil { @@ -465,6 +470,26 @@ 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) + 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) + cancel() + if err != nil { + return nil, err + } + backend.historicalRPCService = client + } + var miningRPC txpool_proto.MiningServer stateDiffClient := direct.NewStateDiffClientDirect(kvRPC) if config.DeprecatedTxPool.Disable { @@ -475,6 +500,7 @@ //cacheConfig.MetricsLabel = "txpool"   backend.newTxs2 = make(chan types2.Announcements, 1024) //defer close(newTxs) + config.TxPool.Optimism = chainConfig.Optimism != nil backend.txPool2DB, backend.txPool2, backend.txPool2Fetch, backend.txPool2Send, backend.txPool2GrpcServer, err = txpooluitl.AllComponents( ctx, config.TxPool, kvcache.NewDummy(), backend.newTxs2, backend.chainDB, backend.sentriesClient.Sentries(), stateDiffClient, ) @@ -496,7 +522,7 @@ // proof-of-work mining mining := stagedsync.New( stagedsync.MiningStages(backend.sentryCtx, stagedsync.StageMiningCreateBlockCfg(backend.chainDB, miner, *backend.chainConfig, backend.engine, backend.txPool2, backend.txPool2DB, nil, tmpdir), - stagedsync.StageMiningExecCfg(backend.chainDB, miner, backend.notifications.Events, *backend.chainConfig, backend.engine, &vm.Config{}, tmpdir, nil, 0, backend.txPool2, backend.txPool2DB, allSnapshots, config.TransactionsV3), + stagedsync.StageMiningExecCfg(backend.chainDB, miner, backend.notifications.Events, *backend.chainConfig, backend.engine, &vm.Config{}, tmpdir, nil, 0, backend.txPool2, backend.txPool2DB, false, allSnapshots, config.TransactionsV3), stagedsync.StageHashStateCfg(backend.chainDB, dirs, config.HistoryV3, backend.agg), stagedsync.StageTrieCfg(backend.chainDB, false, true, true, tmpdir, blockReader, nil, config.HistoryV3, backend.agg), stagedsync.StageMiningFinishCfg(backend.chainDB, *backend.chainConfig, backend.engine, miner, backend.miningSealingQuit), @@ -511,10 +537,13 @@ // proof-of-stake mining assembleBlockPOS := func(param *core.BlockBuilderParameters, interrupt *int32) (*types.BlockWithReceipts, error) { miningStatePos := stagedsync.NewProposingState(&config.Miner) miningStatePos.MiningConfig.Etherbase = param.SuggestedFeeRecipient + miningStatePos.MiningConfig.Transactions = param.Transactions + miningStatePos.MiningConfig.NoTxPool = param.NoTxPool + miningStatePos.MiningConfig.GasLimit = *param.GasLimit proposingSync := stagedsync.New( stagedsync.MiningStages(backend.sentryCtx, stagedsync.StageMiningCreateBlockCfg(backend.chainDB, miningStatePos, *backend.chainConfig, backend.engine, backend.txPool2, backend.txPool2DB, param, tmpdir), - stagedsync.StageMiningExecCfg(backend.chainDB, miningStatePos, backend.notifications.Events, *backend.chainConfig, backend.engine, &vm.Config{}, tmpdir, interrupt, param.PayloadId, backend.txPool2, backend.txPool2DB, allSnapshots, config.TransactionsV3), + stagedsync.StageMiningExecCfg(backend.chainDB, miningStatePos, backend.notifications.Events, *backend.chainConfig, backend.engine, &vm.Config{}, tmpdir, interrupt, param.PayloadId, backend.txPool2, backend.txPool2DB, param.NoTxPool, allSnapshots, config.TransactionsV3), stagedsync.StageHashStateCfg(backend.chainDB, dirs, config.HistoryV3, backend.agg), stagedsync.StageTrieCfg(backend.chainDB, false, true, true, tmpdir, blockReader, nil, config.HistoryV3, backend.agg), stagedsync.StageMiningFinishCfg(backend.chainDB, *backend.chainConfig, backend.engine, miningStatePos, backend.miningSealingQuit), @@ -720,8 +749,8 @@ var borDb kv.RoDB if casted, ok := backend.engine.(*bor.Bor); ok { borDb = casted.DB } - apiList := commands.APIList(chainKv, borDb, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, blockReader, backend.agg, httpRpcCfg, backend.engine) - authApiList := commands.AuthAPIList(chainKv, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, blockReader, backend.agg, httpRpcCfg, backend.engine) + apiList := commands.APIList(chainKv, borDb, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, blockReader, backend.agg, httpRpcCfg, backend.engine, backend.seqRPCService, backend.historicalRPCService) + authApiList := commands.AuthAPIList(chainKv, ethRpcClient, txPoolRpcClient, miningRpcClient, ff, stateCache, blockReader, backend.agg, httpRpcCfg, backend.engine, backend.seqRPCService, backend.historicalRPCService) go func() { if err := cli.StartRpcServer(ctx, httpRpcCfg, apiList, authApiList); err != nil { log.Error(err.Error()) @@ -1060,6 +1089,15 @@ } if s.agg != nil { s.agg.Close() } + + // Stop RPC services to sequencer and historical nodes + if s.seqRPCService != nil { + s.seqRPCService.Close() + } + if s.historicalRPCService != nil { + s.historicalRPCService.Close() + } + s.chainDB.Close() return nil }
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_accounts.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_accounts.go index 40feb36b6da11617532195e578e81c99a215d92e..b3c7f7e247b942471f4c1fe12db23425c97df696 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_accounts.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_accounts.go @@ -26,6 +26,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 +83,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 +123,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 +169,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/cmd/rpcdaemon/commands/eth_call.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_call.go index f9ab76249b4c5349d01db8b83796fd9f2677efe1..8f41da9625f458d4ae4298b6069bc80102bc9ab4 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_call.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_call.go @@ -45,10 +45,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 hexutility.Bytes + if err := api.relayToHistoricalBackend(ctx, &result, "eth_call", args, hexutil.EncodeUint64(blockNum)); 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 { @@ -142,6 +158,26 @@ 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. if args.Gas != nil && uint64(*args.Gas) >= params.TxGas { hi = uint64(*args.Gas) @@ -220,10 +256,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 @@ -436,10 +468,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 } + 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 @@ -538,6 +586,7 @@ tracer := logger.NewAccessListTracer(accessList, *args.From, to, precompiles) 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 = types.NewL1CostFunc(chainConfig, state)   evm := vm.NewEVM(blockCtx, txCtx, state, chainConfig, config) gp := new(core.GasPool).AddGas(msg.Gas())
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/send_transaction.go testinprod-io/erigon/cmd/rpcdaemon/commands/send_transaction.go index 2db43dde00901cb21e99fe8471cf94eed95eaa21..9cc4b51981bba2b71b9b556892a250c63fdc1be0 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/send_transaction.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/send_transaction.go @@ -12,6 +12,7 @@ "github.com/ledgerwatch/erigon-lib/common/hexutility" txPoolProto "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" "github.com/ledgerwatch/log/v3"   + "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/core/rawdb" "github.com/ledgerwatch/erigon/core/types" "github.com/ledgerwatch/erigon/crypto" @@ -25,6 +26,13 @@ func (api *APIImpl) SendRawTransaction(ctx context.Context, encodedTx hexutility.Bytes) (common.Hash, error) { txn, err := types.DecodeTransaction(rlp.NewStream(bytes.NewReader(encodedTx), uint64(len(encodedTx)))) if err != nil { return common.Hash{}, err + } + + if api.seqRPCService != nil { + if err := api.seqRPCService.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(encodedTx)); err != nil { + return common.Hash{}, err + } + return txn.Hash(), nil }   // If the transaction fee cap is already specified, ensure the
diff --git ledgerwatch/erigon/rpc/errors.go testinprod-io/erigon/rpc/errors.go index b6f8f2ff67ec8bc5b01085bc3a85565edbf0c57d..c9527bd91515a3a3fa8fe1e2b38e5fd7f47a1e41 100644 --- ledgerwatch/erigon/rpc/errors.go +++ testinprod-io/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 }

Format deposit and L1-cost data in transaction responses.

diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_api.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_api.go index ce8951023516dcbffa2c038df15674170063c52c..ecd99b114b7a9edcd8239040daddf8fc66a41162 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_api.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_api.go @@ -123,9 +123,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 @@ -135,7 +143,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) { @@ -177,6 +189,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) { @@ -324,7 +350,10 @@ ReturnDataLimit int }   // NewEthAPI returns APIImpl instance -func NewEthAPI(base *BaseAPI, db kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, gascap uint64, returnDataLimit int) *APIImpl { +func NewEthAPI( + base *BaseAPI, db kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, + gascap uint64, returnDataLimit int, +) *APIImpl { if gascap == 0 { gascap = uint64(math.MaxUint64 / 2) } @@ -341,6 +370,10 @@ ReturnDataLimit: returnDataLimit, } }   +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"` @@ -353,20 +386,26 @@ 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"` 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"` + + // deposit-tx only + SourceHash *common.Hash `json:"sourceHash,omitempty"` + Mint *hexutil.Big `json:"mint,omitempty"` + IsSystemTx *bool `json:"isSystemTx,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, + depositNonce *uint64) *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 @@ -383,10 +422,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()) @@ -417,6 +459,23 @@ result.GasPrice = (*hexutil.Big)(price.ToBig()) } else { result.GasPrice = nil } + 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 depositNonce != nil { + result.Nonce = hexutil.Uint64(*depositNonce) + } + 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) } signer := types.LatestSignerForChainID(chainId.ToBig()) result.From, _ = tx.Sender(*signer) @@ -462,7 +521,7 @@ var baseFee *big.Int if current != nil { baseFee = misc.CalcBaseFee(config, current) } - 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 testinprod-io/erigon/turbo/adapter/ethapi/api.go index 933b2b5d679a3873bdb58913d48232d78fef0867..00d32a6471a6eba46000556349cf35fcb738f86a 100644 --- ledgerwatch/erigon/turbo/adapter/ethapi/api.go +++ testinprod-io/erigon/turbo/adapter/ethapi/api.go @@ -150,7 +150,7 @@ if args.AccessList != nil { accessList = *args.AccessList }   - msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, false /* checkNonce */, false /* isFree */, maxFeePerDataGas) + msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, false /* checkNonce */, false /* isFree */, true /* isFake */, maxFeePerDataGas) return msg, nil }   @@ -296,11 +296,12 @@ // 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, depositNonces []*uint64) (map[string]interface{}, error) { + return RPCMarshalBlockExDeprecated(block, inclTx, fullTx, nil, libcommon.Hash{}, depositNonces) }   -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, + depositNonces []*uint64) (map[string]interface{}, error) { fields := RPCMarshalHeader(block.Header()) fields["size"] = hexutil.Uint64(block.Size()) if _, ok := fields["transactions"]; !ok { @@ -313,11 +314,15 @@ return tx.Hash(), nil } if fullTx { formatTx = func(tx types.Transaction, index int) (interface{}, error) { - return newRPCTransactionFromBlockAndTxGivenIndex(block, tx, uint64(index)), nil + return newRPCTransactionFromBlockAndTxGivenIndex(block, tx, uint64(index), depositNonces[index]), nil } } txs := block.Transactions() transactions := make([]interface{}, len(txs), len(txs)+1) + if depositNonces == nil { + // ensure that depositNonces is always initialized for formatTx + depositNonces = make([]*uint64, len(txs)) + } var err error for i, tx := range txs { if transactions[i], err = formatTx(tx, i); err != nil { @@ -386,20 +391,25 @@ MaxFeePerDataGas *hexutil.Big `json:"maxFeePerDataGas,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"` + // deposit-tx only + SourceHash *libcommon.Hash `json:"sourceHash,omitempty"` + Mint *hexutil.Big `json:"mint,omitempty"` + IsSystemTx *bool `json:"isSystemTx,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, + depositNonce *uint64) *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 @@ -416,10 +426,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()) @@ -450,6 +463,23 @@ result.GasPrice = (*hexutil.Big)(price) } else { result.GasPrice = nil } + 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 depositNonce != nil { + result.Nonce = hexutil.Uint64(*depositNonce) + } + 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.SignedBlobTx: // TODO } signer := types.LatestSignerForChainID(chainId.ToBig()) @@ -512,8 +542,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, depositNonce *uint64) *RPCTransaction { + return newRPCTransaction(tx, b.Hash(), b.NumberU64(), index, b.BaseFee(), depositNonce) }   /*
diff --git ledgerwatch/erigon/turbo/adapter/ethapi/internal.go testinprod-io/erigon/turbo/adapter/ethapi/internal.go index 67e985ade1e19354de132fc6a6f962cd1ae8e0db..e19236329f3fbf893fd933b48b0b66d264fdd426 100644 --- ledgerwatch/erigon/turbo/adapter/ethapi/internal.go +++ testinprod-io/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{}, depositNonces []*uint64) (map[string]interface{}, error) { + fields, err := RPCMarshalBlockDeprecated(b, inclTx, fullTx, depositNonces) if err != nil { return nil, err } @@ -22,8 +22,9 @@ 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{}, depositNonces []*uint64) (map[string]interface{}, error) { + fields, err := RPCMarshalBlockExDeprecated(b, inclTx, fullTx, borTx, borTxHash, depositNonces) if err != nil { return nil, err }
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/erigon_block.go testinprod-io/erigon/cmd/rpcdaemon/commands/erigon_block.go index 245dca06854ab4bedc88bbc7b0d1f5e896315033..f334e7f5df9fad0197d8f96f14030b98469d8fc6 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/erigon_block.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/erigon_block.go @@ -180,7 +180,8 @@ if td != nil { additionalFields["totalDifficulty"] = (*hexutil.Big)(td) }   - response, err := ethapi.RPCMarshalBlockEx(block, true, fullTx, nil, common.Hash{}, additionalFields) + depositNonces := rawdb.ReadDepositNonces(db, blockNum) + response, err := ethapi.RPCMarshalBlockEx(block, true, fullTx, nil, common.Hash{}, additionalFields, depositNonces)   if err == nil && rpc.BlockNumber(block.NumberU64()) == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_block.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_block.go index 8257bbd4abd083bb3ddf4b8ee5e3da6c0216cb45..b08177b2e46345a494bb19f447139848d0a27c49 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_block.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_block.go @@ -121,6 +121,7 @@ }   blockCtx := transactions.NewEVMBlockContext(engine, header, stateBlockNumberOrHash.RequireCanonical, tx, api._blockReader) txCtx := core.NewEVMTxContext(firstMsg) + blockCtx.L1CostFunc = types.NewL1CostFunc(chainConfig, ibs) // Get a new instance of the EVM evm := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vm.Config{Debug: false})   @@ -230,7 +231,8 @@ borTxHash = types.ComputeBorTxHash(b.NumberU64(), b.Hash()) } }   - response, err := ethapi.RPCMarshalBlockEx(b, true, fullTx, borTx, borTxHash, additionalFields) + depositNonces := rawdb.ReadDepositNonces(tx, b.NumberU64()) + response, err := ethapi.RPCMarshalBlockEx(b, true, fullTx, borTx, borTxHash, additionalFields, depositNonces) if err == nil && number == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { @@ -289,7 +291,8 @@ borTxHash = types.ComputeBorTxHash(block.NumberU64(), block.Hash()) } }   - response, err := ethapi.RPCMarshalBlockEx(block, true, fullTx, borTx, borTxHash, additionalFields) + depositNonces := rawdb.ReadDepositNonces(tx, number) + response, err := ethapi.RPCMarshalBlockEx(block, true, fullTx, borTx, borTxHash, additionalFields, depositNonces)   if chainConfig.Bor != nil { response["miner"], _ = ecrecover(block.Header(), chainConfig.Bor)
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_txs.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_txs.go index 21fe98462ac28b0e24651c9a4f20a94bc07f6616..3d9a507ae0131ec89dd0e2dc4e80bc170ad64e8b 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_txs.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_txs.go @@ -3,6 +3,7 @@ import ( "bytes" "context" + "fmt" "math/big"   "github.com/ledgerwatch/erigon-lib/common" @@ -85,7 +86,15 @@ } 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() { + depositNonces := rawdb.ReadDepositNonces(tx, block.NumberU64()) + if txnIndex >= uint64(len(depositNonces)) { + return nil, fmt.Errorf("depositNonce for tx %x not found", txnHash) + } else { + return newRPCTransaction(txn, blockHash, blockNum, txnIndex, baseFee, depositNonces[txnIndex]), nil + } + } + return newRPCTransaction(txn, blockHash, blockNum, txnIndex, baseFee, nil), nil }   curHeader := rawdb.ReadCurrentHeader(tx) @@ -201,7 +210,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() { + depositNonces := rawdb.ReadDepositNonces(tx, block.NumberU64()) + if uint64(txIndex) >= uint64(len(depositNonces)) { + return nil, fmt.Errorf("depositNonce for tx %x not found", txs[txIndex].Hash()) + } else { + return newRPCTransaction(txs[txIndex], block.Hash(), block.NumberU64(), uint64(txIndex), block.BaseFee(), depositNonces[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. @@ -264,8 +281,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() { + depositNonces := rawdb.ReadDepositNonces(tx, blockNum) + if uint64(txIndex) >= uint64(len(depositNonces)) { + return nil, fmt.Errorf("depositNonce for tx %x not found", txs[txIndex].Hash()) + } else { + return newRPCTransaction(txs[txIndex], block.Hash(), blockNum, uint64(txIndex), block.BaseFee(), depositNonces[txIndex]), nil + } + } + return newRPCTransaction(txs[txIndex], block.Hash(), block.NumberU64(), uint64(txIndex), block.BaseFee(), nil), nil }   // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index.
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_uncles.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_uncles.go index 31ae196a366ee8c514f23f21a99ea5405938ac7f..28124923649dbc7ebbf9caa2d024f68bc1d07dd3 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_uncles.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_uncles.go @@ -46,7 +46,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) + depositNonces := rawdb.ReadDepositNonces(tx, blockNum) + return ethapi.RPCMarshalBlock(uncle, false, false, additionalFields, depositNonces) }   // GetUncleByBlockHashAndIndex implements eth_getUncleByBlockHashAndIndex. Returns information about an uncle given a block's hash and the index of the uncle. @@ -78,8 +79,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) + depositNonces := rawdb.ReadDepositNonces(tx, number) + return ethapi.RPCMarshalBlock(uncle, false, false, additionalFields, depositNonces) }   // GetUncleCountByBlockNumber implements eth_getUncleCountByBlockNumber. Returns the number of uncles in the block, if any.
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_api.go testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_api.go index 9c97527254d635b23c6b2da2ac75365b7e6b6375..da9498abc8a945af44447c60c2e70ccdd5409fd2 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_api.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_api.go @@ -18,6 +18,8 @@ "github.com/ledgerwatch/erigon-lib/kv/iter" "github.com/ledgerwatch/erigon-lib/kv/order" "github.com/ledgerwatch/erigon-lib/kv/rawdbv3" "github.com/ledgerwatch/erigon/core/state/temporal" + "github.com/ledgerwatch/erigon/core/vm/evmtypes" + "github.com/ledgerwatch/erigon/eth/tracers"   "github.com/ledgerwatch/erigon/common/hexutil" "github.com/ledgerwatch/erigon/consensus/ethash" @@ -114,6 +116,167 @@ } return txn, block, blockHash, blockNum, txnIndex, nil }   +func (api *OtterscanAPIImpl) relayToHistoricalBackend(ctx context.Context, result interface{}, method string, args ...interface{}) error { + return api.historicalRPCService.CallContext(ctx, result, method, args...) +} + +func (api *OtterscanAPIImpl) translateCaptureStart(gethTrace *GethTrace, tracer vm.EVMLogger, vmenv *vm.EVM) error { + from := common.HexToAddress(gethTrace.From) + to := common.HexToAddress(gethTrace.To) + input, err := hexutil.Decode(gethTrace.Input) + if err != nil { + if err != hexutil.ErrEmptyString { + return err + } + input = []byte{} + } + valueBig, err := hexutil.DecodeBig(gethTrace.Value) + if err != nil { + if err != hexutil.ErrEmptyString { + return err + } + valueBig = big.NewInt(0) + } + value, _ := uint256.FromBig(valueBig) + gas, err := hexutil.DecodeUint64(gethTrace.Gas) + if err != nil { + return err + } + _, isPrecompile := vmenv.Precompile(to) + // dummy code + code := []byte{} + tracer.CaptureStart(vmenv, from, to, isPrecompile, false, input, gas, value, code) + return nil +} + +func (api *OtterscanAPIImpl) translateOpcode(typStr string) (vm.OpCode, error) { + switch typStr { + default: + case "CALL": + return vm.CALL, nil + case "STATICCALL": + return vm.STATICCALL, nil + case "DELEGATECALL": + return vm.DELEGATECALL, nil + case "CALLCODE": + return vm.CALLCODE, nil + case "CREATE": + return vm.CREATE, nil + case "CREATE2": + return vm.CREATE2, nil + case "SELFDESTRUCT": + return vm.SELFDESTRUCT, nil + } + return vm.INVALID, fmt.Errorf("unable to translate %s", typStr) +} + +func (api *OtterscanAPIImpl) translateCaptureEnter(gethTrace *GethTrace, tracer vm.EVMLogger, vmenv *vm.EVM) error { + from := common.HexToAddress(gethTrace.From) + to := common.HexToAddress(gethTrace.To) + input, err := hexutil.Decode(gethTrace.Input) + if err != nil { + if err != hexutil.ErrEmptyString { + return err + } + input = []byte{} + } + valueBig, err := hexutil.DecodeBig(gethTrace.Value) + if err != nil { + if err != hexutil.ErrEmptyString { + return err + } + valueBig = big.NewInt(0) + } + value, _ := uint256.FromBig(valueBig) + gas, err := hexutil.DecodeUint64(gethTrace.Gas) + if err != nil { + return err + } + typStr := gethTrace.Type + typ, err := api.translateOpcode(typStr) + if err != nil { + return err + } + _, isPrecompile := vmenv.Precompile(to) + tracer.CaptureEnter(typ, from, to, isPrecompile, false, input, gas, value, nil) + return nil +} + +func (api *OtterscanAPIImpl) translateCaptureExit(gethTrace *GethTrace, tracer vm.EVMLogger) error { + usedGas, err := hexutil.DecodeUint64(gethTrace.GasUsed) + if err != nil { + return err + } + output, err := hexutil.Decode(gethTrace.Output) + if err != nil { + if err != hexutil.ErrEmptyString { + return err + } + output = []byte{} + } + err = errors.New(gethTrace.Error) + tracer.CaptureExit(output, usedGas, err) + return nil +} + +func (api *OtterscanAPIImpl) translateRelayTraceResult(gethTrace *GethTrace, tracer vm.EVMLogger, chainConfig *chain.Config) error { + vmenv := vm.NewEVM(evmtypes.BlockContext{}, evmtypes.TxContext{}, nil, chainConfig, vm.Config{}) + type traceWithIndex struct { + gethTrace *GethTrace + idx int // children index + } + callStacks := make([]*traceWithIndex, 0) + started := false + // Each call stack can call and trigger sub call stack. + // rootIndex indicates the index of child for current inspected parent node trace. + rootIndex := 0 + var trace *GethTrace = gethTrace + // iterative postorder traversal + for trace != nil || len(callStacks) > 0 { + if trace != nil { + // push back + callStacks = append(callStacks, &traceWithIndex{trace, rootIndex}) + if !started { + started = true + if err := api.translateCaptureStart(trace, tracer, vmenv); err != nil { + return err + } + } else { + if err := api.translateCaptureEnter(trace, tracer, vmenv); err != nil { + return err + } + } + rootIndex = 0 + if len(trace.Calls) > 0 { + trace = trace.Calls[0] + } else { + trace = nil + } + continue + } + // pop back + top := callStacks[len(callStacks)-1] + callStacks = callStacks[:len(callStacks)-1] + if err := api.translateCaptureExit(top.gethTrace, tracer); err != nil { + return err + } + // pop back callstack repeatly until popped element is last children of top of the callstack + for len(callStacks) > 0 && top.idx == len(callStacks[len(callStacks)-1].gethTrace.Calls)-1 { + // pop back + top = callStacks[len(callStacks)-1] + callStacks = callStacks[:len(callStacks)-1] + if err := api.translateCaptureExit(top.gethTrace, tracer); err != nil { + return err + } + } + if len(callStacks) > 0 { + trace = callStacks[len(callStacks)-1].gethTrace.Calls[top.idx+1] + rootIndex = top.idx + 1 + } + } + return nil +} + func (api *OtterscanAPIImpl) runTracer(ctx context.Context, tx kv.Tx, hash common.Hash, tracer vm.EVMLogger) (*core.ExecutionResult, error) { txn, block, _, _, txIndex, err := api.getTransactionByHash(ctx, tx, hash) if err != nil { @@ -127,6 +290,43 @@ chainConfig, err := api.chainConfig(tx) if err != nil { return nil, err } + + blockNum := block.NumberU64() + if chainConfig.IsOptimismPreBedrock(blockNum) { + if api.historicalRPCService == nil { + return nil, rpc.ErrNoHistoricalFallback + } + // geth returns nested json so we have to flatten + treeResult := &GethTrace{} + callTracer := "callTracer" + if err := api.relayToHistoricalBackend(ctx, treeResult, "debug_traceTransaction", hash, &tracers.TraceConfig{Tracer: &callTracer}); err != nil { + return nil, fmt.Errorf("historical backend error: %w", err) + } + if tracer != nil { + err := api.translateRelayTraceResult(treeResult, tracer, chainConfig) + if err != nil { + return nil, err + } + } + usedGas, err := hexutil.DecodeUint64(treeResult.GasUsed) + if err != nil { + return nil, err + } + returnData, err := hexutil.Decode(treeResult.Output) + if err != nil { + if err != hexutil.ErrEmptyString { + return nil, err + } + returnData = []byte{} + } + result := &core.ExecutionResult{ + UsedGas: usedGas, + Err: errors.New(treeResult.Error), + ReturnData: returnData, + } + return result, nil + } + engine := api.engine()   msg, blockCtx, txCtx, ibs, _, err := transactions.ComputeTxEnv(ctx, engine, block, chainConfig, api._blockReader, tx, int(txIndex), api.historyV3(tx)) @@ -320,7 +520,17 @@ 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 + if chainConfig.IsOptimism() { + depositNonces := rawdb.ReadDepositNonces(tx, blockNum) + if txIndex >= len(depositNonces) { + return nil, fmt.Errorf("depositNonce for tx %x not found", txn.Hash()) + } else { + rpcTx = newRPCTransaction(txn, blockHash, blockNum, uint64(txIndex), header.BaseFee, depositNonces[txIndex]) + } + } else { + rpcTx = newRPCTransaction(txn, blockHash, blockNum, uint64(txIndex), header.BaseFee, nil) + } txs = append(txs, rpcTx) receipt := &types.Receipt{ Type: txn.Type(), CumulativeGasUsed: res.UsedGas, @@ -427,6 +637,9 @@ }   func (api *OtterscanAPIImpl) traceBlocks(ctx context.Context, addr common.Address, chainConfig *chain.Config, pageSize, resultCount uint16, callFromToProvider BlockProvider) ([]*TransactionsWithReceipts, bool, error) { var wg sync.WaitGroup + errCh := make(chan error, 1) + traceCtx, traceCtxCancel := context.WithCancel(context.Background()) + defer traceCtxCancel()   // Estimate the common case of user address having at most 1 interaction/block and // trace N := remaining page matches as number of blocks to trace concurrently. @@ -450,10 +663,12 @@ }   wg.Add(1) totalBlocksTraced++ - go api.searchTraceBlock(ctx, &wg, addr, chainConfig, i, nextBlock, results) + go api.searchTraceBlock(ctx, traceCtx, traceCtxCancel, &wg, errCh, addr, chainConfig, i, nextBlock, results) } wg.Wait() - + if traceCtx.Err() != nil && len(errCh) == 1 { + return nil, false, <-errCh + } return results[:totalBlocksTraced], hasMore, nil }   @@ -463,7 +678,8 @@ if err != nil { return nil, err } additionalFields := make(map[string]interface{}) - response, err := ethapi.RPCMarshalBlock(b, inclTx, inclTx, additionalFields) + depositNonces := rawdb.ReadDepositNonces(tx, uint64(number.Int64())) + response, err := ethapi.RPCMarshalBlock(b, inclTx, inclTx, additionalFields, depositNonces) if !inclTx { delete(response, "transactions") // workaround for https://github.com/ledgerwatch/erigon/issues/4989#issuecomment-1218415666 } @@ -510,12 +726,13 @@ ret.UncleReward = hexutil.EncodeBig(issuance.ToBig()) return ret, nil }   -func (api *OtterscanAPIImpl) delegateBlockFees(ctx context.Context, tx kv.Tx, block *types.Block, senders []common.Address, chainConfig *chain.Config) (uint64, error) { +func (api *OtterscanAPIImpl) delegateBlockFees(ctx context.Context, tx kv.Tx, block *types.Block, senders []common.Address, chainConfig *chain.Config) (uint64, uint64, error) { receipts, err := api.getReceipts(ctx, tx, chainConfig, block, senders) if err != nil { - return 0, fmt.Errorf("getReceipts error: %v", err) + return 0, 0, fmt.Errorf("getReceipts error: %v", err) }   + gasUsedDepositTx := uint64(0) fees := uint64(0) for _, receipt := range receipts { txn := block.Transactions()[receipt.TransactionIndex] @@ -524,13 +741,18 @@ if !chainConfig.IsLondon(block.NumberU64()) { effectiveGasPrice = txn.GetPrice().Uint64() } else { baseFee, _ := uint256.FromBig(block.BaseFee()) + if chainConfig.IsOptimism() && receipt.IsDepositTxReceipt() { + // if depositTx, no fee consumption + gasUsedDepositTx += receipt.GasUsed + continue + } gasPrice := new(big.Int).Add(block.BaseFee(), txn.GetEffectiveGasTip(baseFee).ToBig()) effectiveGasPrice = gasPrice.Uint64() } fees += effectiveGasPrice * receipt.GasUsed }   - return fees, nil + return fees, gasUsedDepositTx, nil }   func (api *OtterscanAPIImpl) getBlockWithSenders(ctx context.Context, number rpc.BlockNumber, tx kv.Tx) (*types.Block, []common.Address, error) { @@ -572,6 +794,10 @@ if err != nil { return nil, err }   + if len(senders) != b.Transactions().Len() { + // fallback; set senders from inspecting tx + senders = b.Body().SendersFromTxs() + } // Receipts receipts, err := api.getReceipts(ctx, tx, chainConfig, b, senders) if err != nil {
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_block_details.go testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_block_details.go index 5eebf754eb35df18f69c2d74ce6b941c140cb71a..40356f408c2c765e97468f448a9a2c26c07e5d92 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_block_details.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_block_details.go @@ -19,6 +19,10 @@ } defer tx.Rollback()   b, senders, err := api.getBlockWithSenders(ctx, number, tx) + if len(senders) != b.Transactions().Len() { + // fallback; set senders from inspecting tx + senders = b.Body().SendersFromTxs() + } if err != nil { return nil, err } @@ -39,7 +43,7 @@ getIssuanceRes, err := api.delegateIssuance(tx, b, chainConfig) if err != nil { return nil, err } - feesRes, err := api.delegateBlockFees(ctx, tx, b, senders, chainConfig) + feesRes, gasUsedDepositTxRes, err := api.delegateBlockFees(ctx, tx, b, senders, chainConfig) if err != nil { return nil, err } @@ -48,6 +52,9 @@ response := map[string]interface{}{} response["block"] = getBlockRes response["issuance"] = getIssuanceRes response["totalFees"] = hexutil.Uint64(feesRes) + if chainConfig.IsOptimism() { + response["gasUsedDepositTx"] = hexutil.Uint64(gasUsedDepositTxRes) + } return response, nil }   @@ -85,7 +92,7 @@ getIssuanceRes, err := api.delegateIssuance(tx, b, chainConfig) if err != nil { return nil, err } - feesRes, err := api.delegateBlockFees(ctx, tx, b, senders, chainConfig) + feesRes, gasUsedDepositTxRes, err := api.delegateBlockFees(ctx, tx, b, senders, chainConfig) if err != nil { return nil, err } @@ -94,5 +101,8 @@ response := map[string]interface{}{} response["block"] = getBlockRes response["issuance"] = getIssuanceRes response["totalFees"] = hexutil.Uint64(feesRes) + if chainConfig.IsOptimism() { + response["gasUsedDepositTx"] = hexutil.Uint64(gasUsedDepositTxRes) + } return response, nil }
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_contract_creator.go testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_contract_creator.go index 403e80d7578a64e75e5657b696473260de2a8f7f..031ea26c75503830f040efe0f88dbf609cb57a15 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_contract_creator.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_contract_creator.go @@ -298,6 +298,11 @@ if err := api.genericTracer(tx, ctx, blockFound, 0, 0, chainConfig, tracer); err != nil { return nil, err }   + // TODO: check if precompiled contract + if !tracer.Found() { + return nil, nil + } + return &ContractCreatorData{ Tx: tracer.Tx.Hash(), Creator: tracer.Creator,
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_generic_tracer.go testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_generic_tracer.go index 2f0bb9addffea2abdfac445d0851a3b809a785bf..14217cb1b1439bad43cd5837887151946a68629e 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_generic_tracer.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_generic_tracer.go @@ -90,6 +90,7 @@ msg, _ := tx.AsMessage(*signer, header.BaseFee, rules)   BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil, excessDataGas) + BlockContext.L1CostFunc = types.NewL1CostFunc(chainConfig, ibs) TxContext := core.NewEVMTxContext(msg)   vmenv := vm.NewEVM(BlockContext, TxContext, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer})
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_search_trace.go testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_search_trace.go index 83174cca0309578ff9e4e60e5b1765ed4658d51d..fdf0a5b1e0e14a92a1afdf6c3a9085a03c4f43d6 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_search_trace.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_search_trace.go @@ -2,6 +2,7 @@ package commands   import ( "context" + "fmt" "sync"   "github.com/ledgerwatch/erigon-lib/chain" @@ -18,7 +19,7 @@ "github.com/ledgerwatch/erigon/core/vm" "github.com/ledgerwatch/erigon/turbo/shards" )   -func (api *OtterscanAPIImpl) searchTraceBlock(ctx context.Context, wg *sync.WaitGroup, addr common.Address, chainConfig *chain.Config, idx int, bNum uint64, results []*TransactionsWithReceipts) { +func (api *OtterscanAPIImpl) searchTraceBlock(ctx, traceCtx context.Context, traceCtxCancel context.CancelFunc, wg *sync.WaitGroup, errCh chan<- error, addr common.Address, chainConfig *chain.Config, idx int, bNum uint64, results []*TransactionsWithReceipts) { defer wg.Done()   // Trace block for Txs @@ -30,7 +31,22 @@ return } defer newdbtx.Rollback()   - _, result, err := api.traceBlock(newdbtx, ctx, bNum, addr, chainConfig) + // found will be false when CallTraceSet info and CallFromIndex/CallToIndex table info mismatch + // searchTraceBlock goroutine will sequentially search every block written in CallTraceSet + // when mismatch, causing cpu hike. To avoid this, when inconsistency found, early terminate. + found, result, err := api.traceBlock(newdbtx, ctx, bNum, addr, chainConfig) + if !found { + // tx execution result and callFromToProvider() result mismatch + err = fmt.Errorf("search trace failure: inconsistency at block %d", bNum) + select { + case <-traceCtx.Done(): + return + case errCh <- err: + default: + } + traceCtxCancel() + return + } if err != nil { log.Error("Search trace error", "err", err) results[idx] = nil @@ -75,11 +91,16 @@ return h } engine := api.engine()   - blockReceipts := rawdb.ReadReceipts(dbtx, block, senders) + blockReceipts := rawdb.ReadReceipts(api._chainConfig.Load(), dbtx, block, senders) header := block.Header() excessDataGas := header.ParentExcessDataGas(getHeader) rules := chainConfig.Rules(block.NumberU64(), header.Time) found := false + + var depositNonces []*uint64 + if chainConfig.IsOptimism() { + depositNonces = rawdb.ReadDepositNonces(dbtx, blockNum) + } for idx, tx := range block.Transactions() { ibs.Prepare(tx.Hash(), block.Hash(), idx)   @@ -87,6 +108,7 @@ msg, _ := tx.AsMessage(*signer, header.BaseFee, rules)   tracer := NewTouchTracer(searchAddr) BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil, excessDataGas) + BlockContext.L1CostFunc = types.NewL1CostFunc(chainConfig, ibs) TxContext := core.NewEVMTxContext(msg)   vmenv := vm.NewEVM(BlockContext, TxContext, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer}) @@ -96,7 +118,11 @@ } _ = ibs.FinalizeTx(rules, cachedWriter)   if tracer.Found { - rpcTx := newRPCTransaction(tx, block.Hash(), blockNum, uint64(idx), block.BaseFee()) + var depositNonce *uint64 + if chainConfig.IsOptimism() && idx < len(depositNonces) { + depositNonce = depositNonces[idx] + } + rpcTx := newRPCTransaction(tx, block.Hash(), blockNum, uint64(idx), block.BaseFee(), depositNonce) 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 testinprod-io/erigon/core/types/receipt_codecgen_gen.go index e2bc7db9db1f1e9bba2ed75a6cc84f685079bf75..35a3d6b5ec3deb4b6ae812243f860c47ba5078d1 100644 --- ledgerwatch/erigon/core/types/receipt_codecgen_gen.go +++ testinprod-io/erigon/core/types/receipt_codecgen_gen.go @@ -7,7 +7,7 @@ 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" @@ -46,7 +46,7 @@ ver := strconv.FormatInt(int64(codec1978.GenVersion), 10) panic(errors.New("codecgen version mismatch: current: 19, 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 } } @@ -64,7 +64,12 @@ } else { yy2arr2 := z.EncBasicHandle().StructToArray _ = yy2arr2 const yyr2 bool = false // struct tag has 'toArray' - z.EncWriteArrayStart(4) + var yyn7 bool = x.L1GasPrice == nil + var yyn8 bool = x.L1GasUsed == nil + var yyn9 bool = x.L1Fee == nil + var yyn10 bool = x.FeeScalar == nil + var yyn11 bool = x.DepositNonce == nil + z.EncWriteArrayStart(9) z.EncWriteArrayElem() r.EncodeUint(uint64(x.Type)) z.EncWriteArrayElem() @@ -77,6 +82,58 @@ z.EncWriteArrayElem() r.EncodeUint(uint64(x.Status)) z.EncWriteArrayElem() r.EncodeUint(uint64(x.CumulativeGasUsed)) + if yyn7 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + if !z.EncBinary() && z.IsJSONHandle() { + z.EncJSONMarshal(x.L1GasPrice) + } else { + z.EncFallback(x.L1GasPrice) + } + } + if yyn8 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + if !z.EncBinary() && z.IsJSONHandle() { + z.EncJSONMarshal(x.L1GasUsed) + } else { + z.EncFallback(x.L1GasUsed) + } + } + if yyn9 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + if !z.EncBinary() && z.IsJSONHandle() { + z.EncJSONMarshal(x.L1Fee) + } else { + z.EncFallback(x.L1Fee) + } + } + if yyn10 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + if !z.EncBinary() { + z.EncTextMarshal(x.FeeScalar) + } else { + z.EncFallback(x.FeeScalar) + } + } + if yyn11 { + z.EncWriteArrayElem() + r.EncodeNil() + } else { + z.EncWriteArrayElem() + yy20 := *x.DepositNonce + r.EncodeUint(uint64(yy20)) + } z.EncWriteArrayEnd() } } @@ -138,6 +195,77 @@ case "2": x.Status = (uint64)(r.DecodeUint64()) case "3": x.CumulativeGasUsed = (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 "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()) + } default: z.DecStructFieldNotFound(-1, yys3) } // end switch yys3 @@ -148,69 +276,190 @@ func (x *Receipt) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) { var h codecSelfer2 z, r := codec1978.GenHelperDecoder(d) _, _, _ = h, z, r - var yyj9 int - var yyb9 bool - var yyhl9 bool = l >= 0 - yyj9++ - if yyhl9 { - yyb9 = yyj9 > l + var yyj19 int + var yyb19 bool + var yyhl19 bool = l >= 0 + yyj19++ + if yyhl19 { + yyb19 = yyj19 > l } else { - yyb9 = z.DecCheckBreak() + yyb19 = z.DecCheckBreak() } - if yyb9 { + if yyb19 { z.DecReadArrayEnd() return } z.DecReadArrayElem() x.Type = (uint8)(z.C.UintV(r.DecodeUint64(), 8)) - yyj9++ - if yyhl9 { - yyb9 = yyj9 > l + yyj19++ + if yyhl19 { + yyb19 = yyj19 > l } else { - yyb9 = z.DecCheckBreak() + yyb19 = z.DecCheckBreak() } - if yyb9 { + if yyb19 { z.DecReadArrayEnd() return } z.DecReadArrayElem() x.PostState = r.DecodeBytes(([]byte)(x.PostState), false) - yyj9++ - if yyhl9 { - yyb9 = yyj9 > l + yyj19++ + if yyhl19 { + yyb19 = yyj19 > l } else { - yyb9 = z.DecCheckBreak() + yyb19 = z.DecCheckBreak() } - if yyb9 { + if yyb19 { z.DecReadArrayEnd() return } z.DecReadArrayElem() x.Status = (uint64)(r.DecodeUint64()) - yyj9++ - if yyhl9 { - yyb9 = yyj9 > l + yyj19++ + if yyhl19 { + yyb19 = yyj19 > l } else { - yyb9 = z.DecCheckBreak() + yyb19 = z.DecCheckBreak() } - if yyb9 { + if yyb19 { z.DecReadArrayEnd() return } z.DecReadArrayElem() x.CumulativeGasUsed = (uint64)(r.DecodeUint64()) + yyj19++ + if yyhl19 { + yyb19 = yyj19 > l + } else { + yyb19 = z.DecCheckBreak() + } + if yyb19 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + 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) + } + } + yyj19++ + if yyhl19 { + yyb19 = yyj19 > l + } else { + yyb19 = z.DecCheckBreak() + } + if yyb19 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + 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) + } + } + yyj19++ + if yyhl19 { + yyb19 = yyj19 > l + } else { + yyb19 = z.DecCheckBreak() + } + if yyb19 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + 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) + } + } + yyj19++ + if yyhl19 { + yyb19 = yyj19 > l + } else { + yyb19 = z.DecCheckBreak() + } + if yyb19 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + 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) + } + } + yyj19++ + if yyhl19 { + yyb19 = yyj19 > l + } else { + yyb19 = z.DecCheckBreak() + } + if yyb19 { + z.DecReadArrayEnd() + return + } + z.DecReadArrayElem() + 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()) + } for { - yyj9++ - if yyhl9 { - yyb9 = yyj9 > l + yyj19++ + if yyhl19 { + yyb19 = yyj19 > l } else { - yyb9 = z.DecCheckBreak() + yyb19 = z.DecCheckBreak() } - if yyb9 { + if yyb19 { break } z.DecReadArrayElem() - z.DecStructFieldNotFound(yyj9-1, "") + z.DecStructFieldNotFound(yyj19-1, "") } }   @@ -255,13 +504,13 @@ yy6 := &x.Address if !z.EncBinary() { z.EncTextMarshal(*yy6) } else { - h.enccommon_Address((*libcommon.Address)(yy6), e) + h.enccommon_Address((*pkg1_common.Address)(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 { @@ -326,10 +575,10 @@ case "1": if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(&x.Address) } else { - h.deccommon_Address((*libcommon.Address)(&x.Address), d) + h.deccommon_Address((*pkg1_common.Address)(&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) default: @@ -359,7 +608,7 @@ z.DecReadArrayElem() if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(&x.Address) } else { - h.deccommon_Address((*libcommon.Address)(&x.Address), d) + h.deccommon_Address((*pkg1_common.Address)(&x.Address), d) } yyj10++ if yyhl10 { @@ -372,7 +621,7 @@ 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 @@ -526,7 +775,7 @@ *v = yyv1 } }   -func (x codecSelfer2) enccommon_Address(v *libcommon.Address, e *codec1978.Encoder) { +func (x codecSelfer2) enccommon_Address(v *pkg1_common.Address, e *codec1978.Encoder) { var h codecSelfer2 z, r := codec1978.GenHelperEncoder(e) _, _, _ = h, z, r @@ -537,14 +786,14 @@ } r.EncodeStringBytesRaw(((*[20]byte)(v))[:]) }   -func (x codecSelfer2) deccommon_Address(v *libcommon.Address, d *codec1978.Decoder) { +func (x codecSelfer2) deccommon_Address(v *pkg1_common.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) { +func (x codecSelfer2) encSlicecommon_Hash(v []pkg1_common.Hash, e *codec1978.Encoder) { var h codecSelfer2 z, r := codec1978.GenHelperEncoder(e) _, _, _ = h, z, r @@ -559,13 +808,13 @@ yy2 := &yyv1 if !z.EncBinary() { z.EncTextMarshal(*yy2) } else { - h.enccommon_Hash((*libcommon.Hash)(yy2), e) + h.enccommon_Hash((*pkg1_common.Hash)(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) _, _, _ = h, z, r @@ -581,7 +830,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 +846,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) { @@ -613,13 +862,13 @@ 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 +877,7 @@ } else { if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(&yyv1[yyj1]) } else { - h.deccommon_Hash((*libcommon.Hash)(&yyv1[yyj1]), d) + h.deccommon_Hash((*pkg1_common.Hash)(&yyv1[yyj1]), d) } } } @@ -636,7 +885,7 @@ if yyj1 < len(yyv1) { yyv1 = yyv1[:yyj1] yyc1 = true } else if yyj1 == 0 && yyv1 == nil { - yyv1 = make([]libcommon.Hash, 0) + yyv1 = make([]pkg1_common.Hash, 0) yyc1 = true } } @@ -646,7 +895,7 @@ *v = yyv1 } }   -func (x codecSelfer2) enccommon_Hash(v *libcommon.Hash, e *codec1978.Encoder) { +func (x codecSelfer2) enccommon_Hash(v *pkg1_common.Hash, e *codec1978.Encoder) { var h codecSelfer2 z, r := codec1978.GenHelperEncoder(e) _, _, _ = h, z, r @@ -657,7 +906,7 @@ } r.EncodeStringBytesRaw(((*[32]byte)(v))[:]) }   -func (x codecSelfer2) deccommon_Hash(v *libcommon.Hash, d *codec1978.Decoder) { +func (x codecSelfer2) deccommon_Hash(v *pkg1_common.Hash, d *codec1978.Decoder) { var h codecSelfer2 z, r := codec1978.GenHelperDecoder(d) _, _, _ = h, z, r
diff --git ledgerwatch/erigon/.goreleaser.yml testinprod-io/erigon/.goreleaser.yml index c305e2c6392e1cdf902357c28943807e17ab70fc..517587e26583dae8270577e218836419f41b1a82 100644 --- ledgerwatch/erigon/.goreleaser.yml +++ testinprod-io/erigon/.goreleaser.yml @@ -1,4 +1,4 @@ -project_name: erigon +project_name: op-erigon   release: disable: false @@ -50,16 +50,16 @@ - CXX=aarch64-linux-gnu-g++ tags: [ nosqlite, noboltdb, netgo ] ldflags: -s -w -extldflags "-static" # We need to build a static binary because we are building in a glibc based system and running in a musl container   - - id: windows-amd64 - main: ./cmd/erigon - binary: erigon - goos: [ windows ] - goarch: [ amd64 ] - env: - - CC=x86_64-w64-mingw32-gcc - - CXX=x86_64-w64-mingw32-g++ - tags: [ nosqlite, noboltdb, netgo ] - ldflags: -s -w +# - id: windows-amd64 +# main: ./cmd/erigon +# binary: erigon +# goos: [ windows ] +# goarch: [ amd64 ] +# env: +# - CC=x86_64-w64-mingw32-gcc +# - CXX=x86_64-w64-mingw32-g++ +# tags: [ nosqlite, noboltdb, netgo ] +# ldflags: -s -w   snapshot: @@ -67,8 +67,7 @@ name_template: "{{ .Tag }}.next"   dockers: - image_templates: - - thorax/{{ .ProjectName }}:{{ .Version }}-amd64 - - ghcr.io/ledgerwatch/{{ .ProjectName }}:{{ .Version }}-amd64 + - testinprod/{{ .ProjectName }}:{{ .Version }}-amd64 dockerfile: Dockerfile.release use: buildx skip_push: true @@ -79,8 +78,7 @@ build_flag_templates: - --platform=linux/amd64   - image_templates: - - thorax/{{ .ProjectName }}:{{ .Version }}-arm64 - - ghcr.io/ledgerwatch/{{ .ProjectName }}:{{ .Version }}-arm64 + - testinprod/{{ .ProjectName }}:{{ .Version }}-arm64 dockerfile: Dockerfile.release skip_push: true use: buildx @@ -91,29 +89,17 @@ build_flag_templates: - --platform=linux/arm64/v8   docker_manifests: - - name_template: thorax/{{ .ProjectName }}:{{ .Version }} - skip_push: true - image_templates: - - thorax/{{ .ProjectName }}:{{ .Version }}-amd64 - - thorax/{{ .ProjectName }}:{{ .Version }}-arm64 - - - name_template: ghcr.io/ledgerwatch/{{ .ProjectName }}:{{ .Version }} - skip_push: true - image_templates: - - ghcr.io/ledgerwatch/{{ .ProjectName }}:{{ .Version }}-amd64 - - ghcr.io/ledgerwatch/{{ .ProjectName }}:{{ .Version }}-arm64 - - - name_template: thorax/{{ .ProjectName }}:latest + - name_template: testinprod/{{ .ProjectName }}:{{ .Version }} skip_push: true image_templates: - - thorax/{{ .ProjectName }}:{{ .Version }}-amd64 - - thorax/{{ .ProjectName }}:{{ .Version }}-arm64 + - testinprod/{{ .ProjectName }}:{{ .Version }}-amd64 + - testinprod/{{ .ProjectName }}:{{ .Version }}-arm64   - - name_template: ghcr.io/ledgerwatch/{{ .ProjectName }}:latest + - name_template: testinprod/{{ .ProjectName }}:latest skip_push: true image_templates: - - ghcr.io/ledgerwatch/{{ .ProjectName }}:{{ .Version }}-amd64 - - ghcr.io/ledgerwatch/{{ .ProjectName }}:{{ .Version }}-arm64 + - testinprod/{{ .ProjectName }}:{{ .Version }}-amd64 + - testinprod/{{ .ProjectName }}:{{ .Version }}-arm64   announce: slack:
diff --git ledgerwatch/erigon/Dockerfile.debian testinprod-io/erigon/Dockerfile.debian index 7cf40a1e9037430b3a331cf17db41cc4b29d74ca..1f57b7c8a9ece13d2f8f85994b47b9bb9086c822 100644 --- ledgerwatch/erigon/Dockerfile.debian +++ testinprod-io/erigon/Dockerfile.debian @@ -95,10 +95,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/testinprod-io/op-erigon.git" \ org.label-schema.version=$VERSION   ENTRYPOINT ["erigon"]
diff --git ledgerwatch/erigon/cmd/rpcdaemon/cli/config.go testinprod-io/erigon/cmd/rpcdaemon/cli/config.go index 8d489c71a67423a39800244e26f07078fff3216e..f33b8f1b629fcdca9160479adb44c7f544dd6f92 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/cli/config.go +++ testinprod-io/erigon/cmd/rpcdaemon/cli/config.go @@ -121,6 +121,10 @@ 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") + if err := rootCmd.MarkPersistentFlagFilename("rpc.accessList", "json"); err != nil { panic(err) }
diff --git ledgerwatch/erigon/cmd/rpcdaemon/cli/httpcfg/http_cfg.go testinprod-io/erigon/cmd/rpcdaemon/cli/httpcfg/http_cfg.go index fb5f41650430e247da36413716f8143479e554ab..9c8733ee7b7dbc118534c8f66dbbdb5add8e5202 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/cli/httpcfg/http_cfg.go +++ testinprod-io/erigon/cmd/rpcdaemon/cli/httpcfg/http_cfg.go @@ -64,4 +64,9 @@ LogDirPath string   BatchLimit int // Maximum number of requests in a batch ReturnDataLimit int // Maximum number of bytes returned from calls (like eth_call) + + // Optimism + RollupSequencerHTTP string + RollupHistoricalRPC string + RollupHistoricalRPCTimeout time.Duration }
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/call_traces_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/call_traces_test.go index a8c7f899f7dfde948569e6ce3ce1298e4b6386e7..bf66cca7ab8f932f0104aa9c002068dd8f16195a 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/call_traces_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/call_traces_test.go @@ -56,7 +56,7 @@ agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) api := NewTraceAPI( - NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), + NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, &httpcfg.HttpCfg{}) // Insert blocks 1 by 1, to tirgget possible "off by one" errors for i := 0; i < chain.Length(); i++ { @@ -104,7 +104,7 @@ }   agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) - api := NewTraceAPI(NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, &httpcfg.HttpCfg{}) + api := NewTraceAPI(NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, &httpcfg.HttpCfg{})   if err = m.InsertChain(chainA); err != nil { t.Fatalf("inserting chainA: %v", err) @@ -167,7 +167,7 @@ t.Fatalf("generate chain: %v", err) } agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) - api := NewTraceAPI(NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, &httpcfg.HttpCfg{}) + api := NewTraceAPI(NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, &httpcfg.HttpCfg{}) // Insert blocks 1 by 1, to tirgget possible "off by one" errors for i := 0; i < chain.Length(); i++ { if err = m.InsertChain(chain.Slice(i, i+1)); err != nil { @@ -193,7 +193,7 @@ func TestFilterAddressIntersection(t *testing.T) { m := stages.Mock(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) - api := NewTraceAPI(NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, &httpcfg.HttpCfg{}) + api := NewTraceAPI(NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, &httpcfg.HttpCfg{})   toAddress1, toAddress2, other := common.Address{1}, common.Address{2}, common.Address{3}
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/corner_cases_support_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/corner_cases_support_test.go index 66011e6b000d98883171bbd40572953419cc4614..92207ffc5d68bc3f3960053946ff84b19b4f0a5b 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/corner_cases_support_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/corner_cases_support_test.go @@ -23,7 +23,7 @@ agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) api := NewEthAPI( - NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), + NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) ctx := context.Background()
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/debug_api.go testinprod-io/erigon/cmd/rpcdaemon/commands/debug_api.go index 35c3bfe076e569b3d3df537103c7f329436beb68..4f9ea09a5cc74b5437f1fc9053b9b8f8bf13c184 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/debug_api.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/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/cmd/rpcdaemon/commands/debug_api_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/debug_api_test.go index bb6bf7765c5daa70d57081e69fae77d6daf0750f..c2eb62530388c3e15489bf28a8849c095a8eb041 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/debug_api_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/debug_api_test.go @@ -55,7 +55,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - baseApi := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + baseApi := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) ethApi := NewEthAPI(baseApi, m.DB, nil, nil, nil, 5000000, 100_000) api := NewPrivateDebugAPI(baseApi, m.DB, 0) for _, tt := range debugTraceTransactionTests { @@ -104,7 +104,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - baseApi := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + baseApi := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) ethApi := NewEthAPI(baseApi, m.DB, nil, nil, nil, 5000000, 100_000) api := NewPrivateDebugAPI(baseApi, m.DB, 0) for _, tt := range debugTraceTransactionTests { @@ -140,7 +140,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - base := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + base := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) api := NewPrivateDebugAPI(base, m.DB, 0) for _, tt := range debugTraceTransactionTests { var buf bytes.Buffer @@ -173,7 +173,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) agg := m.HistoryV3Components() api := NewPrivateDebugAPI( - NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), + NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, 0) for _, tt := range debugTraceTransactionNoRefundTests { var buf bytes.Buffer @@ -207,7 +207,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) agg := m.HistoryV3Components() api := NewPrivateDebugAPI( - NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), + NewBaseApi(nil, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, 0) t.Run("invalid addr", func(t *testing.T) { var block4 *types.Block @@ -304,7 +304,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - base := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + base := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) api := NewPrivateDebugAPI(base, m.DB, 0)   t.Run("valid account", func(t *testing.T) { @@ -367,7 +367,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - base := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + base := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) api := NewPrivateDebugAPI(base, m.DB, 0)   t.Run("correct input", func(t *testing.T) { @@ -470,7 +470,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - base := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + base := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) api := NewPrivateDebugAPI(base, m.DB, 0)   var blockHash0, blockHash1, blockHash3, blockHash10, blockHash12 common.Hash
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_api_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_api_test.go index 6f3fef131b444110d7bb6b9585966b3f20a852e9..349262bc89897e47374bd9c59d0689e8dd042db8 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_api_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_api_test.go @@ -29,7 +29,7 @@ br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) db := m.DB agg := m.HistoryV3Components() - api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), db, nil) + api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), db, nil) balances, err := api.GetBalanceChangesInBlock(context.Background(), myBlockNum) if err != nil { t.Errorf("calling GetBalanceChangesInBlock resulted in an error: %v", err) @@ -52,7 +52,7 @@ db := m.DB agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), db, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), db, nil, nil, nil, 5000000, 100_000) // 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) @@ -64,7 +64,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) // Call GetTransactionReceipt for un-protected transaction if _, err := api.GetTransactionReceipt(context.Background(), common.HexToHash("0x3f3cb8a0e13ed2481f97f53f7095b9cbc78b6ffb779f2d3e565146371a8830ea")); err != nil { t.Errorf("calling GetTransactionReceipt for unprotected tx: %v", err) @@ -79,7 +79,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")   result, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithNumber(0)) @@ -96,7 +96,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")   result, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithHash(m.Genesis.Hash(), false)) @@ -113,7 +113,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")   result, err := api.GetStorageAt(context.Background(), addr, "0x0", rpc.BlockNumberOrHashWithHash(m.Genesis.Hash(), true)) @@ -129,7 +129,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")   offChain, err := core.GenerateChain(m.ChainConfig, m.Genesis, m.Engine, m.DB, 1, func(i int, block *core.BlockGen) { @@ -153,7 +153,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")   offChain, err := core.GenerateChain(m.ChainConfig, m.Genesis, m.Engine, m.DB, 1, func(i int, block *core.BlockGen) { @@ -178,7 +178,7 @@ m, _, orphanedChain := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")   orphanedBlock := orphanedChain[0].Blocks[0] @@ -200,7 +200,7 @@ m, _, orphanedChain := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) addr := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")   orphanedBlock := orphanedChain[0].Blocks[0] @@ -219,7 +219,7 @@ m, _, orphanedChain := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) from := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") to := common.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e")   @@ -245,7 +245,7 @@ m, _, orphanedChain := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) from := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") to := common.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e")
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_block_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_block_test.go index ccc4ddcf1cbdad02b5363823d87f715ebd364148..522d2e8e29e812a4ceb230ba52a6519eab6e39e1 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_block_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_block_test.go @@ -28,7 +28,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) b, err := api.GetBlockByNumber(context.Background(), rpc.LatestBlockNumber, false) expected := common.HexToHash("0x5883164d4100b95e1d8e931b8b9574586a1dea7507941e6ad3c1e3a2591485fd") if err != nil { @@ -61,7 +61,7 @@ t.Error("didn't find forkchoice head hash") } tx.Commit()   - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) block, err := api.GetBlockByNumber(ctx, rpc.LatestBlockNumber, false) if err != nil { t.Errorf("error retrieving block by number: %s", err) @@ -93,7 +93,7 @@ ff.HandlePendingBlock(&txpool.OnPendingBlockReply{ RplBlock: rlpBlock, })   - api := NewEthAPI(NewBaseApi(ff, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(ff, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) b, err := api.GetBlockByNumber(context.Background(), rpc.PendingBlockNumber, false) if err != nil { t.Errorf("error getting block number with pending tag: %s", err) @@ -107,7 +107,7 @@ agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) ctx := context.Background() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) if _, err := api.GetBlockByNumber(ctx, rpc.FinalizedBlockNumber, false); err != nil { assert.ErrorIs(t, rpchelper.UnknownBlockError, err) } @@ -137,7 +137,7 @@ t.Error("didn't find forkchoice finalized hash") } tx.Commit()   - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) block, err := api.GetBlockByNumber(ctx, rpc.FinalizedBlockNumber, false) if err != nil { t.Errorf("error retrieving block by number: %s", err) @@ -152,7 +152,7 @@ agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) ctx := context.Background() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) if _, err := api.GetBlockByNumber(ctx, rpc.SafeBlockNumber, false); err != nil { assert.ErrorIs(t, rpchelper.UnknownBlockError, err) } @@ -182,7 +182,7 @@ t.Error("didn't find forkchoice safe block hash") } tx.Commit()   - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) block, err := api.GetBlockByNumber(ctx, rpc.SafeBlockNumber, false) if err != nil { t.Errorf("error retrieving block by number: %s", err) @@ -198,7 +198,7 @@ br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) ctx := context.Background() stateCache := kvcache.New(kvcache.DefaultCoherentConfig)   - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) blockHash := common.HexToHash("0x6804117de2f3e6ee32953e78ced1db7b20214e0d8c745a03b8fecf7cc8ee76ef")   tx, err := m.DB.BeginRw(ctx) @@ -234,7 +234,7 @@ br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) ctx := context.Background() stateCache := kvcache.New(kvcache.DefaultCoherentConfig)   - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) blockHash := common.HexToHash("0x5883164d4100b95e1d8e931b8b9574586a1dea7507941e6ad3c1e3a2591485fd")   tx, err := m.DB.BeginRw(ctx) @@ -269,7 +269,7 @@ agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) ctx := context.Background() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) blockHash := common.HexToHash("0x6804117de2f3e6ee32953e78ced1db7b20214e0d8c745a03b8fecf7cc8ee76ef")   tx, err := m.DB.BeginRw(ctx) @@ -304,7 +304,7 @@ agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) ctx := context.Background() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000)   blockHash := common.HexToHash("0x5883164d4100b95e1d8e931b8b9574586a1dea7507941e6ad3c1e3a2591485fd")
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_callMany_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_callMany_test.go index 4dbeb9488a161898747644f38e07c9ba2c5d3d12..88b9835689d871470ff327ca4e4f39bb15abe09b 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_callMany_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_callMany_test.go @@ -82,7 +82,7 @@ var secondNonce hexutil.Uint64 = 2   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) + api := NewEthAPI(NewBaseApi(nil, stateCache, contractBackend.BlockReader(), contractBackend.Agg(), false, rpccfg.DefaultEvmCallTimeout, engine, datadir.New(t.TempDir()), nil, nil), db, nil, nil, nil, 5000000, 100_000)   callArgAddr1 := ethapi.CallArgs{From: &address, To: &tokenAddr, Nonce: &nonce, MaxPriorityFeePerGas: (*hexutil.Big)(big.NewInt(1e9)),
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_call_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_call_test.go index bd7bd99becbc16760f93c5bc8a104466638d4135..fa3627763a852606dd351eea74209ebb17481aad 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_call_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_call_test.go @@ -46,7 +46,7 @@ stateCache := kvcache.New(kvcache.DefaultCoherentConfig) ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, stages.Mock(t)) mining := txpool.NewMiningClient(conn) ff := rpchelper.New(ctx, nil, nil, mining, func() {}) - api := NewEthAPI(NewBaseApi(ff, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(ff, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) var from = libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") var to = libcommon.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e") if _, err := api.EstimateGas(context.Background(), &ethapi.CallArgs{ @@ -62,7 +62,7 @@ m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000) var from = libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7") var to = libcommon.HexToAddress("0x0d3ab14bbad3d99f4203bd7a11acb94882050e7e") if _, err := api.Call(context.Background(), ethapi.CallArgs{ @@ -87,7 +87,7 @@ agg := m.HistoryV3Components()   stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000)   callData := hexutil.MustDecode("0x2e64cec1") callDataBytes := hexutility.Bytes(callData) @@ -280,7 +280,7 @@ } agg := m.HistoryV3Components()   stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000)   key := func(b byte) libcommon.Hash { result := libcommon.Hash{} @@ -382,10 +382,10 @@ } defer tx.Rollback()   stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil) + api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil)   latestBlock := rawdb.ReadCurrentBlock(tx) - 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") @@ -420,14 +420,14 @@ } defer tx.Rollback()   stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil) + api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil)   oldestBlock, err := rawdb.ReadBlockByNumber(tx, 0) 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") @@ -462,11 +462,11 @@ } defer tx.Rollback()   stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil) + api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil)   latestBlock := rawdb.ReadCurrentBlock(tx)   - 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") @@ -501,7 +501,7 @@ } defer tx.Rollback()   stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil) + api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil)   currentHeader := rawdb.ReadCurrentHeader(tx) oldestHeader, err := api._blockReader.HeaderByNumber(ctx, tx, 0) @@ -518,7 +518,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") @@ -552,7 +552,7 @@ } defer tx.Rollback()   stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil) + api := NewErigonAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil)   highestBlockNumber := rawdb.ReadCurrentHeader(tx).Number pickedBlock, err := rawdb.ReadBlockByNumber(tx, highestBlockNumber.Uint64()/3) @@ -563,7 +563,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/cmd/rpcdaemon/commands/eth_filters.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_filters.go index 3945b826804230d0a7bbcacb54c6f6bb4e9f1320..0e55bcca22a594824bf7b42f65d010dacca650f1 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_filters.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_filters.go @@ -4,6 +4,7 @@ import ( "context" "strings"   + libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/log/v3"   "github.com/ledgerwatch/erigon/common/debug" @@ -267,6 +268,10 @@ for { select { case h, ok := <-logs: if h != nil { + // avoid null json array for topics + if h.Topics == nil { + h.Topics = []libcommon.Hash{} + } err := notifier.Notify(rpcSub.ID, h) if err != nil { log.Warn("error while notifying subscription", "err", err)
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_filters_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_filters_test.go index 6f5d906bd405a36bdad741194a95557935ddc82f..46cd0fecc08266e6b2c2c12a61ed12fea3f6e51e 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_filters_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_filters_test.go @@ -31,7 +31,7 @@ stateCache := kvcache.New(kvcache.DefaultCoherentConfig) ctx, conn := rpcdaemontest.CreateTestGrpcConn(t, stages.Mock(t)) mining := txpool.NewMiningClient(conn) ff := rpchelper.New(ctx, nil, nil, mining, func() {}) - api := NewEthAPI(NewBaseApi(ff, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, nil, nil, 5000000, 100_000) + api := NewEthAPI(NewBaseApi(ff, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, nil, nil, 5000000, 100_000)   ptf, err := api.NewPendingTransactionFilter(ctx) assert.Nil(err)
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_mining_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_mining_test.go index b740ea838b6205a3b1442734038c3b310c26c602..7c9b29a4feca9fd132188e9488d294224f39b6e8 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_mining_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_mining_test.go @@ -27,7 +27,7 @@ ff := rpchelper.New(ctx, nil, nil, mining, func() {}) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) engine := ethash.NewFaker() api := NewEthAPI(NewBaseApi(ff, stateCache, snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3), nil, false, rpccfg.DefaultEvmCallTimeout, engine, - m.Dirs), nil, nil, nil, mining, 5000000, 100_000) + m.Dirs, nil, nil), nil, nil, nil, mining, 5000000, 100_000) expect := uint64(12345) b, err := rlp.EncodeToBytes(types.NewBlockWithHeader(&types.Header{Number: big.NewInt(int64(expect))})) require.NoError(t, err)
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_system.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_system.go index 4077a6f0366dde8f12a80a2c5ba1b944aa48a40b..7ac65fccced23a249da957b8a32e6d721a101756 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_system.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_system.go @@ -222,7 +222,7 @@ func (b *GasPriceOracleBackend) ChainConfig() *chain.Config { return b.cc } func (b *GasPriceOracleBackend) GetReceipts(ctx context.Context, hash libcommon.Hash) (types.Receipts, error) { - return rawdb.ReadReceiptsByHash(b.tx, hash) + return rawdb.ReadReceiptsByHash(b.cc, b.tx, hash) } func (b *GasPriceOracleBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { return nil, nil
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_system_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/eth_system_test.go index 923a1d477add9262529f4008c1facd9acaea41d3..fd38af495252883d8abf40516c8d19b61421f773 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/eth_system_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/eth_system_test.go @@ -43,7 +43,7 @@ t.Run(testCase.description, func(t *testing.T) { m := createGasPriceTestKV(t, testCase.chainSize) defer m.DB.Close() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - base := NewBaseApi(nil, stateCache, snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3), nil, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + base := NewBaseApi(nil, stateCache, snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3), nil, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) eth := NewEthAPI(base, m.DB, nil, nil, nil, 5000000, 100_000)   ctx := context.Background()
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/gen_traces_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/gen_traces_test.go index 6f674eff2fb666c8cce573d18c56c214719609a0..a9a0ae322a7adf43f5189635511398a905dd67b2 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/gen_traces_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/gen_traces_test.go @@ -32,7 +32,7 @@ m := rpcdaemontest.CreateTestSentryForTraces(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - baseApi := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + baseApi := NewBaseApi(nil, stateCache, br, 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) @@ -120,7 +120,7 @@ m := rpcdaemontest.CreateTestSentryForTraces(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - baseApi := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + baseApi := NewBaseApi(nil, stateCache, br, 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 { @@ -279,7 +279,7 @@ m := rpcdaemontest.CreateTestSentryForTracesCollision(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - baseApi := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs) + baseApi := NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil) api := NewTraceAPI(baseApi, m.DB, &httpcfg.HttpCfg{}) traces, err := api.Transaction(context.Background(), common.HexToHash("0xb2b9fa4c999c1c8370ce1fbd1c4315a9ce7f8421fe2ebed8a9051ff2e4e7e3da"), new(bool)) if err != nil {
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/graphql_api.go testinprod-io/erigon/cmd/rpcdaemon/commands/graphql_api.go index b4f2fb053342395e8252b9dcfc4241803c13b427..b8dd20bc5a92d20923da6e69303436152cc9db44 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/graphql_api.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/graphql_api.go @@ -115,7 +115,8 @@ if err != nil { return nil, err } additionalFields := make(map[string]interface{}) - response, err := ethapi.RPCMarshalBlock(b, inclTx, inclTx, additionalFields) + depositNonces := rawdb.ReadDepositNonces(tx, uint64(number.Int64())) + response, err := ethapi.RPCMarshalBlock(b, inclTx, inclTx, additionalFields, depositNonces) if !inclTx { delete(response, "transactions") // workaround for https://github.com/ledgerwatch/erigon/issues/4989#issuecomment-1218415666 }
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_contract_creator_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_contract_creator_test.go index 65a901dbacfd365a8c94ceda6c9cc40525ec80a9..309ecc27a99c6976ab70740ec2dc512c7573fc2c 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_contract_creator_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_contract_creator_test.go @@ -14,7 +14,7 @@ func TestGetContractCreator(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) - api := NewOtterscanAPI(NewBaseApi(nil, nil, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB) + api := NewOtterscanAPI(NewBaseApi(nil, nil, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB)   addr := libcommon.HexToAddress("0x537e697c7ab75a26f9ecf0ce810e3154dfcaaf44") expectCreator := libcommon.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_search_backward_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_search_backward_test.go index 56026b3ce31ff5faa16da373a653c9c92516275b..af9d2838a282958ed087b3c14932779abab9b3ab 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_search_backward_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_search_backward_test.go @@ -152,7 +152,7 @@ func TestSearchTransactionsBefore(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) - api := NewOtterscanAPI(NewBaseApi(nil, nil, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB) + api := NewOtterscanAPI(NewBaseApi(nil, nil, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB)   addr := libcommon.HexToAddress("0x537e697c7ab75a26f9ecf0ce810e3154dfcaaf44") t.Run("small page size", func(t *testing.T) {
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_transaction_by_sender_and_nonce_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_transaction_by_sender_and_nonce_test.go index 7ca335ed6fc4a13299cba1810ac1edef5bd799ca..aacc670098ba6a0d0d217c73630a60f25832e4db 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/otterscan_transaction_by_sender_and_nonce_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/otterscan_transaction_by_sender_and_nonce_test.go @@ -14,7 +14,7 @@ func TestGetTransactionBySenderAndNonce(t *testing.T) { m, _, _ := rpcdaemontest.CreateTestSentry(t) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) - api := NewOtterscanAPI(NewBaseApi(nil, nil, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB) + api := NewOtterscanAPI(NewBaseApi(nil, nil, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB)   addr := common.HexToAddress("0x537e697c7ab75a26f9ecf0ce810e3154dfcaaf44") expectCreator := common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/send_transaction_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/send_transaction_test.go index 35edda6013bfa346fa90979b2e8b68fe7aa6857a..0c60744ce738660b0c2c10cf169d8d5db18f1e9d 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/send_transaction_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/send_transaction_test.go @@ -74,7 +74,7 @@ txPool := txpool.NewTxpoolClient(conn) ff := rpchelper.New(ctx, nil, txPool, txpool.NewMiningClient(conn), func() {}) stateCache := kvcache.New(kvcache.DefaultCoherentConfig) br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) - api := commands.NewEthAPI(commands.NewBaseApi(ff, stateCache, br, nil, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, nil, txPool, nil, 5000000, 100_000) + api := commands.NewEthAPI(commands.NewBaseApi(ff, stateCache, br, nil, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, nil, txPool, nil, 5000000, 100_000)   buf := bytes.NewBuffer(nil) err = txn.MarshalBinary(buf)
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/trace_adhoc_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/trace_adhoc_test.go index d75e7eef7bd231ed1a855b840682c2a4bd2ba9d9..53c9b302df206c2ec781f533a130b36617c7be73 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/trace_adhoc_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/trace_adhoc_test.go @@ -25,7 +25,7 @@ agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3)   - api := NewTraceAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, &httpcfg.HttpCfg{}) + api := NewTraceAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, &httpcfg.HttpCfg{}) // Call GetTransactionReceipt for transaction which is not in the database var latest = rpc.LatestBlockNumber results, err := api.CallMany(context.Background(), json.RawMessage("[]"), &rpc.BlockNumberOrHash{BlockNumber: &latest}) @@ -45,7 +45,7 @@ agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3)   - api := NewTraceAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, &httpcfg.HttpCfg{}) + api := NewTraceAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, &httpcfg.HttpCfg{}) // Call GetTransactionReceipt for transaction which is not in the database var latest = rpc.LatestBlockNumber results, err := api.CallMany(context.Background(), json.RawMessage(` @@ -75,7 +75,7 @@ agg := m.HistoryV3Components() stateCache := kvcache.New(kvcache.DefaultCoherentConfig) br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3)   - api := NewTraceAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, &httpcfg.HttpCfg{}) + api := NewTraceAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, &httpcfg.HttpCfg{}) var txnHash libcommon.Hash if err := m.DB.View(context.Background(), func(tx kv.Tx) error { b, err := rawdb.ReadBlockByNumber(tx, 6) @@ -106,7 +106,7 @@ agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3)   stateCache := kvcache.New(kvcache.DefaultCoherentConfig) - api := NewTraceAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, &httpcfg.HttpCfg{}) + api := NewTraceAPI(NewBaseApi(nil, stateCache, br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs, nil, nil), m.DB, &httpcfg.HttpCfg{})   // Call GetTransactionReceipt for transaction which is not in the database n := rpc.BlockNumber(6)
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/trace_types.go testinprod-io/erigon/cmd/rpcdaemon/commands/trace_types.go index a905d3a4c8a20998c96912589bafbb882484b52d..6f2ed25e4788bb856275a56ef1c49d0582cbbea5 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/trace_types.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/trace_types.go @@ -20,17 +20,17 @@ // directly with existing Parity tests   // GethTrace The trace as received from the existing Geth javascript tracer 'callTracer' type GethTrace struct { - Type string `json:"type"` - Error string `json:"error"` - From string `json:"from"` - To string `json:"to"` - Value string `json:"value"` - Gas string `json:"gas"` - GasUsed string `json:"gasUsed"` - Input string `json:"input"` - Output string `json:"output"` - Time string `json:"time"` - Calls GethTraces `json:"calls"` + Type string `json:"type,omitempty"` + Error string `json:"error,omitempty"` + From string `json:"from,omitempty"` + To string `json:"to,omitempty"` + Value string `json:"value,omitempty"` + Gas string `json:"gas,omitempty"` + GasUsed string `json:"gasUsed,omitempty"` + Input string `json:"input,omitempty"` + Output string `json:"output,omitempty"` + Time string `json:"time,omitempty"` + Calls GethTraces `json:"calls,omitempty"` }   // GethTraces an array of GethTraces
diff --git ledgerwatch/erigon/cmd/rpcdaemon/commands/txpool_api_test.go testinprod-io/erigon/cmd/rpcdaemon/commands/txpool_api_test.go index fe6fd07fd4c4448a44cd1b2de9db41b8b71c24c0..cca59f3f685cab7a3de7fcd86df77079969d5c39 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/commands/txpool_api_test.go +++ testinprod-io/erigon/cmd/rpcdaemon/commands/txpool_api_test.go @@ -37,7 +37,7 @@ txPool := txpool.NewTxpoolClient(conn) ff := rpchelper.New(ctx, nil, txPool, txpool.NewMiningClient(conn), func() {}) agg := m.HistoryV3Components() br := snapshotsync.NewBlockReaderWithSnapshots(m.BlockSnapshots, m.TransactionsV3) - api := NewTxPoolAPI(NewBaseApi(ff, kvcache.New(kvcache.DefaultCoherentConfig), br, agg, false, rpccfg.DefaultEvmCallTimeout, m.Engine, m.Dirs), m.DB, txPool) + api := NewTxPoolAPI(NewBaseApi(ff, kvcache.New(kvcache.DefaultCoherentConfig), br, 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/cmd/rpcdaemon/graphql/graph/helpers.go testinprod-io/erigon/cmd/rpcdaemon/graphql/graph/helpers.go index 4bc6c7da4e681865739d45a53f265196c753e7de..7bf46967739ffa2eee6ea10662c11da0c1b75d14 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/graphql/graph/helpers.go +++ testinprod-io/erigon/cmd/rpcdaemon/graphql/graph/helpers.go @@ -18,6 +18,10 @@ func convertDataToStringP(abstractMap map[string]interface{}, field string) *string { var result string   + if reflect.ValueOf(abstractMap[field]).IsZero() { + return nil + } + switch v := abstractMap[field].(type) { case int64: result = strconv.FormatInt(v, 10)
diff --git ledgerwatch/erigon/cmd/rpcdaemon/main.go testinprod-io/erigon/cmd/rpcdaemon/main.go index 3db874b510631a9e411f7a13fbd9ddd32267ed3a..299c7a3f028d1ab78c791e465804181d8393a1b7 100644 --- ledgerwatch/erigon/cmd/rpcdaemon/main.go +++ testinprod-io/erigon/cmd/rpcdaemon/main.go @@ -1,12 +1,15 @@ package main   import ( + "context" "os" + "time"   "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli" "github.com/ledgerwatch/erigon/cmd/rpcdaemon/commands" "github.com/ledgerwatch/erigon/consensus/ethash" + "github.com/ledgerwatch/erigon/rpc" "github.com/ledgerwatch/erigon/turbo/logging" "github.com/ledgerwatch/log/v3" "github.com/spf13/cobra" @@ -28,9 +31,34 @@ if borDb != nil { defer borDb.Close() }   + 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) + cancel() + if err != nil { + log.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) + cancel() + if err != nil { + log.Error(err.Error()) + return nil + } + historicalRPCService = client + } + // TODO: Replace with correct consensus Engine engine := ethash.NewFaker() - apiList := commands.APIList(db, borDb, backend, txPool, mining, ff, stateCache, blockReader, agg, *cfg, engine) + apiList := commands.APIList(db, borDb, backend, txPool, mining, ff, stateCache, blockReader, agg, *cfg, engine, seqRPCService, historicalRPCService) if err := cli.StartRpcServer(ctx, *cfg, apiList, nil); err != nil { log.Error(err.Error()) return nil
diff --git ledgerwatch/erigon/cmd/sentry/sentry/sentry_multi_client.go testinprod-io/erigon/cmd/sentry/sentry/sentry_multi_client.go index b56b1cd100618cd10047bb309ab1a6534867c207..5554d6e43664f3847e09911537776ac1ee0b419b 100644 --- ledgerwatch/erigon/cmd/sentry/sentry/sentry_multi_client.go +++ testinprod-io/erigon/cmd/sentry/sentry/sentry_multi_client.go @@ -670,7 +670,7 @@ if err != nil { return err } defer tx.Rollback() - receipts, err := eth.AnswerGetReceiptsQuery(tx, query.GetReceiptsPacket) + receipts, err := eth.AnswerGetReceiptsQuery(cs.ChainConfig, tx, query.GetReceiptsPacket) if err != nil { return err }
diff --git ledgerwatch/erigon/common/hexutil/hexutil.go testinprod-io/erigon/common/hexutil/hexutil.go index 3df5272075c795bba8d566c6e40a1ff5594b734a..5dc731f15b180ee0addfc97562a921ed63cc35b5 100644 --- ledgerwatch/erigon/common/hexutil/hexutil.go +++ testinprod-io/erigon/common/hexutil/hexutil.go @@ -56,6 +56,14 @@ type decError struct{ msg string }   func (err decError) Error() string { return err.msg }   +// Encode encodes b as a hex string with 0x prefix. +func Encode(b []byte) string { + enc := make([]byte, len(b)*2+2) + copy(enc, "0x") + hex.Encode(enc[2:], b) + return string(enc) +} + // Decode decodes a hex string with 0x prefix. func Decode(input string) ([]byte, error) { if len(input) == 0 {
diff --git ledgerwatch/erigon/core/blockchain.go testinprod-io/erigon/core/blockchain.go index 39695039ea7bde89e4f8aa54358bd7133e6e2298..5b74da3cf24b4aa3ead1396c056d58a93b84bff3 100644 --- ledgerwatch/erigon/core/blockchain.go +++ testinprod-io/erigon/core/blockchain.go @@ -333,8 +333,9 @@ 0, u256.Num0, math.MaxUint64, u256.Num0, nil, nil, data, nil, false, - true, // isFree - nil, // maxFeePerDataGas + true, // isFree + false, // isFake + nil, // maxFeePerDataGas ) vmConfig := vm.Config{NoReceipts: true, RestoreState: constCall} // Create a new context to be used in the EVM environment @@ -377,8 +378,9 @@ 0, u256.Num0, math.MaxUint64, u256.Num0, nil, nil, data, nil, false, - true, // isFree - nil, // maxFeePerDataGas + true, // isFree + false, // isFake + nil, // maxFeePerDataGas ) vmConfig := vm.Config{NoReceipts: true} // Create a new context to be used in the EVM environment
diff --git ledgerwatch/erigon/core/error.go testinprod-io/erigon/core/error.go index 82782407dd511da37a82d26c60c962f639e23224..45fcf52e33dc90d909a9f0dd76872709bf0b3ed8 100644 --- ledgerwatch/erigon/core/error.go +++ testinprod-io/erigon/core/error.go @@ -99,4 +99,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") )
diff --git ledgerwatch/erigon/core/genesis_write.go testinprod-io/erigon/core/genesis_write.go index 0c3855588e8b30ea6a8e57bf0c94e9d72b432845..a156f9ee57d28c862c37e8960f38e35c13e4b88b 100644 --- ledgerwatch/erigon/core/genesis_write.go +++ testinprod-io/erigon/core/genesis_write.go @@ -96,6 +96,9 @@ applyOverrides := func(config *chain.Config) { if overrideShanghaiTime != nil { config.ShanghaiTime = overrideShanghaiTime } + if config.IsOptimism() && config.ChainID != nil && config.ChainID.Cmp(params.OptimismGoerliChainConfig.ChainID) == 0 { + config.RegolithTime = params.OptimismGoerliChainConfig.RegolithTime + } }   if (storedHash == libcommon.Hash{}) { @@ -405,6 +408,17 @@ Alloc: readPrealloc("allocs/bor_devnet.json"), } }   +func DefaultOptimismGoerliGenesisBlock() *types.Genesis { + return &types.Genesis{ + Config: params.OptimismGoerliChainConfig, + Difficulty: big.NewInt(1), + Mixhash: libcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + ExtraData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000000027770a9694e4b4b1e130ab91bc327c36855f612e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + GasLimit: 15000000, + Alloc: readPrealloc("allocs/optimism-goerli.json"), + } +} + func GnosisGenesisBlock() *types.Genesis { return &types.Genesis{ Config: params.GnosisChainConfig, @@ -616,6 +630,8 @@ case networkname.BorMainnetChainName: return BorMainnetGenesisBlock() case networkname.BorDevnetChainName: return BorDevnetGenesisBlock() + case networkname.OptimismGoerliChainName: + return DefaultOptimismGoerliGenesisBlock() case networkname.GnosisChainName: return GnosisGenesisBlock() case networkname.ChiadoChainName:
diff --git ledgerwatch/erigon/core/types/blob_tx_wrapper.go testinprod-io/erigon/core/types/blob_tx_wrapper.go index fe036c683b35e3c60188673ab51daa345ef3c8f2..e9552a8732e2d9385719f26e2ea80cc8841424dd 100644 --- ledgerwatch/erigon/core/types/blob_tx_wrapper.go +++ testinprod-io/erigon/core/types/blob_tx_wrapper.go @@ -437,3 +437,7 @@ return err } return rlp.Encode(w, buf.Bytes()) } + +func (txw *BlobTxWrapper) RollupDataGas() RollupGasData { + return txw.Tx.RollupDataGas() +}
diff --git ledgerwatch/erigon/core/types/signed_blob_tx.go testinprod-io/erigon/core/types/signed_blob_tx.go index ca8354ecef915d7f0df59978cccd16ed7e0652f0..8d5a9383cc43047de29ca5cc6e7f926c6bed9f16 100644 --- ledgerwatch/erigon/core/types/signed_blob_tx.go +++ testinprod-io/erigon/core/types/signed_blob_tx.go @@ -594,3 +594,9 @@ func (stx *SignedBlobTx) FixedLength() uint64 { return 0 } + +func (stx *SignedBlobTx) RollupDataGas() RollupGasData { + // RollupDataGas is a method for calculating L1 cost on L2. + // Because blob TX is not supported on L2, this method must not be called. + panic("BlobTx is not supported on L2") +}
diff --git ledgerwatch/erigon/core/vm/evm.go testinprod-io/erigon/core/vm/evm.go index 632ee1d0dcc721fce28bd78887c24095cacc096e..d64daec310fb18de7ddc58bddcf12317e27d3ac7 100644 --- ledgerwatch/erigon/core/vm/evm.go +++ testinprod-io/erigon/core/vm/evm.go @@ -50,6 +50,10 @@ p, ok := precompiles[addr] return p, ok }   +func (evm *EVM) Precompile(addr libcommon.Address) (PrecompiledContract, bool) { + return evm.precompile(addr) +} + // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { return evm.interpreter.Run(contract, input, readOnly)
diff --git ledgerwatch/erigon/eth/gasprice/gasprice_test.go testinprod-io/erigon/eth/gasprice/gasprice_test.go index fb73a02e787fcfcc26a2db9b04198a1240d113b3..184f8c1885a64db56534696e732d93794447cd23 100644 --- ledgerwatch/erigon/eth/gasprice/gasprice_test.go +++ testinprod-io/erigon/eth/gasprice/gasprice_test.go @@ -50,7 +50,7 @@ if err != nil { return nil, err } defer tx.Rollback() - return rawdb.ReadReceiptsByHash(tx, hash) + return rawdb.ReadReceiptsByHash(b.cfg, tx, hash) }   func (b *testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) {
diff --git ledgerwatch/erigon/eth/protocols/eth/handler_test.go testinprod-io/erigon/eth/protocols/eth/handler_test.go index f632d133dcadbd3848cd8d3789f1c5348bd34264..699afb66a8143ee6bcf8d8d04bfbe30906a583a4 100644 --- ledgerwatch/erigon/eth/protocols/eth/handler_test.go +++ testinprod-io/erigon/eth/protocols/eth/handler_test.go @@ -95,7 +95,7 @@ block := rawdb.ReadHeaderByNumber(tx, i)   hashes = append(hashes, block.Hash()) // If known, encode and queue for response packet - r, err := rawdb.ReadReceiptsByHash(tx, block.Hash()) + r, err := rawdb.ReadReceiptsByHash(params.TestChainConfig, tx, block.Hash()) if err != nil { return err }
diff --git ledgerwatch/erigon/eth/protocols/eth/handlers.go testinprod-io/erigon/eth/protocols/eth/handlers.go index 9be97f2b29536b50faf84264275e2fc60374a3cf..05b1de6a08fed2b4d929ef1f2bd76eb072cfbe6c 100644 --- ledgerwatch/erigon/eth/protocols/eth/handlers.go +++ testinprod-io/erigon/eth/protocols/eth/handlers.go @@ -19,6 +19,7 @@ import ( "context" "fmt" + "github.com/ledgerwatch/erigon-lib/chain"   libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" @@ -166,7 +167,7 @@ } return bodies }   -func AnswerGetReceiptsQuery(db kv.Tx, query GetReceiptsPacket) ([]rlp.RawValue, error) { //nolint:unparam +func AnswerGetReceiptsQuery(chainCfg *chain.Config, db kv.Tx, query GetReceiptsPacket) ([]rlp.RawValue, error) { //nolint:unparam // Gather state data until the fetch or network limits is reached var ( bytes int @@ -178,7 +179,7 @@ lookups >= 2*maxReceiptsServe { break } // Retrieve the requested block's receipts - results, err := rawdb.ReadReceiptsByHash(db, hash) + results, err := rawdb.ReadReceiptsByHash(chainCfg, db, hash) if err != nil { return nil, err }
diff --git ledgerwatch/erigon/eth/tracers/api.go testinprod-io/erigon/eth/tracers/api.go index d246499924851953bac73e843e2316ea1b7720fb..402b92c1a97b9c79a506a330b7ce6c7b1a984c98 100644 --- ledgerwatch/erigon/eth/tracers/api.go +++ testinprod-io/erigon/eth/tracers/api.go @@ -10,13 +10,13 @@ // TraceConfig holds extra parameters to trace functions. type TraceConfig struct { *logger.LogConfig - Tracer *string - TracerConfig *json.RawMessage - Timeout *string - Reexec *uint64 - NoRefunds *bool // Turns off gas refunds when tracing - StateOverrides *ethapi.StateOverrides + Tracer *string `json:"tracer"` + TracerConfig *json.RawMessage `json:"tracerConfig,omitempty"` + Timeout *string `json:"timeout,omitempty"` + Reexec *uint64 `json:"reexec,omitempty"` + NoRefunds *bool `json:"-"` // Turns off gas refunds when tracing + StateOverrides *ethapi.StateOverrides `json:"-"`   - BorTraceEnabled *bool - BorTx *bool + BorTraceEnabled *bool `json:"-"` + BorTx *bool `json:"-"` }
diff --git ledgerwatch/erigon/forkdiff.yaml testinprod-io/erigon/forkdiff.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e9312585697c022a43a19cc6a11be566744d82b5 --- /dev/null +++ testinprod-io/erigon/forkdiff.yaml @@ -0,0 +1,183 @@ +title: "op-erigon" # Define the HTML page title +footer: | # define the footer with markdown + Fork-diff overview of [op-erigon](https://github.com/testinprod-io/erigon), a fork of [erigon](https://github.com/ledgerwatch/erigon). and execution-engine of the [OP Stack](https://github.com/ethereum-optimism/optimism). +base: + name: ledgerwatch/erigon + url: https://github.com/ledgerwatch/erigon + ref: refs/tags/v2.38.1 +fork: + name: testinprod-io/erigon + url: https://github.com/testinprod-io/erigon + ref: refs/heads/op-erigon +def: + title: "op-erigon" + description: | # description in markdown + This is an overview of the changes in [op-erigon](https://github.com/testinprod-io/erigon), a fork of [erigon](https://github.com/ledgerwatch/erigon), part of the OP Stack. + + There are two more forks of erigon dependencies: + + - [op-erigon-lib](./erigon-lib.html) + - [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" + - 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" + - "cmd/rpcdaemon/commands/trace_adhoc.go" + - "cmd/rpcdaemon/commands/trace_filtering.go" + - "cmd/rpcdaemon/commands/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" + - 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" + - 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: + - "cmd/rpcdaemon/commands/engine_api.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: + - "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/stage_mining_force_txs.go" + - "eth/stagedsync/stagebuilder.go" + - "core/block_builder_parameters.go" + - "params/mining.go" + - "core/chain_makers.go" + - "eth/stagedsync/stage_mining_exec_test.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/genesis.go" + - "params/networkname/network_name.go" + - "params/chainspecs/optimism-goerli.json" + - "core/allocs/optimism-goerli.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" + - "cmd/rpcdaemon/commands/eth_receipts.go" + - "cmd/rpcdaemon/commands/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/erigon-el/backend/backend.go" + - "cmd/rpcdaemon/commands/daemon.go" + - "eth/backend.go" + - "cmd/rpcdaemon/commands/eth_accounts.go" + - "cmd/rpcdaemon/commands/eth_call.go" + - "cmd/rpcdaemon/commands/send_transaction.go" + - "rpc/errors.go" + - title: "Transaction & Block response" + description: | + Format deposit and L1-cost data in transaction responses. + globs: + - "cmd/rpcdaemon/commands/eth_api.go" + - "turbo/adapter/ethapi/api.go" + - "turbo/adapter/ethapi/internal.go" + - "cmd/rpcdaemon/commands/erigon_block.go" + - "cmd/rpcdaemon/commands/eth_block.go" + - "cmd/rpcdaemon/commands/eth_txs.go" + - "cmd/rpcdaemon/commands/eth_uncles.go" + - title: "Otterscan API" + globs: + - "cmd/rpcdaemon/commands/otterscan_api.go" + - "cmd/rpcdaemon/commands/otterscan_block_details.go" + - "cmd/rpcdaemon/commands/otterscan_contract_creator.go" + - "cmd/rpcdaemon/commands/otterscan_generic_tracer.go" + - "cmd/rpcdaemon/commands/otterscan_search_trace.go" + - title: "Generated files" + globs: + - "core/types/receipt_codecgen_gen.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: + - "*.sum" + - ".gitignore" + - ".github/**/*" + - "Dockerfile" + - "cmd/downloader/recompress.sh" + - "cmd/downloader/torrent_hashes_update.sh" + - "README.md" + - "Makefile" \ No newline at end of file
diff --git ledgerwatch/erigon/go.mod testinprod-io/erigon/go.mod index 38a4f09af9bcb7a0e43bd4acefcf40787558a223..9a64564e377ae451fb1b106be810dd5672bc965f 100644 --- ledgerwatch/erigon/go.mod +++ testinprod-io/erigon/go.mod @@ -2,6 +2,12 @@ module github.com/ledgerwatch/erigon   go 1.19   +//fork with minor protobuf file changes and txpool support +replace github.com/ledgerwatch/erigon-lib v0.0.0-20230423044930-fc9dd74e6407 => github.com/testinprod-io/erigon-lib v0.0.0-20230510042408-cab68978c512 + +//for local dev: +//replace github.com/ledgerwatch/erigon-lib v0.0.0-20230423044930-fc9dd74e6407 => ../erigon-lib + require ( github.com/ledgerwatch/erigon-lib v0.0.0-20230423044930-fc9dd74e6407 github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20230404044759-5dec854ce336
diff --git ledgerwatch/erigon/node/nodecfg/defaults.go testinprod-io/erigon/node/nodecfg/defaults.go index 611208c55ea3da2f9e9daf75d56b839b070b1661..246b7351cd1476cedc280e6270851f96f6ce9ddd 100644 --- ledgerwatch/erigon/node/nodecfg/defaults.go +++ testinprod-io/erigon/node/nodecfg/defaults.go @@ -17,7 +17,9 @@ package nodecfg   import ( + "github.com/c2h5oh/datasize" "github.com/ledgerwatch/erigon-lib/common/datadir" + "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon/common/paths" "github.com/ledgerwatch/erigon/p2p" "github.com/ledgerwatch/erigon/p2p/nat" @@ -52,4 +54,6 @@ MaxPeers: 100, MaxPendingPeers: 1000, NAT: nat.Any(), }, + MdbxPageSize: datasize.ByteSize(kv.DefaultPageSize()), + MdbxDBSizeLimit: 7 * datasize.TB, }
diff --git ledgerwatch/erigon/rpc/rpccfg/rpccfg.go testinprod-io/erigon/rpc/rpccfg/rpccfg.go index f1cde689c78d917d117656fa44f7ca02cccbe506..b7b936eaf05f5264de4e962fac21fe26e01a30c3 100644 --- ledgerwatch/erigon/rpc/rpccfg/rpccfg.go +++ testinprod-io/erigon/rpc/rpccfg/rpccfg.go @@ -37,3 +37,5 @@ IdleTimeout: 120 * time.Second, }   const DefaultEvmCallTimeout = 5 * time.Minute + +const DefaultHistoricalRPCTimeout = 5 * time.Second
diff --git ledgerwatch/erigon/tests/automated-testing/docker-compose.yml testinprod-io/erigon/tests/automated-testing/docker-compose.yml index aec7614b7930c3ab4a5a22c9e782eac0f4bdefcb..23a46c47a80f0b4c3649a252b1f042aad180b8fb 100644 --- ledgerwatch/erigon/tests/automated-testing/docker-compose.yml +++ testinprod-io/erigon/tests/automated-testing/docker-compose.yml @@ -4,7 +4,7 @@ services: erigon: profiles: - first - image: thorax/erigon:$ERIGON_TAG + image: testinprod/op-erigon:$ERIGON_TAG command: | --datadir=/home/erigon/.local/share/erigon --chain=dev --private.api.addr=0.0.0.0:9090 --mine --log.dir.path=/logs/node1 ports: @@ -19,7 +19,7 @@ erigon-node2: profiles: - second - image: thorax/erigon:$ERIGON_TAG + image: testinprod/op-erigon:$ERIGON_TAG command: | --datadir=/home/erigon/.local/share/erigon --chain=dev --private.api.addr=0.0.0.0:9090 --staticpeers=$ENODE --log.dir.path=/logs/node2 volumes: @@ -32,7 +32,7 @@ rpcdaemon: profiles: - first - image: thorax/erigon:$ERIGON_TAG + image: testinprod/op-erigon:$ERIGON_TAG entrypoint: rpcdaemon command: | --private.api.addr=erigon:9090 --http.api=admin,eth,erigon,web3,net,debug,trace,txpool,parity --http.addr=0.0.0.0 --http.vhosts=* --http.corsdomain=* --http.port=8545 --graphql --log.dir.path=/logs/node1 @@ -44,7 +44,7 @@ rpcdaemon-node2: profiles: - second - image: thorax/erigon:$ERIGON_TAG + image: testinprod/op-erigon:$ERIGON_TAG entrypoint: rpcdaemon command: | --private.api.addr=erigon-node2:9090 --http.api=admin,eth,erigon,web3,net,debug,trace,txpool,parity --http.addr=0.0.0.0 --http.vhosts=* --http.corsdomain=* --http.port=8545 --log.dir.path=/logs/node2
diff --git ledgerwatch/erigon/tests/automated-testing/run.sh testinprod-io/erigon/tests/automated-testing/run.sh index a21fb908aa3efc07b86ce294e01ed9626a70aa2c..bd15e4cda5416c4fd52c8869c1c27bba9719f6f9 100755 --- ledgerwatch/erigon/tests/automated-testing/run.sh +++ testinprod-io/erigon/tests/automated-testing/run.sh @@ -34,7 +34,7 @@ echo "BUILD_ERIGON=$BUILD_ERIGON"   if [ "$BUILD_ERIGON" = 1 ] ; then echo "building erigon..." - cd ../../ && DOCKER_TAG=thorax/erigon:$ERIGON_TAG DOCKER_UID=$(id -u) DOCKER_GID=$(id -g) make docker + cd ../../ && DOCKER_TAG=testinprod/op-erigon:$ERIGON_TAG DOCKER_UID=$(id -u) DOCKER_GID=$(id -g) make docker fi   # move back to the script directory
diff --git ledgerwatch/erigon/tests/state_test_util.go testinprod-io/erigon/tests/state_test_util.go index c972b4b01415556c4d5bdd1bde12f4aa2a2d102c..57d58493db1c436a39aaf301277bf98625e98f37 100644 --- ledgerwatch/erigon/tests/state_test_util.go +++ testinprod-io/erigon/tests/state_test_util.go @@ -456,6 +456,7 @@ data, accessList, false, /* checkNonce */ false, /* isFree */ + false, /* isFake */ uint256.NewInt(tipCap.Uint64()), )
diff --git ledgerwatch/erigon/turbo/adapter/ethapi/api_test.go testinprod-io/erigon/turbo/adapter/ethapi/api_test.go new file mode 100644 index 0000000000000000000000000000000000000000..9874853cbe336768f18639016345636dc4561a44 --- /dev/null +++ testinprod-io/erigon/turbo/adapter/ethapi/api_test.go @@ -0,0 +1,129 @@ +package ethapi + +import ( + "encoding/json" + "math/big" + "testing" + + "github.com/holiman/uint256" + libcommon "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/core/types" + "github.com/stretchr/testify/require" +) + +func TestNewRPCTransactionDepositTx(t *testing.T) { + tx := &types.DepositTx{ + SourceHash: libcommon.HexToHash("0x1234"), + IsSystemTransaction: true, + Mint: uint256.NewInt(34), + Value: uint256.NewInt(1337), + } + nonce := uint64(7) + depositNonce := &nonce + got := newRPCTransaction(tx, libcommon.Hash{}, uint64(12), uint64(1), big.NewInt(0), depositNonce) + // 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().Mint = %v, want %v", got.Nonce, nonce) +} + +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) { + 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, + }, + } + 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") + } + }) + } +}
diff --git ledgerwatch/erigon/turbo/cli/flags.go testinprod-io/erigon/turbo/cli/flags.go index f4746770bd763e9e82d0042f5a3a93bd33f8b843..305fb2d720428f06db5c4ac25f5c9b2e80efd3fc 100644 --- ledgerwatch/erigon/turbo/cli/flags.go +++ testinprod-io/erigon/turbo/cli/flags.go @@ -400,6 +400,10 @@ TxPoolApiAddr: ctx.String(utils.TxpoolApiAddrFlag.Name),   StateCache: kvcache.DefaultCoherentConfig, + + RollupSequencerHTTP: ctx.String(utils.RollupSequencerHTTPFlag.Name), + RollupHistoricalRPC: ctx.String(utils.RollupHistoricalRPCFlag.Name), + RollupHistoricalRPCTimeout: ctx.Duration(utils.RollupHistoricalRPCTimeoutFlag.Name), } if ctx.IsSet(utils.HttpCompressionFlag.Name) { c.HttpCompression = ctx.Bool(utils.HttpCompressionFlag.Name)
diff --git ledgerwatch/erigon/turbo/stages/blockchain_test.go testinprod-io/erigon/turbo/stages/blockchain_test.go index ee8ca992d7be64d59671caca19a6700947d7d2b1..dbf145026f1c67da491f7ca3d688854efbaac5d2 100644 --- ledgerwatch/erigon/turbo/stages/blockchain_test.go +++ testinprod-io/erigon/turbo/stages/blockchain_test.go @@ -486,7 +486,7 @@ for i, txn := range txs { if txn, _, _, _, _ := rawdb.ReadTransactionByHash(tx, txn.Hash()); txn != nil { t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn) } - if rcpt, _, _, _, _ := rawdb.ReadReceipt(tx, txn.Hash()); rcpt != nil { + if rcpt, _, _, _, _ := rawdb.ReadReceipt(params.TestChainConfig, tx, txn.Hash()); rcpt != nil { t.Errorf("drop %d: receipt %v found while shouldn't have been", i, rcpt) } } @@ -502,7 +502,7 @@ if m.HistoryV3 { // m.HistoryV3 doesn't store } else { - if rcpt, _, _, _, _ := rawdb.ReadReceipt(tx, txn.Hash()); rcpt == nil { + if rcpt, _, _, _, _ := rawdb.ReadReceipt(params.TestChainConfig, tx, txn.Hash()); rcpt == nil { t.Errorf("add %d: expected receipt to be found", i) } } @@ -516,7 +516,7 @@ } if m.HistoryV3 { // m.HistoryV3 doesn't store } else { - if rcpt, _, _, _, _ := rawdb.ReadReceipt(tx, txn.Hash()); rcpt == nil { + if rcpt, _, _, _, _ := rawdb.ReadReceipt(params.TestChainConfig, tx, txn.Hash()); rcpt == nil { t.Errorf("share %d: expected receipt to be found", i) } }
diff --git ledgerwatch/erigon/turbo/stages/mock_sentry.go testinprod-io/erigon/turbo/stages/mock_sentry.go index 535f611063bf81237c897a6e602b0347f2e20b75..bd35be4c241b557d596122f8e55cb633cf902cb6 100644 --- ledgerwatch/erigon/turbo/stages/mock_sentry.go +++ testinprod-io/erigon/turbo/stages/mock_sentry.go @@ -493,7 +493,7 @@ mock.MinedBlocks = miner.MiningResultCh mock.MiningSync = stagedsync.New( stagedsync.MiningStages(mock.Ctx, stagedsync.StageMiningCreateBlockCfg(mock.DB, miner, *mock.ChainConfig, mock.Engine, mock.TxPool, nil, nil, dirs.Tmp), - stagedsync.StageMiningExecCfg(mock.DB, miner, nil, *mock.ChainConfig, mock.Engine, &vm.Config{}, dirs.Tmp, nil, 0, mock.TxPool, nil, mock.BlockSnapshots, cfg.TransactionsV3), + stagedsync.StageMiningExecCfg(mock.DB, miner, nil, *mock.ChainConfig, mock.Engine, &vm.Config{}, dirs.Tmp, nil, 0, mock.TxPool, nil, false, mock.BlockSnapshots, cfg.TransactionsV3), stagedsync.StageHashStateCfg(mock.DB, dirs, cfg.HistoryV3, mock.agg), stagedsync.StageTrieCfg(mock.DB, false, true, false, dirs.Tmp, blockReader, mock.sentriesClient.Hd, cfg.HistoryV3, mock.agg), stagedsync.StageMiningFinishCfg(mock.DB, *mock.ChainConfig, mock.Engine, miner, miningCancel),
diff --git ledgerwatch/erigon/.github/workflows/ci.yml testinprod-io/erigon/.github/workflows/ci.yml index 5c3d4962121e0b57279e218895b93775f9dbca83..b8969e54880f48dff15188cf3d347373211e628e 100644 --- ledgerwatch/erigon/.github/workflows/ci.yml +++ testinprod-io/erigon/.github/workflows/ci.yml @@ -5,11 +5,13 @@ branches: - devel - alpha - stable + - op-erigon pull_request: branches: - devel - alpha - stable + - op-erigon types: - opened - reopened @@ -100,11 +102,11 @@ with: fetch-depth: 0 # fetch git tags for "git describe"   - name: make docker (see dockerhub for image builds) - run: DOCKER_TAG=thorax/erigon:ci-$GITHUB_SHA DOCKER_UID=$(id -u) DOCKER_GID=$(id -g) make docker + run: DOCKER_TAG=testinprod/op-erigon:ci-$GITHUB_SHA DOCKER_UID=$(id -u) DOCKER_GID=$(id -g) make docker   # check with root permissions, should be cached from previous build - name: sudo make docker - run: sudo DOCKER_TAG=thorax/erigon:ci-$GITHUB_SHA DOCKER_UID=$(id -u) DOCKER_GID=$(id -g) make docker + run: sudo DOCKER_TAG=testinprod/op-erigon:ci-$GITHUB_SHA DOCKER_UID=$(id -u) DOCKER_GID=$(id -g) make docker   automated-tests: runs-on:
diff --git ledgerwatch/erigon/.github/workflows/hive-nightly.yml testinprod-io/erigon/.github/workflows/hive-nightly.yml deleted file mode 100644 index 6097ab06f8052b609f63847f931ad07788bd72b0..0000000000000000000000000000000000000000 --- ledgerwatch/erigon/.github/workflows/hive-nightly.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Hive (Nightly) - -on: - schedule: - - cron: "0 01 * * *" # run at 1 am UTC every day - workflow_dispatch: - -jobs: - hive: - runs-on: ubuntu-latest - steps: - - uses: AutoModality/action-clean@v1 - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # fetch git tags for "git describe" - - - name: build erigon image - run: DOCKER_TAG=thorax/erigon:ci-$GITHUB_SHA DOCKER_UID=$(id -u) DOCKER_GID=$(id -g) make docker - - # check with root permissions, should be cached from previous build - - name: build erigon image (root permissions) - run: sudo DOCKER_TAG=thorax/erigon:ci-$GITHUB_SHA DOCKER_UID=$(id -u) DOCKER_GID=$(id -g) make docker - - - name: run hive and parse output - run: | - sudo mkdir -p /results-${{ github.run_id }} - docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v ${{ github.workspace }}:/work thorax/hive:latest --sim ethereum/engine --results-root=/work/results-${{ github.run_id }} --client erigon_ci-$GITHUB_SHA --exit.fail=false - docker run --rm --pull always -v /var/run/docker.sock:/var/run/docker.sock -v ${{ github.workspace }}:/work --entrypoint /app/hivecioutput thorax/hive:latest --resultsdir=/work/results-${{ github.run_id }} --outdir=/work/results-${{ github.run_id }} --exclusionsfile=/work/hive/exclusions.json - - - name: clean up containers - if: always() - run: | - ids=$(docker ps -a -q) - for id in $ids - do - echo "stopping/removing container: $id" - docker stop $id && docker rm $id - done - - - name: parse hive results - uses: phoenix-actions/test-reporting@v10 - with: - name: Tests - path: results-${{ github.run_id }}/*.xml - reporter: java-junit \ No newline at end of file
diff --git ledgerwatch/erigon/.github/workflows/hive.yml testinprod-io/erigon/.github/workflows/hive.yml new file mode 100644 index 0000000000000000000000000000000000000000..eb1b27bbb7247af71622db8995570c782cfe43ec --- /dev/null +++ testinprod-io/erigon/.github/workflows/hive.yml @@ -0,0 +1,62 @@ +name: Hive + +on: + push: + branches: + - devel + - alpha + - stable + - op-erigon + pull_request: + branches: + - devel + - alpha + - stable + - op-erigon + types: + - opened + - reopened + - synchronize + - ready_for_review + schedule: + - cron: "0 01 * * *" # run at 1 am UTC every day + workflow_dispatch: + +jobs: + hive: + runs-on: ubuntu-latest + steps: + - uses: AutoModality/action-clean@v1 + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # fetch git tags for "git describe" + + - name: build erigon image + run: DOCKER_TAG=testinprod/op-erigon:latest DOCKER_UID=$(id -u) DOCKER_GID=$(id -g) make docker + + # check with root permissions, should be cached from previous build + - name: build erigon image (root permissions) + run: sudo DOCKER_TAG=testinprod/op-erigon:latest DOCKER_UID=$(id -u) DOCKER_GID=$(id -g) make docker + + - name: run hive and parse output + run: | + sudo mkdir -p /results-${{ github.run_id }} + docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v ${{ github.workspace }}:/work testinprod/hive:latest --sim optimism --results-root=/work/results-${{ github.run_id }} --client go-ethereum,op-erigon,op-proposer,op-batcher,op-node + docker run --rm --pull always -v /var/run/docker.sock:/var/run/docker.sock -v ${{ github.workspace }}:/work --entrypoint /app/hivecioutput testinprod/hive:latest --resultsdir=/work/results-${{ github.run_id }} --outdir=/work/results-${{ github.run_id }} --exclusionsfile=/work/hive/exclusions.json + + - name: clean up containers + if: always() + run: | + ids=$(docker ps -a -q) + for id in $ids + do + echo "stopping/removing container: $id" + docker stop $id && docker rm $id + done + + - name: parse hive results + uses: phoenix-actions/test-reporting@v10 + with: + name: Tests + path: results-${{ github.run_id }}/*.xml + reporter: java-junit
diff --git ledgerwatch/erigon/.github/workflows/release.yml testinprod-io/erigon/.github/workflows/release.yml index 372cdbe00daaafedccbbed75435ccc4cb5f39495..3770c300f5c776d22e5a5c5211495b92722241b6 100644 --- ledgerwatch/erigon/.github/workflows/release.yml +++ testinprod-io/erigon/.github/workflows/release.yml @@ -29,19 +29,12 @@ uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB }} password: ${{ secrets.DOCKERHUB_KEY }} - - name: ghcr-login - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }}   - name: Prepare id: prepare run: | TAG=${GITHUB_REF#refs/tags/} echo ::set-output name=tag_name::${TAG} - - name: Set up QEMU uses: docker/setup-qemu-action@v2   @@ -52,4 +45,4 @@ env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VERSION: ${{ steps.prepare.outputs.tag_name }} DOCKER_USERNAME: ${{ secrets.DOCKERHUB }} - DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_KEY }} \ No newline at end of file + DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_KEY }}
diff --git ledgerwatch/erigon/.github/workflows/test-integration.yml testinprod-io/erigon/.github/workflows/test-integration.yml index e2afd1a3d7632e9dda8b7e67df9ed70360cc3ff2..68d646e2e79b25fd6da7a2d9ccd8a7aff1fb5998 100644 --- ledgerwatch/erigon/.github/workflows/test-integration.yml +++ testinprod-io/erigon/.github/workflows/test-integration.yml @@ -5,6 +5,7 @@ branches: - devel - alpha - stable + - op-erigon schedule: - cron: '20 16 * * *' # daily at 16:20 UTC workflow_dispatch:
diff --git ledgerwatch/erigon/.gitignore testinprod-io/erigon/.gitignore index e246a0d1eeaae0aac13dbee8d9c74d7265276d2d..f99ccde8ff3463ac0ad4eb0ebebd2ac472e80dd4 100644 --- ledgerwatch/erigon/.gitignore +++ testinprod-io/erigon/.gitignore @@ -16,6 +16,7 @@ */**/*dapps* build/_vendor/pkg /*.a docs/readthedocs/build +.dev   #* .#*
diff --git ledgerwatch/erigon/Dockerfile testinprod-io/erigon/Dockerfile index 85524480c40ff0927393c5fef3a6161b68c8c39d..2c2a5d460be44bfa177db86d4e4ec69ac782d055 100644 --- ledgerwatch/erigon/Dockerfile +++ testinprod-io/erigon/Dockerfile @@ -98,10 +98,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/testinprod-io/op-erigon.git" \ org.label-schema.version=$VERSION   ENTRYPOINT ["erigon"]
diff --git ledgerwatch/erigon/Makefile testinprod-io/erigon/Makefile index 68e1c7ddcc41b036734cd76812068f030ae13aca..629d35afe56b5b7ea6e863e4fe71f931290fae75 100644 --- ledgerwatch/erigon/Makefile +++ testinprod-io/erigon/Makefile @@ -10,7 +10,7 @@ ERIGON_USER ?= erigon # 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_TAG ?= testinprod/op-erigon:latest   # Variables below for building on host OS, and are ignored for docker # @@ -29,7 +29,7 @@ CGO_CFLAGS := CGO_CFLAGS="$(CGO_CFLAGS)" DBG_CGO_CFLAGS += -DMDBX_DEBUG=1   BUILD_TAGS = nosqlite,noboltdb,netgo # about netgo see: https://github.com/golang/go/issues/30310#issuecomment-471669125 -PACKAGE = github.com/ledgerwatch/erigon +PACKAGE = github.com/testinprod-io/op-erigon   GO_FLAGS += -trimpath -tags $(BUILD_TAGS) -buildvcs=false GO_FLAGS += -ldflags "-X ${PACKAGE}/params.GitCommit=${GIT_COMMIT} -X ${PACKAGE}/params.GitBranch=${GIT_BRANCH} -X ${PACKAGE}/params.GitTag=${GIT_TAG}" @@ -141,6 +141,10 @@ cd vendor/github.com/torquem-ch/mdbx-go/mdbxdist && cp mdbx_chk $(GOBIN) && cp mdbx_copy $(GOBIN) && cp mdbx_dump $(GOBIN) && cp mdbx_drop $(GOBIN) && cp mdbx_load $(GOBIN) && cp mdbx_stat $(GOBIN) rm -rf vendor @echo "Run \"$(GOBIN)/mdbx_stat -h\" to get info about mdbx db file."   +## devnet: +devnet-up: + ./build/bin/erigon --datadir=.dev --chain=op-dev --private.api.addr=localhost:9090 --mine --http.port=8545 --log.console.verbosity=4 --genesis.path=./genesis-l2.json + ## test: run unit tests with a 100s timeout test: $(GOTEST) --timeout 100s @@ -214,7 +218,7 @@ @# these lines will also fail if ran as root in a non-root user's checked out repository @git submodule sync --quiet --recursive || true @git submodule update --quiet --init --recursive --force || true   -PACKAGE_NAME := github.com/ledgerwatch/erigon +PACKAGE_NAME := github.com/testinprod-io/op-erigon GOLANG_CROSS_VERSION ?= v1.20.2   .PHONY: release-dry-run @@ -245,10 +249,13 @@ -v /var/run/docker.sock:/var/run/docker.sock \ -v `pwd`:/go/src/$(PACKAGE_NAME) \ -w /go/src/$(PACKAGE_NAME) \ ghcr.io/goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \ - --clean --skip-validate + --skip-validate   - @docker image push --all-tags thorax/erigon - @docker image push --all-tags ghcr.io/ledgerwatch/erigon + @docker image push --all-tags testinprod/op-erigon + @docker manifest create testinprod/op-erigon:latest \ + --amend testinprod/op-erigon:$$(echo ${VERSION} | cut -c 2- )-amd64 \ + --amend testinprod/op-erigon:$$(echo ${VERSION} | cut -c 2- )-arm64 + @docker manifest push testinprod/op-erigon:latest   # 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. @@ -288,9 +295,9 @@ ## hive: run hive test suite locally using docker e.g. OUTPUT_DIR=~/results/hive SIM=ethereum/engine make hive .PHONY: hive hive: - DOCKER_TAG=thorax/erigon:ci-local make docker - docker pull thorax/hive:latest - docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v $(OUTPUT_DIR):/work thorax/hive:latest --sim $(SIM) --results-root=/work/results --client erigon_ci-local # run erigon + DOCKER_TAG=testinprod/op-erigon:ci-local make docker + docker pull testinprod/hive:latest + docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v $(OUTPUT_DIR):/work testinprod/hive:latest --sim $(SIM) --results-root=/work/results --client erigon_ci-local # run erigon   ## automated-tests run automated tests (BUILD_ERIGON=0 to prevent erigon build with local image tag) .PHONY: automated-tests
diff --git ledgerwatch/erigon/README.md testinprod-io/erigon/README.md index efd226a97304e94eab1847031377a2305dd3cf4e..77d7858b2c0f0f83ceb19db66a9992d0e60df843 100644 --- ledgerwatch/erigon/README.md +++ testinprod-io/erigon/README.md @@ -1,3 +1,149 @@ +# Optimistic Erigon +[![CI](https://github.com/testinprod-io/op-erigon/actions/workflows/ci.yml/badge.svg)](https://github.com/testinprod-io/op-erigon/actions/workflows/ci.yml) [![Integration tests](https://github.com/testinprod-io/op-erigon/actions/workflows/test-integration.yml/badge.svg)](https://github.com/testinprod-io/op-erigon/actions/workflows/test-integration.yml) [![Hive](https://github.com/testinprod-io/op-erigon/actions/workflows/hive.yml/badge.svg)](https://github.com/testinprod-io/op-erigon/actions/workflows/hive.yml) [![](https://dcbadge.vercel.app/api/server/42DFTeZwUZ?style=flat&compact=true)](https://discord.gg/42DFTeZwUZ) + +A fork of [Erigon](https://github.com/ledgerwatch/erigon) that supports the [execution engine](https://github.com/ethereum-optimism/optimism/blob/develop/specs/exec-engine.md) of [OP stack](https://stack.optimism.io). Check out the fork status here: [https://op-erigon.testinprod.io](https://op-erigon.testinprod.io) + +[`testinprod-io/erigon-lib`](https://github.com/testinprod-io/erigon-lib) has minimal backwards-compatible changes to add Optimism engine-api fields on the `op-erigon` branch. + +[`testinprod-io/erigon-interfaces`](https://github.com/testinprod-io/erigon-interfaces) defines the protobuf changes for `erigon-lib` on the `op-erigon` branch. +- [Optimistic Erigon Project Status](#optimistic-erigon-project-status) + + [Features that work correctly](#features-that-work-correctly) + + [Features that don't work (or yet to be confirmed)](#features-that-dont-work-or-yet-to-be-confirmed) +- [Getting started with Optimism](#getting-started-with-optimism) +- [Example: Running An Optimism Goerli Testnet Node](#example-running-an-optimism-goerli-testnet-node) +- [Need any help?](#need-any-help) +- [Thanks](#thanks) +- [Original Erigon README.md](#erigon) + +## Optimistic Erigon Project Status +Optimistic Erigon is still under development. Please note that some features are not fully implemented or tested. + +### Features that work correctly +- Validator mode (Synchronizing to the Optimism Goerli Testnet with op-node) +- Ethereum standard JSON-RPC API +- JSON-RPC API for Otterscan +- All-in-One binary mode + +### Features that don't work (or yet to be confirmed) +- Block producing as a Sequencer +- Sequencer and proposer mode +- P2P transaction gossip +- Running Erigon services as separate processes +- Erigon Snapshot + +### Stability (dogfooding) +- [![Hive](https://github.com/testinprod-io/op-erigon/actions/workflows/hive.yml/badge.svg)](https://github.com/testinprod-io/op-erigon/actions/workflows/hive.yml) +- We've been running an op-erigon public RPC here: [https://op-erigon.goerli.testinprod.io/](https://op-erigon.goerli.testinprod.io/) +- Our Otterscan (block explorer) uses our public RPC: [https://otterscan.goerli.testinprod.io/](https://otterscan.goerli.testinprod.io/) + +## Getting started with Optimism +To build from the code, you can use the same command described below(`make erigon`) + +You can use every flag erigon has. But there are some required flags and newly added flags for Optimism. + +### `--datadir` +**[Required]** +op-erigon cannot execute state transition before the bedrock update. So preconfigured data file is required to run the node. It includes blocks and states of the pre-bedrock chain. + +You can download the latest chain data of Optimism Goerli Testnet from [https://op-erigon-backup.goerli.testinprod.io](https://backup.goerli.op-erigon.testinprod.io). + +### `--externalcl` +**[Deprecated]** +An Optimism node needs a consensus client(op-node) and an execution client. op-erigon is intended to have an external consensus client though Erigon has its own consensus client. + +This option specifies that Erigon will have an external consensus client. This is **required up to version `v2.39.0-0.1.1`**. In subsequent versions, this behavior has been made the default, and **using the flag will result in an error**. + +### `--authrpc.addr`, `--authrpc.port`, `--authrpc.jwtsecret` +**[Required]** +Authenticated RPC configs that specify engine API connection info for the consensus client. + +### `--rollup.sequencerhttp` +**[New flag / Optional]** +HTTP endpoint of the sequencer. op-erigon will route `eth_sendRawTransaction` calls to this URL. This is **required** for transaction submission since Bedrock does not currently have a public mempool. Refer to the documentation for the network you are participating in to get the correct URL. + +For the Optimism Goerli Testnet, set the sequencer endpoint: `https://goerli-sequencer.optimism.io` + +### `--rollup.historicalrpc` +**[New flag / Optional]** +The historical RPC endpoint. op-erigon queries historical execution data that op-erigon does not support to historical RPC—for example, pre-bedrock executions. For Optimism Goerli Testnet, please set this value to the Legacy Geth endpoint. + +For more information about legacy geth, refer the [Optimism's node operator guide](https://community.optimism.io/docs/developers/bedrock/node-operator-guide/#legacy-geth). + +### `--maxpeers=0`, `--nodiscover` +**[Optional]** +Disable P2P. Execution-layer peering is currently not supported in the Optimism protocol. Though this is not required, it saves resources since TX pool gossip is currently not available. + +## Example: Running An Optimism Goerli Testnet Node +### 1. Download and decompress the chain data +You can download the latest preconfigured chain data from [https://backup.goerli.op-erigon.testinprod.io](https://backup.goerli.op-erigon.testinprod.io). +```bash +curl -L -o "backup.tar.gz" https://backup.goerli.op-erigon.testinprod.io +tar -zxvf backup.tar.gz +``` +After untaring, you will get a folder named `chaindata` which contains two files: `mdbx.dat` and `mdbx.lck`. Create a directory, move `chaindata` to the directory, and use the directory as a datadir(`$DATADIR`) for erigon. For example, +```bash +mkdir database +mv chaindata database/ +export DATA_DIR=`pwd`/database +``` + +### 2. Configuring op-erigon +There are three options to run op-erigon. Please refer to the preceding descriptions for the required flags. +1. Build from the source +```bash +(build from the source) +$ make erigon + +(example execution command) +$ ./build/bin/erigon \ + --datadir=$DATA_DIR \ + --private.api.addr=localhost:9090 \ + --http.addr=0.0.0.0 \ + --http.port=8545 \ + --http.corsdomain="*" \ + --http.vhosts="*" \ + --authrpc.addr=0.0.0.0 \ + --authrpc.port=8551 \ + --authrpc.vhosts="*" \ + --authrpc.jwtsecret=$JWT_SECRET_FILE \ + --rollup.sequencerhttp="https://goerli.optimism.io" \ + --rollup.historicalrpc=$HISTORICAL_RPC_ENDPOINT \ + --nodiscover +``` +2. Use the Docker image: You can get the official Docker image from [testinprod/op-erigon](https://hub.docker.com/r/testinprod/op-erigon). +3. Use the Helm chart: If you want to deploy op-erigon to the K8S cluster, you can use [Helm chart](https://artifacthub.io/packages/helm/op-charts/erigon). + +### 3. Configuring op-node +op-node is a consensus engine of OP stack. You can also build from the source, use official Docker image(`us-docker.pkg.dev/oplabs-tools-artifacts/images/op-node`), or [Helm chart](https://artifacthub.io/packages/helm/op-charts/op-node). + +```bash +(example execution command) +$ op-node \ + --l1=$L1_RPC_ENDPOINT \ + --l2=$OP_ERIGON_ENGINE_API_ENDPOINT \ + --l2.jwt-secret=$JWT_SECRET_FILE \ + --network=goerli \ + --rpc.addr=0.0.0.0 \ + --rpc.port=9545 +``` +For more information for op-node, refer the [Optimism's node operator guide](https://community.optimism.io/docs/developers/bedrock/node-operator-guide/#configuring-op-node). + +## Need any help? +[![](https://dcbadge.vercel.app/api/server/42DFTeZwUZ?style=flat&compact=true)](https://discord.gg/42DFTeZwUZ) If you need help or find a bug, please share it with our discord! + +## Thanks +- Erigon team for building this amazing, super fast, and cutting-edge efficient client. +- Willian for building an awesome open-sourced block explorer, Otterscan. +- Optimism Collective and OP Labs for the huge support and for building this amazing technology stack. +- Kelvin, Proto, and Lindsay for guiding and helping us a lot. Also, forkdiff is amazing. +- and Ethereum ❤️ + +_Let's stay Optimistic_ 🔴 + +--- + +<!-- Original Erigon README starts. --> + # Erigon   Erigon is an implementation of Ethereum (execution client with light client for consensus layer), on the efficiency
diff --git ledgerwatch/erigon/cmd/downloader/recompress.sh testinprod-io/erigon/cmd/downloader/recompress.sh old mode 100755 new mode 100644
diff --git ledgerwatch/erigon/cmd/downloader/torrent_hashes_update.sh testinprod-io/erigon/cmd/downloader/torrent_hashes_update.sh old mode 100755 new mode 100644
diff --git ledgerwatch/erigon/go.sum testinprod-io/erigon/go.sum index 5b2a3ad894bdf6afd6a90bedc2177d41f3ba8e88..ef9af2cb5431f444ad98638849ecd4a293772b8a 100644 --- ledgerwatch/erigon/go.sum +++ testinprod-io/erigon/go.sum @@ -438,8 +438,6 @@ 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/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-lib v0.0.0-20230423044930-fc9dd74e6407 h1:PBcNdCUF0UtY+pkbzwXWeRsEIinVWGiCjyqD9WvV+H4= -github.com/ledgerwatch/erigon-lib v0.0.0-20230423044930-fc9dd74e6407/go.mod h1:D05f9OXc/2cnYxCyBexlu5HeIeQW9GKXynyWYzJ1F5I= github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20230404044759-5dec854ce336 h1:Yxmt4Wyd0RCLr7UJJAl0ApCP/f5qkWfvHfgPbnI8ghM= github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20230404044759-5dec854ce336/go.mod h1:3AuPxZc85jkehh/HA9h8gabv5MSi3kb/ddtzBsTVJFo= github.com/ledgerwatch/log/v3 v3.7.0 h1:aFPEZdwZx4jzA3+/Pf8wNDN5tCI0cIolq/kfvgcM+og= @@ -779,6 +777,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/supranational/blst v0.3.10 h1:CMciDZ/h4pXDDXQASe8ZGTNKUiVNxVVA5hpci2Uuhuk= github.com/supranational/blst v0.3.10/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/testinprod-io/erigon-lib v0.0.0-20230510042408-cab68978c512 h1:W4E/VTA0MZuvM/M9Bu4EUxKuvR/Lg3S7Ae2PUbC2xZM= +github.com/testinprod-io/erigon-lib v0.0.0-20230510042408-cab68978c512/go.mod h1:Riqyql8ODsUgb2bXD7RYC4p7Osbq4019/lPin3/eESA= github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e h1:cR8/SYRgyQCt5cNCMniB/ZScMkhI9nk8U5C7SbISXjo= github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e/go.mod h1:Tu4lItkATkonrYuvtVjG0/rhy15qrNGNTjPdaphtZ/8= github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg=