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 54eb63f3deb2f1dcb16f5b70582473c832852e8e..14087af4f8f94f146d942035a669e88cda1c754e 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/cmd/evm/internal/t8ntool/transition.go op-geth/cmd/evm/internal/t8ntool/transition.go
index d517592e5cfb4693533baf1d5b199b00e50b7a8b..971adffec2200eb8cefa21e947ad11ef7b6bc702 100644
--- go-ethereum/cmd/evm/internal/t8ntool/transition.go
+++ op-geth/cmd/evm/internal/t8ntool/transition.go
@@ -231,7 +231,7 @@ Number: new(big.Int).SetUint64(env.Number - 1),
BaseFee: env.ParentBaseFee,
GasUsed: env.ParentGasUsed,
GasLimit: env.ParentGasLimit,
- })
+ }, env.Timestamp)
return nil
}
diff --git go-ethereum/consensus/misc/create2deployer.go op-geth/consensus/misc/create2deployer.go
new file mode 100644
index 0000000000000000000000000000000000000000..27c87a4a8c45b1e859719e8d4f8e5775ff3da0ca
--- /dev/null
+++ op-geth/consensus/misc/create2deployer.go
@@ -0,0 +1,37 @@
+package misc
+
+import (
+ "github.com/ethereum-optimism/superchain-registry/superchain"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/params"
+)
+
+// The original create2deployer contract could not be deployed to Base mainnet at
+// the canonical address of 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2 due to
+// an accidental nonce increment from a deposit transaction. See
+// https://github.com/pcaversaccio/create2deployer/issues/128 for context. This
+// file applies the contract code to the canonical address manually in the Canyon
+// hardfork.
+
+var create2DeployerAddress = common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2")
+var create2DeployerCodeHash = common.HexToHash("0xb0550b5b431e30d38000efb7107aaa0ade03d48a7198a140edda9d27134468b2")
+var create2DeployerCode []byte
+
+func init() {
+ code, err := superchain.LoadContractBytecode(superchain.Hash(create2DeployerCodeHash))
+ if err != nil {
+ panic(err)
+ }
+ create2DeployerCode = code
+}
+
+func EnsureCreate2Deployer(c *params.ChainConfig, timestamp uint64, db vm.StateDB) {
+ if !c.IsOptimism() || c.CanyonTime == nil || *c.CanyonTime != timestamp {
+ return
+ }
+ log.Info("Setting Create2Deployer code", "address", create2DeployerAddress, "codeHash", create2DeployerCodeHash)
+ db.SetCode(create2DeployerAddress, create2DeployerCode)
+}
diff --git go-ethereum/consensus/misc/create2deployer_test.go op-geth/consensus/misc/create2deployer_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..fc0ef79fd7739d92431085d515481be8621e8fcb
--- /dev/null
+++ op-geth/consensus/misc/create2deployer_test.go
@@ -0,0 +1,95 @@
+package misc
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/params"
+)
+
+func TestEnsureCreate2Deployer(t *testing.T) {
+ canyonTime := uint64(1000)
+ var tests = []struct {
+ name string
+ override func(cfg *params.ChainConfig)
+ timestamp uint64
+ codeExists bool
+ applied bool
+ }{
+ {
+ name: "at hardfork",
+ timestamp: canyonTime,
+ applied: true,
+ },
+ {
+ name: "another chain ID",
+ override: func(cfg *params.ChainConfig) {
+ cfg.ChainID = big.NewInt(params.OPMainnetChainID)
+ },
+ timestamp: canyonTime,
+ applied: true,
+ },
+ {
+ name: "code already exists",
+ timestamp: canyonTime,
+ codeExists: true,
+ applied: true,
+ },
+ {
+ name: "pre canyon",
+ timestamp: canyonTime - 1,
+ applied: false,
+ },
+ {
+ name: "post hardfork",
+ timestamp: canyonTime + 1,
+ applied: false,
+ },
+ {
+ name: "canyon not configured",
+ override: func(cfg *params.ChainConfig) {
+ cfg.CanyonTime = nil
+ },
+ timestamp: canyonTime,
+ applied: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ cfg := params.ChainConfig{
+ ChainID: big.NewInt(params.BaseMainnetChainID),
+ Optimism: ¶ms.OptimismConfig{},
+ CanyonTime: &canyonTime,
+ }
+ if tt.override != nil {
+ tt.override(&cfg)
+ }
+ state := &stateDb{
+ codeExists: tt.codeExists,
+ }
+ EnsureCreate2Deployer(&cfg, tt.timestamp, state)
+ assert.Equal(t, tt.applied, state.codeSet)
+ })
+ }
+}
+
+type stateDb struct {
+ vm.StateDB
+ codeExists bool
+ codeSet bool
+}
+
+func (s *stateDb) GetCodeSize(_ common.Address) int {
+ if s.codeExists {
+ return 1
+ }
+ return 0
+}
+
+func (s *stateDb) SetCode(_ common.Address, _ []byte) {
+ s.codeSet = true
+}
diff --git go-ethereum/consensus/misc/eip1559/eip1559_test.go op-geth/consensus/misc/eip1559/eip1559_test.go
index b5afdf0fe5e56ca6ced6031be233c6aafb17dcdd..d34da8fd8bbb21a6a649384435c3926a6735083d 100644
--- go-ethereum/consensus/misc/eip1559/eip1559_test.go
+++ op-geth/consensus/misc/eip1559/eip1559_test.go
@@ -55,6 +55,19 @@ config.LondonBlock = big.NewInt(5)
return config
}
+func opConfig() *params.ChainConfig {
+ config := copyConfig(params.TestChainConfig)
+ config.LondonBlock = big.NewInt(5)
+ ct := uint64(10)
+ config.CanyonTime = &ct
+ config.Optimism = ¶ms.OptimismConfig{
+ EIP1559Elasticity: 6,
+ EIP1559Denominator: 50,
+ EIP1559DenominatorCanyon: 250,
+ }
+ return config
+}
+
// TestBlockGasLimits tests the gasLimit checks for blocks both across
// the EIP-1559 boundary and post-1559 blocks
func TestBlockGasLimits(t *testing.T) {
@@ -124,7 +137,40 @@ GasLimit: test.parentGasLimit,
GasUsed: test.parentGasUsed,
BaseFee: big.NewInt(test.parentBaseFee),
}
- if have, want := CalcBaseFee(config(), parent), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 {
+ if have, want := CalcBaseFee(config(), parent, 0), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 {
+ t.Errorf("test %d: have %d want %d, ", i, have, want)
+ }
+ }
+}
+
+// TestCalcBaseFeeOptimism assumes all blocks are 1559-blocks but tests the Canyon activation
+func TestCalcBaseFeeOptimism(t *testing.T) {
+ tests := []struct {
+ parentBaseFee int64
+ parentGasLimit uint64
+ parentGasUsed uint64
+ expectedBaseFee int64
+ postCanyon bool
+ }{
+ {params.InitialBaseFee, 30_000_000, 5_000_000, params.InitialBaseFee, false}, // usage == target
+ {params.InitialBaseFee, 30_000_000, 4_000_000, 996000000, false}, // usage below target
+ {params.InitialBaseFee, 30_000_000, 10_000_000, 1020000000, false}, // usage above target
+ {params.InitialBaseFee, 30_000_000, 5_000_000, params.InitialBaseFee, true}, // usage == target
+ {params.InitialBaseFee, 30_000_000, 4_000_000, 999200000, true}, // usage below target
+ {params.InitialBaseFee, 30_000_000, 10_000_000, 1004000000, true}, // usage above target
+ }
+ for i, test := range tests {
+ parent := &types.Header{
+ Number: common.Big32,
+ GasLimit: test.parentGasLimit,
+ GasUsed: test.parentGasUsed,
+ BaseFee: big.NewInt(test.parentBaseFee),
+ Time: 6,
+ }
+ if test.postCanyon {
+ parent.Time = 8
+ }
+ if have, want := CalcBaseFee(opConfig(), parent, parent.Time+2), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 {
t.Errorf("test %d: have %d want %d, ", i, have, want)
}
}
diff --git go-ethereum/core/chain_makers.go op-geth/core/chain_makers.go
index 31c111b73e06eb252274754bf320835fbc0a5897..90b5b1fcee370a8b5d23f567de0b9ed68b923107 100644
--- go-ethereum/core/chain_makers.go
+++ op-geth/core/chain_makers.go
@@ -97,7 +97,7 @@ // block.
func (b *BlockGen) SetParentBeaconRoot(root common.Hash) {
b.header.ParentBeaconRoot = &root
var (
- blockContext = NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase)
+ blockContext = NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase, b.cm.config, b.statedb)
vmenv = vm.NewEVM(blockContext, vm.TxContext{}, b.statedb, b.cm.config, vm.Config{})
)
ProcessBeaconBlockRoot(root, vmenv, b.statedb)
@@ -229,7 +229,7 @@
// The gas limit and price should be derived from the parent
h.GasLimit = parent.GasLimit
if b.cm.config.IsLondon(h.Number) {
- h.BaseFee = eip1559.CalcBaseFee(b.cm.config, parent)
+ h.BaseFee = eip1559.CalcBaseFee(b.cm.config, parent, h.Time)
if !b.cm.config.IsLondon(parent.Number) {
parentGasLimit := parent.GasLimit * b.cm.config.ElasticityMultiplier()
h.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit)
@@ -429,7 +429,7 @@ Time: time,
}
if cm.config.IsLondon(header.Number) {
- header.BaseFee = eip1559.CalcBaseFee(cm.config, parent.Header())
+ header.BaseFee = eip1559.CalcBaseFee(cm.config, parent.Header(), header.Time)
if !cm.config.IsLondon(parent.Number()) {
parentGasLimit := parent.GasLimit() * cm.config.ElasticityMultiplier()
header.GasLimit = CalcGasLimit(parentGasLimit, parentGasLimit)
diff --git go-ethereum/core/rawdb/accessors_chain_test.go op-geth/core/rawdb/accessors_chain_test.go
index a7ceb72998a115653130a19932f443dfda3f7cc4..3340c7f15c8200a11b2831abb90dd4a052b2b6f8 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,13 +383,16 @@ 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)
if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) == 0 {
@@ -694,36 +702,56 @@
// 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)
+ tx3 := types.NewTransaction(3, common.HexToAddress("0x3"), big.NewInt(3), 3, big.NewInt(3), nil)
- body := &types.Body{Transactions: types.Transactions{tx1, tx2}}
+ body := &types.Body{Transactions: types.Transactions{tx1, tx2, tx3}}
- // Create the two receipts to manage afterwards
- receipt1 := &types.Receipt{
+ // Create the three receipts to manage afterwards
+ depositNonce := uint64(math.MaxUint64)
+ depositReceipt := types.Receipt{
Status: types.ReceiptStatusFailed,
CumulativeGasUsed: 1,
Logs: []*types.Log{
{Address: common.BytesToAddress([]byte{0x11})},
{Address: common.BytesToAddress([]byte{0x01, 0x11})},
},
- TxHash: tx1.Hash(),
- ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
- GasUsed: 111111,
+ TxHash: tx1.Hash(),
+ ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
+ GasUsed: 111111,
+ DepositNonce: &depositNonce,
+ DepositReceiptVersion: nil,
}
- receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1})
+ depositReceipt.Bloom = types.CreateBloom(types.Receipts{&depositReceipt})
- receipt2 := &types.Receipt{
- PostState: common.Hash{2}.Bytes(),
+ receiptVersion := types.CanyonDepositReceiptVersion
+ versionedDepositReceipt := types.Receipt{
+ Status: types.ReceiptStatusFailed,
CumulativeGasUsed: 2,
Logs: []*types.Log{
{Address: common.BytesToAddress([]byte{0x22})},
- {Address: common.BytesToAddress([]byte{0x02, 0x22})},
+ {Address: common.BytesToAddress([]byte{0x01, 0x11})},
+ },
+ TxHash: tx2.Hash(),
+ ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
+ GasUsed: 222222,
+ DepositNonce: &depositNonce,
+ DepositReceiptVersion: &receiptVersion,
+ }
+ versionedDepositReceipt.Bloom = types.CreateBloom(types.Receipts{&versionedDepositReceipt})
+
+ receipt := types.Receipt{
+ PostState: common.Hash{3}.Bytes(),
+ CumulativeGasUsed: 3,
+ Logs: []*types.Log{
+ {Address: common.BytesToAddress([]byte{0x33})},
+ {Address: common.BytesToAddress([]byte{0x03, 0x33})},
},
- TxHash: tx2.Hash(),
- ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
- GasUsed: 222222,
+ TxHash: tx3.Hash(),
+ ContractAddress: common.BytesToAddress([]byte{0x03, 0x33, 0x33}),
+ GasUsed: 333333,
}
- receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2})
- receipts := []*types.Receipt{receipt1, receipt2}
+ receipt.Bloom = types.CreateBloom(types.Receipts{&receipt})
+ receipts := []*types.Receipt{&receipt, &depositReceipt, &versionedDepositReceipt}
hash := common.BytesToHash([]byte{0x03, 0x14})
// Check that no receipt entries are in a pristine database
@@ -740,14 +768,13 @@ logs := ReadLogs(db, hash, 0)
if len(logs) == 0 {
t.Fatalf("no logs returned")
}
- if have, want := len(logs), 2; have != want {
+ if have, want := len(logs), 3; have != want {
t.Fatalf("unexpected number of logs returned, have %d want %d", have, want)
}
- if have, want := len(logs[0]), 2; have != want {
- t.Fatalf("unexpected number of logs[0] returned, have %d want %d", have, want)
- }
- if have, want := len(logs[1]), 2; have != want {
- t.Fatalf("unexpected number of logs[1] returned, have %d want %d", have, want)
+ for i := range logs {
+ if have, want := len(logs[i]), 2; have != want {
+ t.Fatalf("unexpected number of logs[%d] returned, have %d want %d", i, have, want)
+ }
}
for i, pr := range receipts {
@@ -765,6 +792,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/state_processor_test.go op-geth/core/state_processor_test.go
index 5ff9353bd9a4640e5911797b958d59ed50bd7d01..5bfb5947a7d409b9cd6cd7a0ef296a91bc791499 100644
--- go-ethereum/core/state_processor_test.go
+++ op-geth/core/state_processor_test.go
@@ -379,7 +379,7 @@ Time: parent.Time() + 10,
UncleHash: types.EmptyUncleHash,
}
if config.IsLondon(header.Number) {
- header.BaseFee = eip1559.CalcBaseFee(config, parent.Header())
+ header.BaseFee = eip1559.CalcBaseFee(config, parent.Header(), header.Time)
}
if config.IsShanghai(header.Number, header.Time) {
header.WithdrawalsHash = &types.EmptyWithdrawalsHash
diff --git go-ethereum/core/superchain_test.go op-geth/core/superchain_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..9959374bddc1e87dd95e5995811054c581068d71
--- /dev/null
+++ op-geth/core/superchain_test.go
@@ -0,0 +1,54 @@
+package core
+
+import (
+ "testing"
+
+ "github.com/ethereum-optimism/superchain-registry/superchain"
+
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/trie"
+)
+
+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())
+ }
+}
+
+func TestRegistryChainConfigOverride(t *testing.T) {
+ db := rawdb.NewMemoryDatabase()
+ genesis, err := LoadOPStackGenesis(10)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if genesis.Config.RegolithTime == nil {
+ t.Fatal("expected non-nil regolith time")
+ }
+ expectedRegolithTime := *genesis.Config.RegolithTime
+ genesis.Config.RegolithTime = nil
+
+ // initialize the DB
+ tdb := trie.NewDatabase(db, newDbConfig(rawdb.PathScheme))
+ genesis.MustCommit(db, tdb)
+ bl := genesis.ToBlock()
+ rawdb.WriteCanonicalHash(db, bl.Hash(), 0)
+ rawdb.WriteBlock(db, bl)
+
+ // create chain config, even with incomplete genesis input: the chain config should be corrected
+ chainConfig, _, err := SetupGenesisBlockWithOverride(db, tdb, genesis, &ChainOverrides{
+ ApplySuperchainUpgrades: true,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ // check if we have a corrected chain config
+ if chainConfig.RegolithTime == nil {
+ t.Fatal("expected regolith time to be corrected, but time is still nil")
+ } else if *chainConfig.RegolithTime != expectedRegolithTime {
+ t.Fatalf("expected regolith time to be %d, but got %d", expectedRegolithTime, *chainConfig.RegolithTime)
+ }
+}
diff --git go-ethereum/core/txpool/blobpool/blobpool.go op-geth/core/txpool/blobpool/blobpool.go
index 32c6c0e8feeff9db0bf2ebaedb9869decc82b336..3b6292d6423ee550657a479176ea85403add7341 100644
--- go-ethereum/core/txpool/blobpool/blobpool.go
+++ op-geth/core/txpool/blobpool/blobpool.go
@@ -399,7 +399,7 @@ for addr := range p.index {
p.recheck(addr, nil)
}
var (
- basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), p.head))
+ basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), p.head, p.head.Time+1))
blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice))
)
if p.head.ExcessBlobGas != nil {
@@ -782,7 +782,7 @@ p.limbo.finalize(p.chain.CurrentFinalBlock())
}
// Reset the price heap for the new set of basefee/blobfee pairs
var (
- basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), newHead))
+ basefee = uint256.MustFromBig(eip1559.CalcBaseFee(p.chain.Config(), newHead, newHead.Time+1))
blobfee = uint256.MustFromBig(big.NewInt(params.BlobTxMinBlobGasprice))
)
if newHead.ExcessBlobGas != nil {
diff --git go-ethereum/core/txpool/blobpool/blobpool_test.go op-geth/core/txpool/blobpool/blobpool_test.go
index 8914301e14c32648498077d51ee1d3ddc5484734..6011f33bfa42117a1d7446cd0145f2b7e7ecf2ae 100644
--- go-ethereum/core/txpool/blobpool/blobpool_test.go
+++ op-geth/core/txpool/blobpool/blobpool_test.go
@@ -114,7 +114,7 @@ Number: blockNumber,
GasLimit: gasLimit,
GasUsed: 0,
BaseFee: mid,
- }).Cmp(bc.basefee.ToBig()) > 0 {
+ }, blockTime).Cmp(bc.basefee.ToBig()) > 0 {
hi = mid
} else {
lo = mid
diff --git go-ethereum/core/types/receipt_test.go op-geth/core/types/receipt_test.go
index a7b26444712fe8c669ea732fa423588a58497f32..766640129cb4f59229ae5c2ea0f5dde1301bdc01 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,63 @@ },
},
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,
+ DepositReceiptVersion: nil,
+ 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,
+ }
+ version = CanyonDepositReceiptVersion
+ depositReceiptWithNonceAndVersion = &Receipt{
+ Status: ReceiptStatusFailed,
+ CumulativeGasUsed: 1,
+ DepositNonce: &nonce,
+ DepositReceiptVersion: &version,
+ 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,11 +208,23 @@ GasFeeCap: uint256.NewInt(1077),
BlobFeeCap: uint256.NewInt(100077),
BlobHashes: []common.Hash{{}, {}, {}},
}),
+ NewTx(&DepositTx{
+ To: nil, // contract creation
+ Value: big.NewInt(6),
+ Gas: 50,
+ }),
+ NewTx(&DepositTx{
+ To: nil, // contract creation
+ Value: big.NewInt(6),
+ Gas: 60,
+ }),
}
-
- blockNumber = big.NewInt(1)
- blockTime = uint64(2)
- blockHash = common.BytesToHash([]byte{0x03, 0x14})
+ depNonce1 = uint64(7)
+ depNonce2 = uint64(8)
+ blockNumber = big.NewInt(1)
+ blockTime = uint64(2)
+ blockHash = common.BytesToHash([]byte{0x03, 0x14})
+ canyonDepositReceiptVersion = CanyonDepositReceiptVersion
// Create the corresponding receipts
receipts = Receipts{
@@ -293,6 +364,78 @@ 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: &depNonce1,
+ DepositReceiptVersion: nil,
+ },
+ &Receipt{
+ Type: DepositTxType,
+ PostState: common.Hash{5}.Bytes(),
+ CumulativeGasUsed: 60 + 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[8].Hash(),
+ TxIndex: 8,
+ BlockHash: blockHash,
+ Index: 6,
+ },
+ {
+ Address: common.BytesToAddress([]byte{0x03, 0x33}),
+ Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
+ // derived fields:
+ BlockNumber: blockNumber.Uint64(),
+ TxHash: txs[8].Hash(),
+ TxIndex: 8,
+ BlockHash: blockHash,
+ Index: 7,
+ },
+ },
+ TxHash: txs[8].Hash(),
+ ContractAddress: common.HexToAddress("0x117814af22cb83d8ad6e8489e9477d28265bc105"),
+ GasUsed: 60,
+ EffectiveGasPrice: big.NewInt(0),
+ BlockHash: blockHash,
+ BlockNumber: blockNumber,
+ TransactionIndex: 8,
+ DepositNonce: &depNonce2,
+ DepositReceiptVersion: &canyonDepositReceiptVersion,
+ },
}
)
@@ -344,6 +487,18 @@ r := Receipt{}
err = r.UnmarshalJSON(b)
if err != nil {
t.Fatal("error unmarshaling receipt from json:", err)
+ }
+
+ // Make sure marshal/unmarshal doesn't affect receipt hash root computation by comparing
+ // the output of EncodeIndex
+ rsBefore := Receipts([]*Receipt{receipts[i]})
+ rsAfter := Receipts([]*Receipt{&r})
+
+ encBefore, encAfter := bytes.Buffer{}, bytes.Buffer{}
+ rsBefore.EncodeIndex(0, &encBefore)
+ rsAfter.EncodeIndex(0, &encAfter)
+ if !bytes.Equal(encBefore.Bytes(), encAfter.Bytes()) {
+ t.Errorf("%v: EncodeIndex differs after JSON marshal/unmarshal", i)
}
}
}
@@ -527,3 +682,257 @@ 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)
+ // ..or a deposit nonce
+ require.Nil(t, parsed.DepositReceiptVersion)
+}
+
+// Regolith introduced an inconsistency in behavior between EncodeIndex and MarshalBinary for a
+// deposit transaction receipt. TestReceiptEncodeIndexBugIsEnshrined makes sure this difference is
+// preserved for backwards compatibility purposes, but also that there is no discrepancy for the
+// post-Canyon encoding.
+func TestReceiptEncodeIndexBugIsEnshrined(t *testing.T) {
+ // Check that a post-Regolith, pre-Canyon receipt produces the expected difference between
+ // EncodeIndex and MarshalBinary.
+ buf := new(bytes.Buffer)
+ receipts := Receipts{depositReceiptWithNonce}
+ receipts.EncodeIndex(0, buf)
+ indexBytes := buf.Bytes()
+
+ regularBytes, _ := receipts[0].MarshalBinary()
+
+ require.NotEqual(t, indexBytes, regularBytes)
+
+ // Confirm the buggy encoding is as expected, which means it should encode as if it had no
+ // nonce specified (like that of a non-deposit receipt, whose encoding would differ only in the
+ // type byte).
+ buf.Reset()
+ tempReceipt := *depositReceiptWithNonce
+ tempReceipt.Type = eip1559Receipt.Type
+ buggyBytes, _ := tempReceipt.MarshalBinary()
+
+ require.Equal(t, indexBytes[1:], buggyBytes[1:])
+
+ // check that the post-Canyon encoding has no differences between EncodeIndex and
+ // MarshalBinary.
+ buf.Reset()
+ receipts = Receipts{depositReceiptWithNonceAndVersion}
+ receipts.EncodeIndex(0, buf)
+ indexBytes = buf.Bytes()
+
+ regularBytes, _ = receipts[0].MarshalBinary()
+
+ require.Equal(t, indexBytes, regularBytes)
+
+ // Check that bumping the nonce post-canyon changes the hash
+ bumpedReceipt := *depositReceiptWithNonceAndVersion
+ bumpedNonce := nonce + 1
+ bumpedReceipt.DepositNonce = &bumpedNonce
+ bumpedBytes, _ := bumpedReceipt.MarshalBinary()
+ require.NotEqual(t, regularBytes, bumpedBytes)
+}
+
+func TestRoundTripReceipt(t *testing.T) {
+ tests := []struct {
+ name string
+ rcpt *Receipt
+ }{
+ {name: "Legacy", rcpt: legacyReceipt},
+ {name: "AccessList", rcpt: accessListReceipt},
+ {name: "EIP1559", rcpt: eip1559Receipt},
+ {name: "DepositNoNonce", rcpt: depositReceiptNoNonce},
+ {name: "DepositWithNonce", rcpt: depositReceiptWithNonce},
+ {name: "DepositWithNonceAndVersion", rcpt: depositReceiptWithNonceAndVersion},
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ data, err := test.rcpt.MarshalBinary()
+ require.NoError(t, err)
+
+ d := &Receipt{}
+ err = d.UnmarshalBinary(data)
+ require.NoError(t, err)
+ require.Equal(t, test.rcpt, d)
+ require.Equal(t, test.rcpt.DepositNonce, d.DepositNonce)
+ require.Equal(t, test.rcpt.DepositReceiptVersion, d.DepositReceiptVersion)
+ })
+
+ t.Run(fmt.Sprintf("%sRejectExtraData", test.name), func(t *testing.T) {
+ data, err := 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},
+ {name: "DepositWithNonceAndVersion", rcpt: depositReceiptWithNonceAndVersion},
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ data, err := rlp.EncodeToBytes((*ReceiptForStorage)(test.rcpt))
+ require.NoError(t, err)
+
+ d := &ReceiptForStorage{}
+ err = rlp.DecodeBytes(data, d)
+ require.NoError(t, err)
+ // Only check the stored fields - the others are derived later
+ require.Equal(t, test.rcpt.Status, d.Status)
+ require.Equal(t, test.rcpt.CumulativeGasUsed, d.CumulativeGasUsed)
+ require.Equal(t, test.rcpt.Logs, d.Logs)
+ require.Equal(t, test.rcpt.DepositNonce, d.DepositNonce)
+ require.Equal(t, test.rcpt.DepositReceiptVersion, d.DepositReceiptVersion)
+ })
+ }
+}
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..4fd46a4c1257c38998878071ef618a71849e6d6e
--- /dev/null
+++ op-geth/eth/catalyst/superchain_test.go
@@ -0,0 +1,120 @@
+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) {
+ // Note: depending on the params.OPStackSupport some types of bumps are not possible with active prerelease
+ 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 {
+ tc := tc
+ 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()
+ if preRelease != 0 { // transform back from prerelease, so we can do a clean version bump
+ if patch != 0 {
+ patch -= 1
+ } else if minor != 0 {
+ // can't patch-bump e.g. v3.1.0-1, the prerelease forces a minor bump:
+ // v3.0.999 is lower than the prerelease, v3.1.1-1 is a prerelease of v3.1.1.
+ if tc.bump == "patch" {
+ t.Skip()
+ }
+ minor -= 1
+ } else if major != 0 {
+ if tc.bump == "minor" || tc.bump == "patch" { // can't minor-bump or patch-bump
+ t.Skip()
+ }
+ major -= 1
+ }
+ preRelease = 0
+ }
+ 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 we are not stopped already
+ 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/feehistory.go op-geth/eth/gasprice/feehistory.go
index 226991b24b2c635f2c7708bbcbb828e05676aacb..13f36499d4222a259aa89eef27fa958026d85ab7 100644
--- go-ethereum/eth/gasprice/feehistory.go
+++ op-geth/eth/gasprice/feehistory.go
@@ -83,7 +83,7 @@ if bf.results.baseFee = bf.header.BaseFee; bf.results.baseFee == nil {
bf.results.baseFee = new(big.Int)
}
if chainconfig.IsLondon(big.NewInt(int64(bf.blockNumber + 1))) {
- bf.results.nextBaseFee = eip1559.CalcBaseFee(chainconfig, bf.header)
+ bf.results.nextBaseFee = eip1559.CalcBaseFee(chainconfig, bf.header, bf.header.Time+1)
} else {
bf.results.nextBaseFee = new(big.Int)
}
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/graphql/graphql.go op-geth/graphql/graphql.go
index 49be23af69dd8caebd8ecc44e84f342d12d2f1ac..d8330dffc68323dad92b0ce2d0a7d581922b84f0 100644
--- go-ethereum/graphql/graphql.go
+++ op-geth/graphql/graphql.go
@@ -773,7 +773,7 @@ if !chaincfg.IsLondon(new(big.Int).Add(header.Number, common.Big1)) {
return nil, nil
}
}
- nextBaseFee := eip1559.CalcBaseFee(chaincfg, header)
+ nextBaseFee := eip1559.CalcBaseFee(chaincfg, header, header.Time+1)
return (*hexutil.Big)(nextBaseFee), nil
}
diff --git go-ethereum/internal/ethapi/api_test.go op-geth/internal/ethapi/api_test.go
index a67bd1203b9a34f06d76f4b5800dccd6e615f31e..3380a591c05dca2162eb95ca66aeb0fadcce448e 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,166 @@ "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().Nonce = %v, want %v", got.Nonce, nonce)
+}
+
+func TestRPCTransactionDepositTxWithVersion(t *testing.T) {
+ tx := types.NewTx(&types.DepositTx{
+ SourceHash: common.HexToHash("0x1234"),
+ IsSystemTransaction: true,
+ Mint: big.NewInt(34),
+ })
+ nonce := uint64(7)
+ version := types.CanyonDepositReceiptVersion
+ receipt := &types.Receipt{
+ DepositNonce: &nonce,
+ DepositReceiptVersion: &version,
+ }
+ 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 versioned deposit tx specific fields
+ require.Equal(t, *got.SourceHash, tx.SourceHash(), "newRPCTransaction().SourceHash = %v, want %v", got.SourceHash, tx.SourceHash())
+ require.Equal(t, *got.IsSystemTx, tx.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().Nonce = %v, want %v", got.Nonce, nonce)
+ require.Equal(t, *got.DepositReceiptVersion, (hexutil.Uint64(version)), "newRPCTransaction().DepositReceiptVersion = %v, want %v", *got.DepositReceiptVersion, version)
+
+ // Make sure json marshal/unmarshal of the rpc tx preserves the receipt version
+ b, err := json.Marshal(got)
+ require.NoError(t, err, "marshalling failed: %w", err)
+ parsed := make(map[string]interface{})
+ err = json.Unmarshal(b, &parsed)
+ require.NoError(t, err, "unmarshalling failed: %w", err)
+ require.Equal(t, "0x1", parsed["depositReceiptVersion"])
+}
+
+func TestNewRPCTransactionOmitIsSystemTxFalse(t *testing.T) {
+ tx := types.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) {
+ version := hexutil.Uint64(types.CanyonDepositReceiptVersion)
+ tests := []struct {
+ name string
+ modifier func(tx *RPCTransaction)
+ valid bool
+ }{
+ {
+ name: "Unmodified",
+ modifier: func(tx *RPCTransaction) {},
+ valid: true,
+ },
+ {
+ name: "Zero Values",
+ modifier: func(tx *RPCTransaction) {
+ tx.V = (*hexutil.Big)(common.Big0)
+ tx.R = (*hexutil.Big)(common.Big0)
+ tx.S = (*hexutil.Big)(common.Big0)
+ tx.GasPrice = (*hexutil.Big)(common.Big0)
+ },
+ valid: true,
+ },
+ {
+ name: "Nil Values",
+ modifier: func(tx *RPCTransaction) {
+ tx.V = nil
+ tx.R = nil
+ tx.S = nil
+ tx.GasPrice = nil
+ },
+ valid: true,
+ },
+ {
+ name: "Non-Zero GasPrice",
+ modifier: func(tx *RPCTransaction) {
+ tx.GasPrice = (*hexutil.Big)(big.NewInt(43))
+ },
+ valid: false,
+ },
+ {
+ name: "Non-Zero V",
+ modifier: func(tx *RPCTransaction) {
+ tx.V = (*hexutil.Big)(big.NewInt(43))
+ },
+ valid: false,
+ },
+ {
+ name: "Non-Zero R",
+ modifier: func(tx *RPCTransaction) {
+ tx.R = (*hexutil.Big)(big.NewInt(43))
+ },
+ valid: false,
+ },
+ {
+ name: "Non-Zero S",
+ modifier: func(tx *RPCTransaction) {
+ tx.S = (*hexutil.Big)(big.NewInt(43))
+ },
+ valid: false,
+ },
+ {
+ name: "Non-nil deposit receipt version",
+ modifier: func(tx *RPCTransaction) {
+ tx.DepositReceiptVersion = &version
+ },
+ valid: true,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ tx := types.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 +235,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 +701,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
}
@@ -595,6 +754,12 @@ panic("implement me")
}
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")
}
@@ -804,7 +969,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
{
@@ -1084,7 +1249,7 @@ "to": "0x0000000000000000000000000000000000000011",
"transactionIndex": "0x1",
"value": "0x6f",
"type": "0x0",
- "chainId": "0x7fffffffffffffee",
+ "chainId": "0x1",
"v": "0x0",
"r": "0x0",
"s": "0x0"
@@ -1122,7 +1287,7 @@ "to": "0x0000000000000000000000000000000000000011",
"transactionIndex": "0x3",
"value": "0x6f",
"type": "0x0",
- "chainId": "0x7fffffffffffffee",
+ "chainId": "0x1",
"v": "0x0",
"r": "0x0",
"s": "0x0"
@@ -1135,7 +1300,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 c415d73e7ef2396556eeed0e4a81da016c4512c8..b8fd99b3e1633bdd7faea7191486d8854c88712b 100644
--- go-ethereum/light/odr_test.go
+++ op-geth/light/odr_test.go
@@ -214,7 +214,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..abb72bbd351f4c0a99ea8b78deac222a816a9ccc
--- /dev/null
+++ op-geth/params/superchain_test.go
@@ -0,0 +1,172 @@
+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,
+ },
+ {
+ A: HumanProtocolVersion{0, 4, 0, 0, 0, [8]byte{}},
+ B: HumanProtocolVersion{0, 4, 0, 0, 1, [8]byte{}},
+ Cmp: AheadMajor,
+ },
+ {
+ A: HumanProtocolVersion{0, 4, 1, 0, 0, [8]byte{}},
+ B: HumanProtocolVersion{0, 4, 1, 0, 1, [8]byte{}},
+ Cmp: AheadMinor,
+ },
+ {
+ A: HumanProtocolVersion{0, 4, 0, 1, 0, [8]byte{}},
+ B: HumanProtocolVersion{0, 4, 0, 1, 1, [8]byte{}},
+ Cmp: AheadPatch,
+ },
+ {
+ A: HumanProtocolVersion{0, 4, 0, 0, 2, [8]byte{}},
+ B: HumanProtocolVersion{0, 4, 0, 0, 1, [8]byte{}},
+ Cmp: AheadPrerelease,
+ },
+ {
+ A: HumanProtocolVersion{0, 4, 1, 0, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 4, 0, 0, 0, [8]byte{}},
+ Cmp: AheadPatch,
+ },
+ {
+ A: HumanProtocolVersion{0, 4, 0, 1, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 4, 0, 0, 0, [8]byte{}},
+ Cmp: AheadPrerelease,
+ },
+ {
+ A: HumanProtocolVersion{0, 4, 1, 1, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 4, 0, 0, 0, [8]byte{}},
+ Cmp: AheadMinor,
+ },
+ {
+ A: HumanProtocolVersion{0, 4, 0, 2, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 4, 0, 0, 0, [8]byte{}},
+ Cmp: AheadPatch,
+ },
+ {
+ A: HumanProtocolVersion{0, 5, 0, 1, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 4, 0, 0, 0, [8]byte{}},
+ Cmp: AheadMajor,
+ },
+ {
+ A: HumanProtocolVersion{0, 1, 0, 0, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 0, 9, 0, 0, [8]byte{}},
+ Cmp: AheadMinor,
+ },
+ {
+ A: HumanProtocolVersion{0, 0, 1, 0, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 0, 0, 9, 0, [8]byte{}},
+ Cmp: AheadPatch,
+ },
+ {
+ A: HumanProtocolVersion{0, 1, ^uint32(0), 0, 1, [8]byte{}},
+ B: HumanProtocolVersion{0, 0, 1, 0, 0, [8]byte{}},
+ Cmp: InvalidVersion,
+ },
+ }
+ for i, tc := range testCases {
+ tc := tc // not a parallel sub-test, but better than a flake
+ 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/rpc/http.go op-geth/rpc/http.go
index 741fa1c0eb4f63ed864dc406685d91b9707dbfe3..19e44a2e8cd2f433e9e939b953a97c18cf1e1806 100644
--- go-ethereum/rpc/http.go
+++ op-geth/rpc/http.go
@@ -33,7 +33,7 @@ "time"
)
const (
- maxRequestContentLength = 1024 * 1024 * 5
+ maxRequestContentLength = 1024 * 1024 * 32
contentType = "application/json"
)
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 745a3c6b287ad1c9827c81784b030d8595e0adc8..39864b77b8f963d4e869e8d409c72aae7a776a65 100644
--- go-ethereum/tests/state_test_util.go
+++ op-geth/tests/state_test_util.go
@@ -271,7 +271,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