diff --git a/core/tx_pool.go b/core/tx_pool.go index bb24b7d05..a3d4a6062 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -18,6 +18,7 @@ package core import ( "errors" + "fmt" "math" "math/big" "sort" @@ -619,6 +620,10 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { if uint64(tx.Size()) > txMaxSize { return ErrOversizedData } + // Check whether the init code size has been exceeded. + if pool.shanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { + return fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) + } // Transactions can't be negative. This may never happen using RLP decoded // transactions but may occur if you create a transaction using the RPC. if tx.Value().Sign() < 0 { diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index e7e98339d..4112361b3 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -64,9 +64,12 @@ var ( // JumpTable contains the EVM opcodes supported at a given fork. type JumpTable [256]*operation +// newShanghaiInstructionSet returns the frontier, homestead, byzantium, +// contantinople, istanbul, petersburg, berlin, london and shanghai instructions. func newShanghaiInstructionSet() JumpTable { instructionSet := newLondonInstructionSet() - enable3860(&instructionSet) + enable3855(&instructionSet) // PUSH0 instruction https://eips.ethereum.org/EIPS/eip-3855 + enable3860(&instructionSet) // Limit and meter initcode https://eips.ethereum.org/EIPS/eip-3860 return instructionSet } diff --git a/eth/tracers/api_blocktrace.go b/eth/tracers/api_blocktrace.go index 851bf9549..030cabe01 100644 --- a/eth/tracers/api_blocktrace.go +++ b/eth/tracers/api_blocktrace.go @@ -290,6 +290,8 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc // merge required proof data proofAccounts := tracer.UpdatedAccounts() + proofAccounts[vmenv.FeeRecipient()] = struct{}{} + proofAccounts[rcfg.L1GasPriceOracleAddress] = struct{}{} for addr := range proofAccounts { addrStr := addr.String() @@ -314,6 +316,12 @@ func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, bloc } proofStorages := tracer.UpdatedStorages() + proofStorages[rcfg.L1GasPriceOracleAddress] = vm.Storage( + map[common.Hash]common.Hash{ + rcfg.L1BaseFeeSlot: {}, // notice we do not need the right value here + rcfg.OverheadSlot: {}, + rcfg.ScalarSlot: {}, + }) for addr, keys := range proofStorages { env.sMu.Lock() trie, err := state.GetStorageTrieForProof(addr) @@ -404,6 +412,35 @@ func (api *API) fillBlockTrace(env *traceEnv, block *types.Block) (*types.BlockT txs[i] = types.NewTransactionData(tx, block.NumberU64(), api.backend.ChainConfig()) } + if _, existed := env.Proofs[rcfg.L2MessageQueueAddress.String()]; !existed { + if proof, err := statedb.GetProof(rcfg.L2MessageQueueAddress); err != nil { + log.Error("Proof for L2MessageQueueAddress not available", "error", err) + } else { + wrappedProof := make([]hexutil.Bytes, len(proof)) + for i, bt := range proof { + wrappedProof[i] = bt + } + env.Proofs[rcfg.L2MessageQueueAddress.String()] = wrappedProof + } + } + + if _, existed := env.StorageProofs[rcfg.L2MessageQueueAddress.String()]; !existed { + env.StorageProofs[rcfg.L2MessageQueueAddress.String()] = make(map[string][]hexutil.Bytes) + } + if _, existed := env.StorageProofs[rcfg.L2MessageQueueAddress.String()][rcfg.WithdrawTrieRootSlot.String()]; !existed { + if trie, err := statedb.GetStorageTrieForProof(rcfg.L2MessageQueueAddress); err != nil { + log.Error("Storage proof for WithdrawTrieRootSlot not available", "error", err) + } else if proof, _ := statedb.GetSecureTrieProof(trie, rcfg.WithdrawTrieRootSlot); err != nil { + log.Error("Get storage proof for WithdrawTrieRootSlot failed", "error", err) + } else { + wrappedProof := make([]hexutil.Bytes, len(proof)) + for i, bt := range proof { + wrappedProof[i] = bt + } + env.StorageProofs[rcfg.L2MessageQueueAddress.String()][rcfg.WithdrawTrieRootSlot.String()] = wrappedProof + } + } + blockTrace := &types.BlockTrace{ ChainID: api.backend.ChainConfig().ChainID.Uint64(), Version: params.ArchiveVersion(params.CommitHash), diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 574ec6619..bc310f09e 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1679,7 +1679,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha "logs": receipt.Logs, "logsBloom": receipt.Bloom, "type": hexutil.Uint(tx.Type()), - "l1Fee": hexutil.Uint64(receipt.L1Fee.Uint64()), + "l1Fee": (*hexutil.Big)(receipt.L1Fee), } // Assign the effective gas price paid if !s.b.ChainConfig().IsLondon(bigblock) { diff --git a/params/version.go b/params/version.go index 36583679e..1e971462f 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ import ( const ( VersionMajor = 3 // Major version component of the current release VersionMinor = 2 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release + VersionPatch = 4 // Patch version component of the current release VersionMeta = "alpha" // Version metadata to append to the version string ) diff --git a/trie/zk_trie_proof_test.go b/trie/zk_trie_proof_test.go index 0109e9be8..9246a7a99 100644 --- a/trie/zk_trie_proof_test.go +++ b/trie/zk_trie_proof_test.go @@ -244,11 +244,12 @@ func TestProofWithDeletion(t *testing.T) { // notice the sibling of key `k*32`` is just the leaf of key `m*32` assert.Equal(t, siblings[0][l-33:l-1], nd) - // no effect + // Marking a key that is currently not hit (but terminated by an empty node) + // also causes it to be added to the deletion proof proofTracer.MarkDeletion(s_key2.Bytes()) siblings, err = proofTracer.GetDeletionProofs() assert.NoError(t, err) - assert.Equal(t, 1, len(siblings)) + assert.Equal(t, 2, len(siblings)) key3 := bytes.Repeat([]byte("x"), 32) err = mt.UpdateWord( diff --git a/trie/zktrie_deletionproof.go b/trie/zktrie_deletionproof.go index ebb8419e7..8547c1eda 100644 --- a/trie/zktrie_deletionproof.go +++ b/trie/zktrie_deletionproof.go @@ -28,6 +28,7 @@ type ProofTracer struct { *ZkTrie deletionTracer map[zkt.Hash]struct{} rawPaths map[string][]*zktrie.Node + emptyTermPaths map[string][]*zktrie.Node } // NewProofTracer create a proof tracer object @@ -37,6 +38,7 @@ func (t *ZkTrie) NewProofTracer() *ProofTracer { // always consider 0 is "deleted" deletionTracer: map[zkt.Hash]struct{}{zkt.HashZero: {}}, rawPaths: make(map[string][]*zktrie.Node), + emptyTermPaths: make(map[string][]*zktrie.Node), } } @@ -112,9 +114,13 @@ func (t *ProofTracer) GetDeletionProofs() ([][]byte, error) { // MarkDeletion mark a key has been involved into deletion func (t *ProofTracer) MarkDeletion(key []byte) { - if path, existed := t.rawPaths[string(key)]; existed { + if path, existed := t.emptyTermPaths[string(key)]; existed { + // copy empty node terminated path for final scanning + t.rawPaths[string(key)] = path + } else if path, existed = t.rawPaths[string(key)]; existed { // sanity check leafNode := path[len(path)-1] + if leafNode.Type != zktrie.NodeTypeLeaf { panic("all path recorded in proofTrace should be ended with leafNode") } @@ -143,6 +149,11 @@ func (t *ProofTracer) Prove(key []byte, fromLevel uint, proofDb ethdb.KeyValueWr } } else if n.Type == zktrie.NodeTypeParent { mptPath = append(mptPath, n) + } else if n.Type == zktrie.NodeTypeEmpty { + // empty node is considered as "unhit" but it should be also being added + // into a temporary slot for possibly being marked as deletion later + mptPath = append(mptPath, n) + t.emptyTermPaths[string(key)] = mptPath } return proofDb.Put(nodeHash[:], n.Value())