diff --git go-ethereum/Makefile op-geth/Makefile
index d736ef61c001ec02581a6867982291cdf684b3ab..226bac2d1e1b87b26dd70989b37e32117a1837fe 100644
--- go-ethereum/Makefile
+++ op-geth/Makefile
@@ -36,3 +36,9 @@ env GOBIN= go install github.com/golang/protobuf/protoc-gen-go@latest
env GOBIN= go install ./cmd/abigen
@type "solc" 2> /dev/null || echo 'Please install solc'
@type "protoc" 2> /dev/null || echo 'Please install protoc'
+
+forkdiff:
+ docker run --rm \
+ --mount src=$(shell pwd),target=/host-pwd,type=bind \
+ protolambda/forkdiff:latest \
+ -repo /host-pwd/ -fork /host-pwd/fork.yaml -out /host-pwd/forkdiff.html
diff --git go-ethereum/cmd/devp2p/internal/ethtest/snap.go op-geth/cmd/devp2p/internal/ethtest/snap.go
index f947e4bc9bae791bc1a0058fcadf7fae094632b8..8fa03660cfcc9f8e979cb9d9bdec20b0af4a215b 100644
--- go-ethereum/cmd/devp2p/internal/ethtest/snap.go
+++ op-geth/cmd/devp2p/internal/ethtest/snap.go
@@ -249,11 +249,11 @@ for i, tc := range []byteCodesTest{
// A few stateroots
{
nBytes: 10000, hashes: []common.Hash{s.chain.RootAt(0), s.chain.RootAt(999)},
- expHashes: 0,
+ expHashes: 1, // 32-byte keys are detected as code, even if not code (like genesis hash), in legacy lookups.
},
{
nBytes: 10000, hashes: []common.Hash{s.chain.RootAt(0), s.chain.RootAt(0)},
- expHashes: 0,
+ expHashes: 2, // 32-byte keys are detected as code, even if not code (like genesis hash), in legacy lookups.
},
// Empties
{
diff --git go-ethereum/core/rawdb/accessors_chain_test.go op-geth/core/rawdb/accessors_chain_test.go
index a7ceb72998a115653130a19932f443dfda3f7cc4..1226bbbb6321ffae0ea5394c31fe3aa91dbbdfe7 100644
--- go-ethereum/core/rawdb/accessors_chain_test.go
+++ op-geth/core/rawdb/accessors_chain_test.go
@@ -27,10 +27,12 @@ "reflect"
"testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
+ "github.com/stretchr/testify/require"
"golang.org/x/crypto/sha3"
)
@@ -347,6 +349,9 @@ // Create a live block since we need metadata to reconstruct the receipt
tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil)
tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil)
+ header := &types.Header{
+ Number: big.NewInt(0),
+ }
body := &types.Body{Transactions: types.Transactions{tx1, tx2}}
// Create the two receipts to manage afterwards
@@ -378,12 +383,15 @@ receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2})
receipts := []*types.Receipt{receipt1, receipt2}
// Check that no receipt entries are in a pristine database
- hash := common.BytesToHash([]byte{0x03, 0x14})
+ hash := header.Hash()
if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 {
t.Fatalf("non existent receipts returned: %v", rs)
}
// Insert the body that corresponds to the receipts
WriteBody(db, hash, 0, body)
+
+ // Insert the header that corresponds to the receipts
+ WriteHeader(db, header)
// Insert the receipt slice into the database and check presence
WriteReceipts(db, hash, 0, receipts)
@@ -698,6 +706,7 @@
body := &types.Body{Transactions: types.Transactions{tx1, tx2}}
// Create the two receipts to manage afterwards
+ depositNonce := uint64(math.MaxUint64)
receipt1 := &types.Receipt{
Status: types.ReceiptStatusFailed,
CumulativeGasUsed: 1,
@@ -708,6 +717,7 @@ },
TxHash: tx1.Hash(),
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
GasUsed: 111111,
+ DepositNonce: &depositNonce,
}
receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1})
@@ -765,6 +775,36 @@ t.Fatalf("receipt #%d: receipt mismatch: have %s, want %s", i, hex.EncodeToString(rlpHave), hex.EncodeToString(rlpWant))
}
}
}
+}
+
+func TestParseLegacyReceiptRLP(t *testing.T) {
+ // Create a gasUsed value greater than a uint64 can represent
+ gasUsed := big.NewInt(0)
+ gasUsed = gasUsed.SetUint64(math.MaxUint64)
+ gasUsed = gasUsed.Add(gasUsed, big.NewInt(math.MaxInt64))
+ sanityCheck := (&big.Int{}).SetUint64(gasUsed.Uint64())
+ require.NotEqual(t, gasUsed, sanityCheck)
+ receipt := types.LegacyOptimismStoredReceiptRLP{
+ CumulativeGasUsed: 1,
+ Logs: []*types.LogForStorage{
+ {Address: common.BytesToAddress([]byte{0x11})},
+ {Address: common.BytesToAddress([]byte{0x01, 0x11})},
+ },
+ L1GasUsed: gasUsed,
+ L1GasPrice: gasUsed,
+ L1Fee: gasUsed,
+ FeeScalar: "6",
+ }
+
+ data, err := rlp.EncodeToBytes(receipt)
+ require.NoError(t, err)
+ var result storedReceiptRLP
+ err = rlp.DecodeBytes(data, &result)
+ require.NoError(t, err)
+ require.Equal(t, receipt.L1GasUsed, result.L1GasUsed)
+ require.Equal(t, receipt.L1GasPrice, result.L1GasPrice)
+ require.Equal(t, receipt.L1Fee, result.L1Fee)
+ require.Equal(t, receipt.FeeScalar, result.FeeScalar)
}
func TestDeriveLogFields(t *testing.T) {
diff --git go-ethereum/core/superchain_test.go op-geth/core/superchain_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..fa3246250ac32aebea1410295f946fd10f25252d
--- /dev/null
+++ op-geth/core/superchain_test.go
@@ -0,0 +1,17 @@
+package core
+
+import (
+ "testing"
+
+ "github.com/ethereum-optimism/superchain-registry/superchain"
+)
+
+func TestOPStackGenesis(t *testing.T) {
+ for id := range superchain.OPChains {
+ gen, err := LoadOPStackGenesis(id)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("chain: %d, genesis block hash: %s", id, gen.ToBlock().Hash())
+ }
+}
diff --git go-ethereum/core/types/receipt_test.go op-geth/core/types/receipt_test.go
index a7b26444712fe8c669ea732fa423588a58497f32..e6c76a733d1a1772182c3d5af67f7ef5e8e490c5 100644
--- go-ethereum/core/types/receipt_test.go
+++ op-geth/core/types/receipt_test.go
@@ -19,6 +19,7 @@
import (
"bytes"
"encoding/json"
+ "fmt"
"math"
"math/big"
"reflect"
@@ -29,6 +30,7 @@ "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256"
"github.com/kylelemons/godebug/diff"
+ "github.com/stretchr/testify/require"
)
var (
@@ -82,6 +84,42 @@ },
},
Type: DynamicFeeTxType,
}
+ depositReceiptNoNonce = &Receipt{
+ Status: ReceiptStatusFailed,
+ CumulativeGasUsed: 1,
+ Logs: []*Log{
+ {
+ Address: common.BytesToAddress([]byte{0x11}),
+ Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
+ Data: []byte{0x01, 0x00, 0xff},
+ },
+ {
+ Address: common.BytesToAddress([]byte{0x01, 0x11}),
+ Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
+ Data: []byte{0x01, 0x00, 0xff},
+ },
+ },
+ Type: DepositTxType,
+ }
+ nonce = uint64(1234)
+ depositReceiptWithNonce = &Receipt{
+ Status: ReceiptStatusFailed,
+ CumulativeGasUsed: 1,
+ DepositNonce: &nonce,
+ Logs: []*Log{
+ {
+ Address: common.BytesToAddress([]byte{0x11}),
+ Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
+ Data: []byte{0x01, 0x00, 0xff},
+ },
+ {
+ Address: common.BytesToAddress([]byte{0x01, 0x11}),
+ Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
+ Data: []byte{0x01, 0x00, 0xff},
+ },
+ },
+ Type: DepositTxType,
+ }
// Create a few transactions to have receipts for
to2 = common.HexToAddress("0x2")
@@ -149,8 +187,13 @@ GasFeeCap: uint256.NewInt(1077),
BlobFeeCap: uint256.NewInt(100077),
BlobHashes: []common.Hash{{}, {}, {}},
}),
+ NewTx(&DepositTx{
+ To: nil, // contract creation
+ Value: big.NewInt(6),
+ Gas: 50,
+ }),
}
-
+ depNonce = uint64(7)
blockNumber = big.NewInt(1)
blockTime = uint64(2)
blockHash = common.BytesToHash([]byte{0x03, 0x14})
@@ -293,6 +336,41 @@ BlockHash: blockHash,
BlockNumber: blockNumber,
TransactionIndex: 6,
},
+ &Receipt{
+ Type: DepositTxType,
+ PostState: common.Hash{5}.Bytes(),
+ CumulativeGasUsed: 50 + 28,
+ Logs: []*Log{
+ {
+ Address: common.BytesToAddress([]byte{0x33}),
+ Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
+ // derived fields:
+ BlockNumber: blockNumber.Uint64(),
+ TxHash: txs[7].Hash(),
+ TxIndex: 7,
+ BlockHash: blockHash,
+ Index: 4,
+ },
+ {
+ Address: common.BytesToAddress([]byte{0x03, 0x33}),
+ Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
+ // derived fields:
+ BlockNumber: blockNumber.Uint64(),
+ TxHash: txs[7].Hash(),
+ TxIndex: 7,
+ BlockHash: blockHash,
+ Index: 5,
+ },
+ },
+ TxHash: txs[7].Hash(),
+ ContractAddress: common.HexToAddress("0x3bb898b4bbe24f68a4e9be46cfe72d1787fd74f4"),
+ GasUsed: 50,
+ EffectiveGasPrice: big.NewInt(0),
+ BlockHash: blockHash,
+ BlockNumber: blockNumber,
+ TransactionIndex: 7,
+ DepositNonce: &depNonce,
+ },
}
)
@@ -527,3 +605,205 @@ l[i] = &cpy
}
return l
}
+
+func TestDeriveOptimismTxReceipt(t *testing.T) {
+ to4 := common.HexToAddress("0x4")
+ // Create a few transactions to have receipts for
+ txs := Transactions{
+ NewTx(&DepositTx{
+ To: nil, // contract creation
+ Value: big.NewInt(6),
+ Gas: 50,
+ // System config with L1Scalar=2_000_000 (becomes 2 after division), L1Overhead=2500, L1BaseFee=5000
+ Data: common.Hex2Bytes("015d8eb900000000000000000000000000000000000000000000000026b39534042076f70000000000000000000000000000000000000000000000007e33b7c4995967580000000000000000000000000000000000000000000000000000000000001388547dea8ff339566349ed0ef6384876655d1b9b955e36ac165c6b8ab69b9af5cd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123400000000000000000000000000000000000000000000000000000000000009c400000000000000000000000000000000000000000000000000000000001e8480"),
+ }),
+ NewTx(&DynamicFeeTx{
+ To: &to4,
+ Nonce: 4,
+ Value: big.NewInt(4),
+ Gas: 4,
+ GasTipCap: big.NewInt(44),
+ GasFeeCap: big.NewInt(1045),
+ Data: []byte{0, 1, 255, 0},
+ }),
+ }
+ depNonce := uint64(7)
+ blockNumber := big.NewInt(1)
+ blockHash := common.BytesToHash([]byte{0x03, 0x14})
+
+ // Create the corresponding receipts
+ receipts := Receipts{
+ &Receipt{
+ Type: DepositTxType,
+ PostState: common.Hash{5}.Bytes(),
+ CumulativeGasUsed: 50 + 15,
+ Logs: []*Log{
+ {
+ Address: common.BytesToAddress([]byte{0x33}),
+ // derived fields:
+ BlockNumber: blockNumber.Uint64(),
+ TxHash: txs[0].Hash(),
+ TxIndex: 0,
+ BlockHash: blockHash,
+ Index: 0,
+ },
+ {
+ Address: common.BytesToAddress([]byte{0x03, 0x33}),
+ // derived fields:
+ BlockNumber: blockNumber.Uint64(),
+ TxHash: txs[0].Hash(),
+ TxIndex: 0,
+ BlockHash: blockHash,
+ Index: 1,
+ },
+ },
+ TxHash: txs[0].Hash(),
+ ContractAddress: common.HexToAddress("0x3bb898b4bbe24f68a4e9be46cfe72d1787fd74f4"),
+ GasUsed: 65,
+ EffectiveGasPrice: big.NewInt(0),
+ BlockHash: blockHash,
+ BlockNumber: blockNumber,
+ TransactionIndex: 0,
+ DepositNonce: &depNonce,
+ },
+ &Receipt{
+ Type: DynamicFeeTxType,
+ PostState: common.Hash{4}.Bytes(),
+ CumulativeGasUsed: 10,
+ Logs: []*Log{},
+ // derived fields:
+ TxHash: txs[1].Hash(),
+ GasUsed: 18446744073709551561,
+ EffectiveGasPrice: big.NewInt(1044),
+ BlockHash: blockHash,
+ BlockNumber: blockNumber,
+ TransactionIndex: 1,
+ L1GasPrice: big.NewInt(5000),
+ L1GasUsed: big.NewInt(3976),
+ L1Fee: big.NewInt(39760000),
+ FeeScalar: big.NewFloat(2),
+ },
+ }
+
+ // Re-derive receipts.
+ basefee := big.NewInt(1000)
+ derivedReceipts := clearComputedFieldsOnReceipts(receipts)
+ err := Receipts(derivedReceipts).DeriveFields(params.OptimismTestConfig, blockHash, blockNumber.Uint64(), 0, basefee, nil, txs)
+ if err != nil {
+ t.Fatalf("DeriveFields(...) = %v, want <nil>", err)
+ }
+
+ // Check diff of receipts against derivedReceipts.
+ r1, err := json.MarshalIndent(receipts, "", " ")
+ if err != nil {
+ t.Fatal("error marshaling input receipts:", err)
+ }
+ r2, err := json.MarshalIndent(derivedReceipts, "", " ")
+ if err != nil {
+ t.Fatal("error marshaling derived receipts:", err)
+ }
+ d := diff.Diff(string(r1), string(r2))
+ if d != "" {
+ t.Fatal("receipts differ:", d)
+ }
+
+ // Check that we preserved the invariant: l1Fee = l1GasPrice * l1GasUsed * l1FeeScalar
+ // but with more difficult int math...
+ l2Rcpt := derivedReceipts[1]
+ l1GasCost := new(big.Int).Mul(l2Rcpt.L1GasPrice, l2Rcpt.L1GasUsed)
+ l1Fee := new(big.Float).Mul(new(big.Float).SetInt(l1GasCost), l2Rcpt.FeeScalar)
+ require.Equal(t, new(big.Float).SetInt(l2Rcpt.L1Fee), l1Fee)
+}
+
+func TestBedrockDepositReceiptUnchanged(t *testing.T) {
+ expectedRlp := common.FromHex("7EF90156A003000000000000000000000000000000000000000000000000000000000000000AB9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F0D7940000000000000000000000000000000000000033C001D7940000000000000000000000000000000000000333C002")
+ // Deposit receipt with no nonce
+ receipt := &Receipt{
+ Type: DepositTxType,
+ PostState: common.Hash{3}.Bytes(),
+ CumulativeGasUsed: 10,
+ Logs: []*Log{
+ {Address: common.BytesToAddress([]byte{0x33}), Data: []byte{1}, Topics: []common.Hash{}},
+ {Address: common.BytesToAddress([]byte{0x03, 0x33}), Data: []byte{2}, Topics: []common.Hash{}},
+ },
+ TxHash: common.Hash{},
+ ContractAddress: common.BytesToAddress([]byte{0x03, 0x33, 0x33}),
+ GasUsed: 4,
+ }
+
+ rlp, err := receipt.MarshalBinary()
+ require.NoError(t, err)
+ require.Equal(t, expectedRlp, rlp)
+
+ // Consensus values should be unchanged after reparsing
+ parsed := new(Receipt)
+ err = parsed.UnmarshalBinary(rlp)
+ 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.EqualValues(t, receipt.Logs, parsed.Logs)
+ // 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 := test.rcpt.MarshalBinary()
+ require.NoError(t, err)
+
+ d := &Receipt{}
+ err = d.UnmarshalBinary(data)
+ require.NoError(t, err)
+ require.Equal(t, test.rcpt, d)
+ })
+
+ t.Run(fmt.Sprintf("%sRejectExtraData", test.name), func(t *testing.T) {
+ data, err := test.rcpt.MarshalBinary()
+ require.NoError(t, err)
+ data = append(data, 1, 2, 3, 4)
+ d := &Receipt{}
+ err = d.UnmarshalBinary(data)
+ 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 go-ethereum/core/types/rollup_l1_cost_test.go op-geth/core/types/rollup_l1_cost_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..e43ea967ee87a257cfc2afa58396c2eb6685ed76
--- /dev/null
+++ op-geth/core/types/rollup_l1_cost_test.go
@@ -0,0 +1,30 @@
+package types
+
+import (
+ "math/rand"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/stretchr/testify/require"
+)
+
+func TestRollupGasData(t *testing.T) {
+ for i := 0; i < 100; i++ {
+ zeroes := rand.Uint64()
+ ones := rand.Uint64()
+
+ r := RollupGasData{
+ Zeroes: zeroes,
+ Ones: ones,
+ }
+ time := uint64(1)
+ cfg := ¶ms.ChainConfig{
+ RegolithTime: &time,
+ }
+ gasPreRegolith := r.DataGas(0, cfg)
+ gasPostRegolith := r.DataGas(1, cfg)
+
+ require.Equal(t, r.Zeroes*params.TxDataZeroGas+(r.Ones+68)*params.TxDataNonZeroGasEIP2028, gasPreRegolith)
+ require.Equal(t, r.Zeroes*params.TxDataZeroGas+r.Ones*params.TxDataNonZeroGasEIP2028, gasPostRegolith)
+ }
+}
diff --git go-ethereum/core/types/transaction_marshalling_test.go op-geth/core/types/transaction_marshalling_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..4ab93a539d19bbcffa0293738b2e4dcc3ebe7ad2
--- /dev/null
+++ op-geth/core/types/transaction_marshalling_test.go
@@ -0,0 +1,103 @@
+package types
+
+import (
+ "encoding/json"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/require"
+)
+
+func TestTransactionUnmarshalJsonDeposit(t *testing.T) {
+ tx := NewTx(&DepositTx{
+ SourceHash: common.HexToHash("0x1234"),
+ IsSystemTransaction: true,
+ Mint: big.NewInt(34),
+ })
+ json, err := tx.MarshalJSON()
+ require.NoError(t, err, "Failed to marshal tx JSON")
+
+ got := &Transaction{}
+ err = got.UnmarshalJSON(json)
+ require.NoError(t, err, "Failed to unmarshal tx JSON")
+ require.Equal(t, tx.Hash(), got.Hash())
+}
+
+func TestTransactionUnmarshalJSON(t *testing.T) {
+ tests := []struct {
+ name string
+ json string
+ expectedError string
+ }{
+ {
+ name: "No gas",
+ json: `{"type":"0x7e","nonce":null,"gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}`,
+ expectedError: "missing required field 'gas'",
+ },
+ {
+ name: "No value",
+ json: `{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}`,
+ expectedError: "missing required field 'value'",
+ },
+ {
+ name: "No input",
+ json: `{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}`,
+ expectedError: "missing required field 'input'",
+ },
+ {
+ name: "No from",
+ json: `{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}`,
+ expectedError: "missing required field 'from'",
+ },
+ {
+ name: "No sourceHash",
+ json: `{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}`,
+ expectedError: "missing required field 'sourceHash'",
+ },
+ {
+ name: "No mint",
+ json: `{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","isSystemTx":false,"hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}`,
+ // Allowed
+ },
+ {
+ name: "No IsSystemTx",
+ json: `{"type":"0x7e","nonce":null,"gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}`,
+ // Allowed
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ var parsedTx = &Transaction{}
+ err := json.Unmarshal([]byte(test.json), &parsedTx)
+ if test.expectedError == "" {
+ require.NoError(t, err)
+ } else {
+ require.ErrorContains(t, err, test.expectedError)
+ }
+ })
+ }
+
+ tests = []struct {
+ name string
+ json string
+ expectedError string
+ }{
+ {
+ name: "Valid deposit sender",
+ json: `{"type":"0x7e","nonce":"0x1","gas": "0x1234", "gasPrice":null,"maxPriorityFeePerGas":null,"maxFeePerGas":null,"value":"0x1","input":"0x616263646566","v":null,"r":null,"s":null,"to":null,"sourceHash":"0x0000000000000000000000000000000000000000000000000000000000000000","from":"0x0000000000000000000000000000000000000001","hash":"0xa4341f3db4363b7ca269a8538bd027b2f8784f84454ca917668642d5f6dffdf9"}`,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ var parsedTx = &Transaction{}
+ err := json.Unmarshal([]byte(test.json), &parsedTx)
+ require.NoError(t, err)
+
+ signer := NewLondonSigner(big.NewInt(123))
+ sender, err := signer.Sender(parsedTx)
+ require.NoError(t, err)
+ require.Equal(t, common.HexToAddress("0x1"), sender)
+ })
+ }
+}
diff --git go-ethereum/eth/catalyst/api_test.go op-geth/eth/catalyst/api_test.go
index 59f44fafea4e0273b5db5b81b1609526e77c9d05..116bca1af9e14a40ab0031fd1b88161e8316360e 100644
--- go-ethereum/eth/catalyst/api_test.go
+++ op-geth/eth/catalyst/api_test.go
@@ -437,6 +437,11 @@ }
// startEthService creates a full node instance for testing.
func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) (*node.Node, *eth.Ethereum) {
+ ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256}
+ return startEthServiceWithConfigFn(t, blocks, ethcfg)
+}
+
+func startEthServiceWithConfigFn(t *testing.T, blocks []*types.Block, ethcfg *ethconfig.Config) (*node.Node, *eth.Ethereum) {
t.Helper()
n, err := node.New(&node.Config{
@@ -449,7 +454,7 @@ if err != nil {
t.Fatal("can't create node:", err)
}
- ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256}
+ // default eth config is moved to startEthService
ethservice, err := eth.New(n, ethcfg)
if err != nil {
t.Fatal("can't create eth service:", err)
diff --git go-ethereum/eth/catalyst/superchain_test.go op-geth/eth/catalyst/superchain_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..e06770fa3235a5f9022468c9f2fb47117cca1343
--- /dev/null
+++ op-geth/eth/catalyst/superchain_test.go
@@ -0,0 +1,100 @@
+package catalyst
+
+import (
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/eth/downloader"
+ "github.com/ethereum/go-ethereum/eth/ethconfig"
+ "github.com/ethereum/go-ethereum/node"
+ "github.com/ethereum/go-ethereum/params"
+)
+
+func TestSignalSuperchainV1(t *testing.T) {
+ genesis, preMergeBlocks := generateMergeChain(2, false)
+ n, ethservice := startEthService(t, genesis, preMergeBlocks)
+ defer n.Close()
+ api := NewConsensusAPI(ethservice)
+ t.Run("matching", func(t *testing.T) {
+ out, err := api.SignalSuperchainV1(&SuperchainSignal{
+ Recommended: params.OPStackSupport,
+ Required: params.OPStackSupport,
+ })
+ if err != nil {
+ t.Fatalf("failed to process signal: %v", err)
+ }
+ if out != params.OPStackSupport {
+ t.Fatalf("expected %s but got %s", params.OPStackSupport, out)
+ }
+ })
+ t.Run("null_arg", func(t *testing.T) {
+ out, err := api.SignalSuperchainV1(nil)
+ if err != nil {
+ t.Fatalf("failed to process signal: %v", err)
+ }
+ if out != params.OPStackSupport {
+ t.Fatalf("expected %s but got %s", params.OPStackSupport, out)
+ }
+ })
+}
+
+func TestSignalSuperchainV1Halt(t *testing.T) {
+ testCases := []struct {
+ cfg string
+ bump string
+ halt bool
+ }{
+ {"none", "major", false},
+ {"major", "major", true},
+ {"minor", "major", true},
+ {"patch", "major", true},
+ {"major", "minor", false},
+ {"minor", "minor", true},
+ {"patch", "minor", true},
+ {"major", "patch", false},
+ {"minor", "patch", false},
+ {"patch", "patch", true},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.cfg+"_"+tc.bump, func(t *testing.T) {
+ genesis, preMergeBlocks := generateMergeChain(2, false)
+ ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256}
+ ethcfg.RollupHaltOnIncompatibleProtocolVersion = tc.cfg // opt-in to halting (or not)
+ n, ethservice := startEthServiceWithConfigFn(t, preMergeBlocks, ethcfg)
+ defer n.Close() // close at the end, regardless of any prior (failed) closing
+ api := NewConsensusAPI(ethservice)
+ _, build, major, minor, patch, preRelease := params.OPStackSupport.Parse()
+ majorSignal, minorSignal, patchSignal := major, minor, patch
+ switch tc.bump {
+ case "major":
+ majorSignal += 1
+ case "minor":
+ minorSignal += 1
+ case "patch":
+ patchSignal += 1
+ }
+ out, err := api.SignalSuperchainV1(&SuperchainSignal{
+ Recommended: params.OPStackSupport, // required version change should be enough
+ Required: params.ProtocolVersionV0{Build: build, Major: majorSignal, Minor: minorSignal, Patch: patchSignal, PreRelease: preRelease}.Encode(),
+ })
+ if err != nil {
+ t.Fatalf("failed to process signal: %v", err)
+ }
+ if out != params.OPStackSupport {
+ t.Fatalf("expected %s but got %s", params.OPStackSupport, out)
+ }
+ closeErr := n.Close()
+ if tc.halt {
+ // assert no halt by closing, and not getting any error
+ if closeErr == nil {
+ t.Fatalf("expected not to have closed already, but just closed without error")
+ }
+ } else {
+ // assert halt by closing again, and seeing if things error
+ if closeErr == node.ErrNodeStopped {
+ t.Fatalf("expected to have already closed and get a ErrNodeStopped error, but got %v", closeErr)
+ }
+ }
+ })
+ }
+}
diff --git go-ethereum/eth/gasprice/optimism-gasprice_test.go op-geth/eth/gasprice/optimism-gasprice_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..dd0140839d91e45be16d06faae9b714ad53265fa
--- /dev/null
+++ op-geth/eth/gasprice/optimism-gasprice_test.go
@@ -0,0 +1,142 @@
+// Copyright 2020 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package gasprice
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/ethereum/go-ethereum/trie"
+)
+
+const (
+ blockGasLimit = params.TxGas * 3
+)
+
+type testTxData struct {
+ priorityFee int64
+ gasLimit uint64
+}
+
+type opTestBackend struct {
+ block *types.Block
+ receipts []*types.Receipt
+}
+
+func (b *opTestBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
+ panic("not implemented")
+}
+
+func (b *opTestBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
+ return b.block, nil
+}
+
+func (b *opTestBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
+ return b.receipts, nil
+}
+
+func (b *opTestBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) {
+ panic("not implemented")
+}
+
+func (b *opTestBackend) ChainConfig() *params.ChainConfig {
+ return params.OptimismTestConfig
+}
+
+func (b *opTestBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
+ return nil
+}
+
+func newOpTestBackend(t *testing.T, txs []testTxData) *opTestBackend {
+ var (
+ key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ signer = types.LatestSigner(params.TestChainConfig)
+ )
+ // only the most recent block is considered for optimism priority fee suggestions, so this is
+ // where we add the test transactions
+ ts := []*types.Transaction{}
+ rs := []*types.Receipt{}
+ header := types.Header{}
+ header.GasLimit = blockGasLimit
+ var nonce uint64
+ for _, tx := range txs {
+ txdata := &types.DynamicFeeTx{
+ ChainID: params.TestChainConfig.ChainID,
+ Nonce: nonce,
+ To: &common.Address{},
+ Gas: params.TxGas,
+ GasFeeCap: big.NewInt(100 * params.GWei),
+ GasTipCap: big.NewInt(tx.priorityFee),
+ Data: []byte{},
+ }
+ t := types.MustSignNewTx(key, signer, txdata)
+ ts = append(ts, t)
+ r := types.Receipt{}
+ r.GasUsed = tx.gasLimit
+ header.GasUsed += r.GasUsed
+ rs = append(rs, &r)
+ nonce++
+ }
+ hasher := trie.NewStackTrie(nil)
+ b := types.NewBlock(&header, ts, nil, nil, hasher)
+ return &opTestBackend{block: b, receipts: rs}
+}
+
+func TestSuggestOptimismPriorityFee(t *testing.T) {
+ minSuggestion := new(big.Int).SetUint64(1e8 * params.Wei)
+ var cases = []struct {
+ txdata []testTxData
+ want *big.Int
+ }{
+ {
+ // block well under capacity, expect min priority fee suggestion
+ txdata: []testTxData{testTxData{params.GWei, 21000}},
+ want: minSuggestion,
+ },
+ {
+ // 2 txs, still under capacity, expect min priority fee suggestion
+ txdata: []testTxData{testTxData{params.GWei, 21000}, testTxData{params.GWei, 21000}},
+ want: minSuggestion,
+ },
+ {
+ // 2 txs w same priority fee (1 gwei), but second tx puts it right over capacity
+ txdata: []testTxData{testTxData{params.GWei, 21000}, testTxData{params.GWei, 21001}},
+ want: big.NewInt(1100000000), // 10 percent over 1 gwei, the median
+ },
+ {
+ // 3 txs, full block. return 10% over the median tx (10 gwei * 10% == 11 gwei)
+ txdata: []testTxData{testTxData{10 * params.GWei, 21000}, testTxData{1 * params.GWei, 21000}, testTxData{100 * params.GWei, 21000}},
+ want: big.NewInt(11 * params.GWei),
+ },
+ }
+ for i, c := range cases {
+ backend := newOpTestBackend(t, c.txdata)
+ oracle := NewOracle(backend, Config{MinSuggestedPriorityFee: minSuggestion})
+ got := oracle.SuggestOptimismPriorityFee(context.Background(), backend.block.Header(), backend.block.Hash())
+ if got.Cmp(c.want) != 0 {
+ t.Errorf("Gas price mismatch for test case %d: want %d, got %d", i, c.want, got)
+ }
+ }
+}
diff --git go-ethereum/internal/ethapi/api_test.go op-geth/internal/ethapi/api_test.go
index fc135c3779ef63bfc94800c9f19ff5519a73f497..f76fc8883b2e4890d90c60f24323d6d52c9c510c 100644
--- go-ethereum/internal/ethapi/api_test.go
+++ op-geth/internal/ethapi/api_test.go
@@ -29,6 +29,10 @@ "reflect"
"testing"
"time"
+ "github.com/holiman/uint256"
+ "github.com/stretchr/testify/require"
+ "golang.org/x/exp/slices"
+
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
@@ -48,11 +52,123 @@ "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/blocktest"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
- "github.com/holiman/uint256"
- "github.com/stretchr/testify/require"
- "golang.org/x/exp/slices"
)
+func TestNewRPCTransactionDepositTx(t *testing.T) {
+ tx := types.NewTx(&types.DepositTx{
+ SourceHash: common.HexToHash("0x1234"),
+ IsSystemTransaction: true,
+ Mint: big.NewInt(34),
+ })
+ nonce := uint64(7)
+ receipt := &types.Receipt{
+ DepositNonce: &nonce,
+ }
+ got := newRPCTransaction(tx, common.Hash{}, uint64(12), uint64(1234), uint64(1), big.NewInt(0), ¶ms.ChainConfig{}, receipt)
+ // Should provide zero values for unused fields that are required in other transactions
+ require.Equal(t, got.GasPrice, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().GasPrice = %v, want 0x0", got.GasPrice)
+ require.Equal(t, got.V, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().V = %v, want 0x0", got.V)
+ require.Equal(t, got.R, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().R = %v, want 0x0", got.R)
+ require.Equal(t, got.S, (*hexutil.Big)(big.NewInt(0)), "newRPCTransaction().S = %v, want 0x0", got.S)
+
+ // Should include deposit tx specific fields
+ require.Equal(t, *got.SourceHash, tx.SourceHash(), "newRPCTransaction().SourceHash = %v, want %v", got.SourceHash, tx.SourceHash())
+ require.Equal(t, *got.IsSystemTx, tx.IsSystemTx(), "newRPCTransaction().IsSystemTx = %v, want %v", got.IsSystemTx, tx.IsSystemTx())
+ require.Equal(t, got.Mint, (*hexutil.Big)(tx.Mint()), "newRPCTransaction().Mint = %v, want %v", got.Mint, tx.Mint())
+ require.Equal(t, got.Nonce, (hexutil.Uint64)(nonce), "newRPCTransaction().Mint = %v, want %v", got.Nonce, nonce)
+}
+
+func TestNewRPCTransactionOmitIsSystemTxFalse(t *testing.T) {
+ tx := types.NewTx(&types.DepositTx{
+ IsSystemTransaction: false,
+ })
+ got := newRPCTransaction(tx, common.Hash{}, uint64(12), uint64(1234), uint64(1), big.NewInt(0), ¶ms.ChainConfig{}, 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)(common.Big0)
+ tx.R = (*hexutil.Big)(common.Big0)
+ tx.S = (*hexutil.Big)(common.Big0)
+ tx.GasPrice = (*hexutil.Big)(common.Big0)
+ },
+ valid: true,
+ },
+ {
+ name: "Nil Values",
+ modifier: func(tx *RPCTransaction) {
+ tx.V = nil
+ tx.R = nil
+ tx.S = nil
+ tx.GasPrice = nil
+ },
+ valid: true,
+ },
+ {
+ name: "Non-Zero GasPrice",
+ modifier: func(tx *RPCTransaction) {
+ tx.GasPrice = (*hexutil.Big)(big.NewInt(43))
+ },
+ valid: false,
+ },
+ {
+ name: "Non-Zero V",
+ modifier: func(tx *RPCTransaction) {
+ tx.V = (*hexutil.Big)(big.NewInt(43))
+ },
+ valid: false,
+ },
+ {
+ name: "Non-Zero R",
+ modifier: func(tx *RPCTransaction) {
+ tx.R = (*hexutil.Big)(big.NewInt(43))
+ },
+ valid: false,
+ },
+ {
+ name: "Non-Zero S",
+ modifier: func(tx *RPCTransaction) {
+ tx.S = (*hexutil.Big)(big.NewInt(43))
+ },
+ valid: false,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ tx := types.NewTx(&types.DepositTx{
+ SourceHash: common.HexToHash("0x1234"),
+ IsSystemTransaction: true,
+ Mint: big.NewInt(34),
+ })
+ rpcTx := newRPCTransaction(tx, common.Hash{}, uint64(12), uint64(1234), uint64(1), big.NewInt(0), ¶ms.ChainConfig{}, nil)
+ test.modifier(rpcTx)
+ json, err := json.Marshal(rpcTx)
+ require.NoError(t, err, "marshalling failed: %w", err)
+ parsed := &types.Transaction{}
+ 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")
+ }
+ })
+ }
+}
+
func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainConfig) {
t.Parallel()
var (
@@ -76,7 +192,7 @@ t.Fatalf("test %d: stx changed, want %x have %x", i, want, have)
}
// rpcTransaction
- rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config)
+ rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config, nil)
if data, err := json.Marshal(rpcTx); err != nil {
t.Fatalf("test %d: marshalling failed; %v", i, err)
} else if err = tx2.UnmarshalJSON(data); err != nil {
@@ -542,7 +658,7 @@ if vmConfig == nil {
vmConfig = b.chain.GetVMConfig()
}
txContext := core.NewEVMTxContext(msg)
- context := core.NewEVMBlockContext(header, b.chain, nil)
+ context := core.NewEVMBlockContext(header, b.chain, nil, b.ChainConfig(), state)
if blockContext != nil {
context = *blockContext
}
@@ -597,6 +713,12 @@ func (b testBackend) BloomStatus() (uint64, uint64) { panic("implement me") }
func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
panic("implement me")
}
+func (b testBackend) HistoricalRPCService() *rpc.Client {
+ panic("implement me")
+}
+func (b testBackend) Genesis() *types.Block {
+ panic("implement me")
+}
func TestEstimateGas(t *testing.T) {
t.Parallel()
@@ -763,7 +885,7 @@ From: &accounts[0].addr,
To: &accounts[1].addr,
Value: (*hexutil.Big)(big.NewInt(1000)),
},
- expectErr: errors.New("header not found"),
+ expectErr: ethereum.NotFound,
},
// transfer on the latest block
{
@@ -1043,7 +1165,7 @@ "to": "0x0000000000000000000000000000000000000011",
"transactionIndex": "0x1",
"value": "0x6f",
"type": "0x0",
- "chainId": "0x7fffffffffffffee",
+ "chainId": "0x1",
"v": "0x0",
"r": "0x0",
"s": "0x0"
@@ -1081,7 +1203,7 @@ "to": "0x0000000000000000000000000000000000000011",
"transactionIndex": "0x3",
"value": "0x6f",
"type": "0x0",
- "chainId": "0x7fffffffffffffee",
+ "chainId": "0x1",
"v": "0x0",
"r": "0x0",
"s": "0x0"
@@ -1094,7 +1216,11 @@ },
}
for i, tc := range testSuite {
- resp := RPCMarshalBlock(block, tc.inclTx, tc.fullTx, params.MainnetChainConfig)
+ resp, err := RPCMarshalBlock(context.Background(), block, tc.inclTx, tc.fullTx, params.MainnetChainConfig, testBackend{})
+ if err != nil {
+ t.Errorf("test %d: got error %v", i, err)
+ continue
+ }
out, err := json.Marshal(resp)
if err != nil {
t.Errorf("test %d: json marshal error: %v", i, err)
diff --git go-ethereum/light/odr_test.go op-geth/light/odr_test.go
index d8a7f1067556a15a1cde87b95b72f749325fd8eb..f0b6ca60187edf0b972efb86d8586e23ac43427a 100644
--- go-ethereum/light/odr_test.go
+++ op-geth/light/odr_test.go
@@ -213,7 +213,7 @@ Data: data,
SkipAccountChecks: true,
}
txContext := core.NewEVMTxContext(msg)
- context := core.NewEVMBlockContext(header, chain, nil)
+ context := core.NewEVMBlockContext(header, chain, nil, config, st)
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true})
gp := new(core.GasPool).AddGas(math.MaxUint64)
result, _ := core.ApplyMessage(vmenv, msg, gp)
diff --git go-ethereum/params/config_test.go op-geth/params/config_test.go
index bf8ce2fc5e247242615ff478a455785f9f07f88b..14d7f833bb978c2bb7cefc70cff2015079c9a04a 100644
--- go-ethereum/params/config_test.go
+++ op-geth/params/config_test.go
@@ -137,3 +137,22 @@ if r := c.Rules(big.NewInt(0), true, stamp); !r.IsShanghai {
t.Errorf("expected %v to be shanghai", stamp)
}
}
+
+func TestConfigRulesRegolith(t *testing.T) {
+ c := &ChainConfig{
+ RegolithTime: newUint64(500),
+ Optimism: &OptimismConfig{},
+ }
+ var stamp uint64
+ if r := c.Rules(big.NewInt(0), true, stamp); r.IsOptimismRegolith {
+ t.Errorf("expected %v to not be regolith", stamp)
+ }
+ stamp = 500
+ if r := c.Rules(big.NewInt(0), true, stamp); !r.IsOptimismRegolith {
+ t.Errorf("expected %v to be regolith", stamp)
+ }
+ stamp = math.MaxInt64
+ if r := c.Rules(big.NewInt(0), true, stamp); !r.IsOptimismRegolith {
+ t.Errorf("expected %v to be regolith", stamp)
+ }
+}
diff --git go-ethereum/params/superchain_test.go op-geth/params/superchain_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..a1fe1d5332ad24daa4cd4cd617019e97cb190762
--- /dev/null
+++ op-geth/params/superchain_test.go
@@ -0,0 +1,111 @@
+package params
+
+import (
+ "fmt"
+ "testing"
+)
+
+type HumanProtocolVersion struct {
+ VersionType uint8
+ Major, Minor, Patch uint32
+ Prerelease uint32
+ Build [8]byte
+}
+
+type ComparisonCase struct {
+ A, B HumanProtocolVersion
+ Cmp ProtocolVersionComparison
+}
+
+func TestProtocolVersion_Compare(t *testing.T) {
+ testCases := []ComparisonCase{
+ {
+ A: HumanProtocolVersion{0, 2, 1, 1, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 1, 2, 2, 2, [8]byte{}},
+ Cmp: AheadMajor,
+ },
+ {
+ A: HumanProtocolVersion{0, 1, 2, 1, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 1, 1, 2, 2, [8]byte{}},
+ Cmp: AheadMinor,
+ },
+ {
+ A: HumanProtocolVersion{0, 1, 1, 2, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 1, 1, 1, 2, [8]byte{}},
+ Cmp: AheadPatch,
+ },
+ {
+ A: HumanProtocolVersion{0, 1, 1, 1, 2, [8]byte{}},
+ B: HumanProtocolVersion{0, 1, 1, 1, 1, [8]byte{}},
+ Cmp: AheadPrerelease,
+ },
+ {
+ A: HumanProtocolVersion{0, 1, 2, 3, 4, [8]byte{}},
+ B: HumanProtocolVersion{0, 1, 2, 3, 4, [8]byte{}},
+ Cmp: Matching,
+ },
+ {
+ A: HumanProtocolVersion{0, 3, 2, 1, 5, [8]byte{3}},
+ B: HumanProtocolVersion{1, 1, 2, 3, 3, [8]byte{6}},
+ Cmp: DiffVersionType,
+ },
+ {
+ A: HumanProtocolVersion{0, 3, 2, 1, 5, [8]byte{3}},
+ B: HumanProtocolVersion{0, 1, 2, 3, 3, [8]byte{6}},
+ Cmp: DiffBuild,
+ },
+ {
+ A: HumanProtocolVersion{0, 0, 0, 0, 0, [8]byte{}},
+ B: HumanProtocolVersion{0, 1, 3, 3, 3, [8]byte{3}},
+ Cmp: EmptyVersion,
+ },
+ }
+ for i, tc := range testCases {
+ t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) {
+ a := ProtocolVersionV0{tc.A.Build, tc.A.Major, tc.A.Minor, tc.A.Patch, tc.A.Prerelease}.Encode()
+ a[0] = tc.A.VersionType
+ b := ProtocolVersionV0{tc.B.Build, tc.B.Major, tc.B.Minor, tc.B.Patch, tc.B.Prerelease}.Encode()
+ b[0] = tc.B.VersionType
+ cmp := a.Compare(b)
+ if cmp != tc.Cmp {
+ t.Fatalf("expected %d but got %d", tc.Cmp, cmp)
+ }
+ switch tc.Cmp {
+ case AheadMajor, AheadMinor, AheadPatch, AheadPrerelease:
+ inv := b.Compare(a)
+ if inv != -tc.Cmp {
+ t.Fatalf("expected inverse when reversing the comparison, %d but got %d", -tc.Cmp, inv)
+ }
+ case DiffVersionType, DiffBuild, EmptyVersion, Matching:
+ inv := b.Compare(a)
+ if inv != tc.Cmp {
+ t.Fatalf("expected comparison reversed to hold the same, expected %d but got %d", tc.Cmp, inv)
+ }
+ }
+ })
+ }
+}
+func TestProtocolVersion_String(t *testing.T) {
+ testCases := []struct {
+ version ProtocolVersion
+ expected string
+ }{
+ {ProtocolVersionV0{[8]byte{}, 0, 0, 0, 0}.Encode(), "v0.0.0"},
+ {ProtocolVersionV0{[8]byte{}, 0, 0, 0, 1}.Encode(), "v0.0.0-1"},
+ {ProtocolVersionV0{[8]byte{}, 0, 0, 1, 0}.Encode(), "v0.0.1"},
+ {ProtocolVersionV0{[8]byte{}, 4, 3, 2, 1}.Encode(), "v4.3.2-1"},
+ {ProtocolVersionV0{[8]byte{}, 0, 100, 2, 0}.Encode(), "v0.100.2"},
+ {ProtocolVersionV0{[8]byte{'O', 'P', '-', 'm', 'o', 'd'}, 42, 0, 2, 1}.Encode(), "v42.0.2-1+OP-mod"},
+ {ProtocolVersionV0{[8]byte{'b', 'e', 't', 'a', '.', '1', '2', '3'}, 1, 0, 0, 0}.Encode(), "v1.0.0+beta.123"},
+ {ProtocolVersionV0{[8]byte{'a', 'b', 1}, 42, 0, 2, 0}.Encode(), "v42.0.2+0x6162010000000000"}, // do not render invalid alpha numeric
+ {ProtocolVersionV0{[8]byte{1, 2, 3, 4, 5, 6, 7, 8}, 42, 0, 2, 0}.Encode(), "v42.0.2+0x0102030405060708"},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.expected, func(t *testing.T) {
+ got := tc.version.String()
+ if got != tc.expected {
+ t.Fatalf("got %q but expected %q", got, tc.expected)
+ }
+ })
+ }
+}
diff --git go-ethereum/tests/state_test.go op-geth/tests/state_test.go
index 094dafcafd7a372b7f8331d14fe1b387bc5a7357..42b46e9c40a70e40432268b1351bdf7dbeeb547b 100644
--- go-ethereum/tests/state_test.go
+++ op-geth/tests/state_test.go
@@ -259,7 +259,7 @@ }
// Prepare the EVM.
txContext := core.NewEVMTxContext(msg)
- context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
+ context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase, config, statedb)
context.GetHash = vmTestBlockHash
context.BaseFee = baseFee
evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
diff --git go-ethereum/tests/state_test_util.go op-geth/tests/state_test_util.go
index 8c255c1b5bd23c1c3fa374fb997d57f596c3a56d..d09b29b762201785d988ae1a9aa79c4f0e684fad 100644
--- go-ethereum/tests/state_test_util.go
+++ op-geth/tests/state_test_util.go
@@ -268,7 +268,7 @@ }
// Prepare the EVM.
txContext := core.NewEVMTxContext(msg)
- context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
+ context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase, config, statedb)
context.GetHash = vmTestBlockHash
context.BaseFee = baseFee
context.Random = nil