diff --git a/.golangci.yml b/.golangci.yml index e355e6f9d1..b63251055b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,9 +3,6 @@ run: timeout: 20m tests: true - # default is true. Enables skipping of directories: - # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ - skip-dirs-use-default: true linters: disable-all: true @@ -54,6 +51,9 @@ linters-settings: exclude: [""] issues: + # default is true. Enables skipping of directories: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + exclude-dirs-use-default: true exclude-files: - core/genesis_alloc.go exclude-rules: diff --git a/README.md b/README.md index 27842008aa..45b80e86a6 100644 --- a/README.md +++ b/README.md @@ -54,14 +54,14 @@ on how you can run your own `geth` instance. Minimum: -* CPU with 2+ cores -* 4GB RAM +* CPU with 4+ cores +* 8GB RAM * 1TB free storage space to sync the Mainnet * 8 MBit/sec download Internet service Recommended: -* Fast CPU with 4+ cores +* Fast CPU with 8+ cores * 16GB+ RAM * High-performance SSD with at least 1TB of free space * 25+ MBit/sec download Internet service @@ -138,8 +138,6 @@ export your existing configuration: $ geth --your-favourite-flags dumpconfig ``` -*Note: This works only with `geth` v1.6.0 and above.* - #### Docker quick start One of the quickest ways to get Ethereum up and running on your machine is by using @@ -187,7 +185,6 @@ HTTP based JSON-RPC API options: * `--ws.api` API's offered over the WS-RPC interface (default: `eth,net,web3`) * `--ws.origins` Origins from which to accept WebSocket requests * `--ipcdisable` Disable the IPC-RPC server - * `--ipcapi` API's offered over the IPC-RPC interface (default: `admin,debug,eth,miner,net,personal,txpool,web3`) * `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it) You'll need to use your own programming environments' capabilities (libraries, tools, etc) to @@ -206,118 +203,14 @@ APIs!** Maintaining your own private network is more involved as a lot of configurations taken for granted in the official networks need to be manually set up. -#### Defining the private genesis state +Unfortunately since [the Merge](https://ethereum.org/en/roadmap/merge/) it is no longer possible +to easily set up a network of geth nodes without also setting up a corresponding beacon chain. -First, you'll need to create the genesis state of your networks, which all nodes need to be -aware of and agree upon. This consists of a small JSON file (e.g. call it `genesis.json`): +There are three different solutions depending on your use case: -```json -{ - "config": { - "chainId": , - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "londonBlock": 0 - }, - "alloc": {}, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x20000", - "extraData": "", - "gasLimit": "0x2fefd8", - "nonce": "0x0000000000000042", - "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x00" -} -``` - -The above fields should be fine for most purposes, although we'd recommend changing -the `nonce` to some random value so you prevent unknown remote nodes from being able -to connect to you. If you'd like to pre-fund some accounts for easier testing, create -the accounts and populate the `alloc` field with their addresses. - -```json -"alloc": { - "0x0000000000000000000000000000000000000001": { - "balance": "111111111" - }, - "0x0000000000000000000000000000000000000002": { - "balance": "222222222" - } -} -``` - -With the genesis state defined in the above JSON file, you'll need to initialize **every** -`geth` node with it prior to starting it up to ensure all blockchain parameters are correctly -set: - -```shell -$ geth init path/to/genesis.json -``` - -#### Creating the rendezvous point - -With all nodes that you want to run initialized to the desired genesis state, you'll need to -start a bootstrap node that others can use to find each other in your network and/or over -the internet. The clean way is to configure and run a dedicated bootnode: - -```shell -# Use the devp2p tool to create a node file. -# The devp2p tool is also part of the 'alltools' distribution bundle. -$ devp2p key generate node1.key -# file node1.key is created. -$ devp2p key to-enr -ip 10.2.3.4 -udp 30303 -tcp 30303 node1.key -# Prints the ENR for use in --bootnode flag of other nodes. -# Note this method requires knowing the IP/ports ahead of time. -$ geth --nodekey=node1.key -``` - -With the bootnode online, it will display an [`enode` URL](https://ethereum.org/en/developers/docs/networking-layer/network-addresses/#enode) -that other nodes can use to connect to it and exchange peer information. Make sure to -replace the displayed IP address information (most probably `[::]`) with your externally -accessible IP to get the actual `enode` URL. - -*Note: You could previously use the `bootnode` utility to start a stripped down version of geth. This is not possible anymore.* - -#### Starting up your member nodes - -With the bootnode operational and externally reachable (you can try -`telnet ` to ensure it's indeed reachable), start every subsequent `geth` -node pointed to the bootnode for peer discovery via the `--bootnodes` flag. It will -probably also be desirable to keep the data directory of your private network separated, so -do also specify a custom `--datadir` flag. - -```shell -$ geth --datadir=path/to/custom/data/folder --bootnodes= -``` - -*Note: Since your network will be completely cut off from the main and test networks, you'll -also need to configure a miner to process transactions and create new blocks for you.* - -#### Running a private miner - - -In a private network setting a single CPU miner instance is more than enough for -practical purposes as it can produce a stable stream of blocks at the correct intervals -without needing heavy resources (consider running on a single thread, no need for multiple -ones either). To start a `geth` instance for mining, run it with all your usual flags, extended -by: - -```shell -$ geth --mine --miner.threads=1 --miner.etherbase=0x0000000000000000000000000000000000000000 -``` - -Which will start mining blocks and transactions on a single CPU thread, crediting all -proceedings to the account specified by `--miner.etherbase`. You can further tune the mining -by changing the default gas limit blocks converge to (`--miner.targetgaslimit`) and the price -transactions are accepted at (`--miner.gasprice`). + * If you are looking for a simple way to test smart contracts from go in your CI, you can use the [Simulated Backend](https://geth.ethereum.org/docs/developers/dapp-developer/native-bindings#blockchain-simulator). + * If you want a convenient single node environment for testing, you can use our [Dev Mode](https://geth.ethereum.org/docs/developers/dapp-developer/dev-mode). + * If you are looking for a multiple node test network, you can set one up quite easily with [Kurtosis](https://geth.ethereum.org/docs/fundamentals/kurtosis). ## Contribution diff --git a/accounts/accounts.go b/accounts/accounts.go index b995498a6d..7bd911577a 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -214,7 +214,9 @@ const ( // of starting any background processes such as automatic key derivation. WalletOpened - // WalletDropped + // WalletDropped is fired when a wallet is removed or disconnected, either via USB + // or due to a filesystem event in the keystore. This event indicates that the wallet + // is no longer available for operations. WalletDropped ) diff --git a/build/checksums.txt b/build/checksums.txt index b8061c9244..b0b7a73a3b 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -56,37 +56,37 @@ fc77c0531406d092c5356167e45c05a22d16bea84e3fa555e0f03af085c11763 go1.23.4.windo 8347c1aa4e1e67954d12830f88dbe44bd7ac0ec134bb472783dbfb5a3a8865d0 go1.23.4.windows-arm64.msi db69cae5006753c785345c3215ad941f8b6224e2f81fec471c42d6857bee0e6f go1.23.4.windows-arm64.zip -# version:golangci 1.61.0 +# version:golangci 1.63.4 # https://github.com/golangci/golangci-lint/releases/ -# https://github.com/golangci/golangci-lint/releases/download/v1.61.0/ -5c280ef3284f80c54fd90d73dc39ca276953949da1db03eb9dd0fbf868cc6e55 golangci-lint-1.61.0-darwin-amd64.tar.gz -544334890701e4e04a6e574bc010bea8945205c08c44cced73745a6378012d36 golangci-lint-1.61.0-darwin-arm64.tar.gz -e885a6f561092055930ebd298914d80e8fd2e10d2b1e9942836c2c6a115301fa golangci-lint-1.61.0-freebsd-386.tar.gz -b13f6a3f11f65e7ff66b734d7554df3bbae0f485768848424e7554ed289e19c2 golangci-lint-1.61.0-freebsd-amd64.tar.gz -cd8e7bbe5b8f33ed1597aa1cc588da96a3b9f22e1b9ae60d93511eae1a0ee8c5 golangci-lint-1.61.0-freebsd-armv6.tar.gz -7ade524dbd88bd250968f45e190af90e151fa5ee63dd6aa7f7bb90e8155db61d golangci-lint-1.61.0-freebsd-armv7.tar.gz -0fe3cd8a1ed8d9f54f48670a5af3df056d6040d94017057f0f4d65c930660ad9 golangci-lint-1.61.0-illumos-amd64.tar.gz -b463fc5053a612abd26393ebaff1d85d7d56058946f4f0f7bf25ed44ea899415 golangci-lint-1.61.0-linux-386.tar.gz -77cb0af99379d9a21d5dc8c38364d060e864a01bd2f3e30b5e8cc550c3a54111 golangci-lint-1.61.0-linux-amd64.tar.gz -af60ac05566d9351615cb31b4cc070185c25bf8cbd9b09c1873aa5ec6f3cc17e golangci-lint-1.61.0-linux-arm64.tar.gz -1f307f2fcc5d7d674062a967a0d83a7091e300529aa237ec6ad2b3dd14c897f5 golangci-lint-1.61.0-linux-armv6.tar.gz -3ad8cbaae75a547450844811300f99c4cd290277398e43d22b9eb1792d15af4c golangci-lint-1.61.0-linux-armv7.tar.gz -9be2ca67d961d7699079739cf6f7c8291c5183d57e34d1677de21ca19d0bd3ed golangci-lint-1.61.0-linux-loong64.tar.gz -90d005e1648115ebf0861b408eab9c936079a24763e883058b0a227cd3135d31 golangci-lint-1.61.0-linux-mips64.tar.gz -6d2ed4f49407115460b8c10ccfc40fd177e0887a48864a2879dd16e84ba2a48c golangci-lint-1.61.0-linux-mips64le.tar.gz -633089589af5a58b7430afb6eee107d4e9c99e8d91711ddc219eb13a07e8d3b8 golangci-lint-1.61.0-linux-ppc64le.tar.gz -4c1a097d9e0d1b4a8144dae6a1f5583a38d662f3bdc1498c4e954b6ed856be98 golangci-lint-1.61.0-linux-riscv64.tar.gz -30581d3c987d287b7064617f1a2694143e10dffc40bc25be6636006ee82d7e1c golangci-lint-1.61.0-linux-s390x.tar.gz -42530bf8100bd43c07f5efe6d92148ba6c5a7a712d510c6f24be85af6571d5eb golangci-lint-1.61.0-netbsd-386.tar.gz -b8bb07c920f6601edf718d5e82ec0784fd590b0992b42b6ec18da99f26013ed4 golangci-lint-1.61.0-netbsd-amd64.tar.gz -353a51527c60bd0776b0891b03f247c791986f625fca689d121972c624e54198 golangci-lint-1.61.0-netbsd-arm64.tar.gz -957a6272c3137910514225704c5dac0723b9c65eb7d9587366a997736e2d7580 golangci-lint-1.61.0-netbsd-armv6.tar.gz -a89eb28ff7f18f5cd52b914739360fa95cf2f643de4adeca46e26bec3a07e8d8 golangci-lint-1.61.0-netbsd-armv7.tar.gz -d8d74c43600b271393000717a4ed157d7a15bb85bab7db2efad9b63a694d4634 golangci-lint-1.61.0-windows-386.zip -e7bc2a81929a50f830244d6d2e657cce4f19a59aff49fa9000176ff34fda64ce golangci-lint-1.61.0-windows-amd64.zip -ed97c221596dd771e3dd9344872c140340bee2e819cd7a90afa1de752f1f2e0f golangci-lint-1.61.0-windows-arm64.zip -4b365233948b13d02d45928a5c390045e00945e919747b9887b5f260247541ae golangci-lint-1.61.0-windows-armv6.zip -595538fb64d152173959d28f6235227f9cd969a828e5af0c4e960d02af4ffd0e golangci-lint-1.61.0-windows-armv7.zip +# https://github.com/golangci/golangci-lint/releases/download/v1.63.4/ +878d017cc360e4fb19510d39852c8189852e3c48e7ce0337577df73507c97d68 golangci-lint-1.63.4-darwin-amd64.tar.gz +a2b630c2ac8466393f0ccbbede4462387b6c190697a70bc2298c6d2123f21bbf golangci-lint-1.63.4-darwin-arm64.tar.gz +8938b74aa92888e561a1c5a4c175110b92f84e7d24733703e6d9ebc39e9cd5f8 golangci-lint-1.63.4-freebsd-386.tar.gz +054903339d620df2e760b978920100986e3b03bcb058f669d520a71dac9c34ed golangci-lint-1.63.4-freebsd-amd64.tar.gz +a19d499f961a02608348e8b626537a88edfaab6e1b6534f1eff742b5d6d750e4 golangci-lint-1.63.4-freebsd-armv6.tar.gz +00d616f0fb275b780ce4d26604bdd7fdbfe6bc9c63acd5a0b31498e1f7511108 golangci-lint-1.63.4-freebsd-armv7.tar.gz +d453688e0eabded3c1a97ff5a2777bb0df5a18851efdaaaf6b472e3e5713c33e golangci-lint-1.63.4-illumos-amd64.tar.gz +6b1bec847fc9f347d53712d05606a49d55d0e3b5c1bacadfed2393f3503de0e9 golangci-lint-1.63.4-linux-386.tar.gz +01abb14a4df47b5ca585eff3c34b105023cba92ec34ff17212dbb83855581690 golangci-lint-1.63.4-linux-amd64.tar.gz +51f0c79d19a92353e0465fb30a4901a0644a975d34e6f399ad2eebc0160bbb24 golangci-lint-1.63.4-linux-arm64.tar.gz +8d0a43f41e8424fbae10f7aa2dc29999f98112817c6dba63d7dc76832940a673 golangci-lint-1.63.4-linux-armv6.tar.gz +1045a047b31e9302c9160c7b0f199f4ac1bd02a1b221a2d9521bd3507f0cf671 golangci-lint-1.63.4-linux-armv7.tar.gz +933fe10ab50ce3bb0806e15a4ae69fe20f0549abf91dea0161236000ca706e67 golangci-lint-1.63.4-linux-loong64.tar.gz +45798630cbad5642862766051199fa862ef3c33d569cab12f01cac4f68e2ddd5 golangci-lint-1.63.4-linux-mips64.tar.gz +86ae25335ddb24975d2c915c1af0c7fad70dce99d0b4614fa4bee392de714aa2 golangci-lint-1.63.4-linux-mips64le.tar.gz +33dabd11aaba4b602938da98bcf49aabab55019557e0115cdc3dbcc3009768fa golangci-lint-1.63.4-linux-ppc64le.tar.gz +4e7a81230a663bcdf30bba5689ce96040abc76994dbc2003dce32c8dca8c06f3 golangci-lint-1.63.4-linux-riscv64.tar.gz +21370b49c7c47f4d9b8f982c952f940b01e65710174c3b4dad7b6452d58f92ec golangci-lint-1.63.4-linux-s390x.tar.gz +255866a6464c7e11bb7edd8e6e6ad54f11e1f01b82ba9ca229698ac788cd9724 golangci-lint-1.63.4-netbsd-386.tar.gz +2798c040ac658bda97224f204795199c81ac97bb207b21c02b664aaed380d5d2 golangci-lint-1.63.4-netbsd-amd64.tar.gz +b910eecffd0064103837e7e1abe870deb8ade22331e6dffe319f430d49399c8e golangci-lint-1.63.4-netbsd-arm64.tar.gz +df2693ef37147b457c3e2089614537dd2ae2e18e53641e756a5b404f4c72d3fa golangci-lint-1.63.4-netbsd-armv6.tar.gz +a28a533366974bd7834c4516cd6075bff3419a508d1ed7aa63ae8182768b352e golangci-lint-1.63.4-netbsd-armv7.tar.gz +368932775fb5c620b324dabf018155f3365f5e33c5af5b26e9321db373f96eea golangci-lint-1.63.4-windows-386.zip +184d13c2b8f5441576bec2a0d8ba7b2d45445595cf796b879a73bcc98c39f8c1 golangci-lint-1.63.4-windows-amd64.zip +4fabf175d5b05ef0858ded49527948eebac50e9093814979fd84555a75fb80a6 golangci-lint-1.63.4-windows-arm64.zip +e92be3f3ff30d4a849fb4b9a4c8d56837dee45269cb405a3ecad52fa034c781b golangci-lint-1.63.4-windows-armv6.zip +c71d348653b8f7fbb109bb10c1a481722bc6b0b2b6e731b897f99ac869f7653e golangci-lint-1.63.4-windows-armv7.zip # This is the builder on PPA that will build Go itself (inception-y), don't modify! # diff --git a/cmd/clef/rules.md b/cmd/clef/rules.md index cc4a645596..3cd1bb52c6 100644 --- a/cmd/clef/rules.md +++ b/cmd/clef/rules.md @@ -7,7 +7,7 @@ It enables usecases like the following: * I want to auto-approve transactions with contract `CasinoDapp`, with up to `0.05 ether` in value to maximum `1 ether` per 24h period * I want to auto-approve transaction to contract `EthAlarmClock` with `data`=`0xdeadbeef`, if `value=0`, `gas < 44k` and `gasPrice < 40Gwei` -The two main features that are required for this to work well are; +The two main features that are required for this to work well are: 1. Rule Implementation: how to create, manage, and interpret rules in a flexible but secure manner 2. Credential management and credentials; how to provide auto-unlock without exposing keys unnecessarily. @@ -29,10 +29,10 @@ function asBig(str) { // Approve transactions to a certain contract if the value is below a certain limit function ApproveTx(req) { - var limit = big.Newint("0xb1a2bc2ec50000") + var limit = new BigNumber("0xb1a2bc2ec50000") var value = asBig(req.transaction.value); - if (req.transaction.to.toLowerCase() == "0xae967917c465db8578ca9024c205720b1a3651a9") && value.lt(limit)) { + if (req.transaction.to.toLowerCase() == "0xae967917c465db8578ca9024c205720b1a3651a9" && value.lt(limit)) { return "Approve" } // If we return "Reject", it will be rejected. diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index 2a70e0328f..222c66d4df 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -28,7 +28,6 @@ import ( "os" "path/filepath" "slices" - "sort" "strings" "github.com/ethereum/go-ethereum/common" @@ -41,6 +40,7 @@ import ( "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/exp/maps" ) // Chain is a lightweight blockchain-like store which can read a hivechain @@ -166,11 +166,8 @@ func (c *Chain) RootAt(height int) common.Hash { // GetSender returns the address associated with account at the index in the // pre-funded accounts list. func (c *Chain) GetSender(idx int) (common.Address, uint64) { - var accounts Addresses - for addr := range c.senders { - accounts = append(accounts, addr) - } - sort.Sort(accounts) + accounts := maps.Keys(c.senders) + slices.SortFunc(accounts, common.Address.Cmp) addr := accounts[idx] return addr, c.senders[addr].Nonce } @@ -260,22 +257,6 @@ func loadGenesis(genesisFile string) (core.Genesis, error) { return gen, nil } -type Addresses []common.Address - -func (a Addresses) Len() int { - return len(a) -} - -func (a Addresses) Less(i, j int) bool { - return bytes.Compare(a[i][:], a[j][:]) < 0 -} - -func (a Addresses) Swap(i, j int) { - tmp := a[i] - a[i] = a[j] - a[j] = tmp -} - func blocksFromFile(chainfile string, gblock *types.Block) ([]*types.Block, error) { // Load chain.rlp. fh, err := os.Open(chainfile) diff --git a/cmd/devp2p/internal/ethtest/protocol.go b/cmd/devp2p/internal/ethtest/protocol.go index f5f5f7e489..5c2f7d9e48 100644 --- a/cmd/devp2p/internal/ethtest/protocol.go +++ b/cmd/devp2p/internal/ethtest/protocol.go @@ -13,6 +13,7 @@ // // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . + package ethtest import ( diff --git a/cmd/devp2p/internal/v4test/discv4tests.go b/cmd/devp2p/internal/v4test/discv4tests.go index ca556851b4..963df6cdbc 100644 --- a/cmd/devp2p/internal/v4test/discv4tests.go +++ b/cmd/devp2p/internal/v4test/discv4tests.go @@ -194,7 +194,7 @@ func PingExtraData(t *utesting.T) { } } -// This test sends a PING packet with additional data and wrong 'from' field +// PingExtraDataWrongFrom sends a PING packet with additional data and wrong 'from' field // and expects a PONG response. func PingExtraDataWrongFrom(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) @@ -215,7 +215,7 @@ func PingExtraDataWrongFrom(t *utesting.T) { } } -// This test sends a PING packet with an expiration in the past. +// PingPastExpiration sends a PING packet with an expiration in the past. // The remote node should not respond. func PingPastExpiration(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) @@ -234,7 +234,7 @@ func PingPastExpiration(t *utesting.T) { } } -// This test sends an invalid packet. The remote node should not respond. +// WrongPacketType sends an invalid packet. The remote node should not respond. func WrongPacketType(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) defer te.close() @@ -252,7 +252,7 @@ func WrongPacketType(t *utesting.T) { } } -// This test verifies that the default behaviour of ignoring 'from' fields is unaffected by +// BondThenPingWithWrongFrom verifies that the default behaviour of ignoring 'from' fields is unaffected by // the bonding process. After bonding, it pings the target with a different from endpoint. func BondThenPingWithWrongFrom(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) @@ -289,7 +289,7 @@ waitForPong: } } -// This test just sends FINDNODE. The remote node should not reply +// FindnodeWithoutEndpointProof sends FINDNODE. The remote node should not reply // because the endpoint proof has not completed. func FindnodeWithoutEndpointProof(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) @@ -332,7 +332,7 @@ func BasicFindnode(t *utesting.T) { } } -// This test sends an unsolicited NEIGHBORS packet after the endpoint proof, then sends +// UnsolicitedNeighbors sends an unsolicited NEIGHBORS packet after the endpoint proof, then sends // FINDNODE to read the remote table. The remote node should not return the node contained // in the unsolicited NEIGHBORS packet. func UnsolicitedNeighbors(t *utesting.T) { @@ -373,7 +373,7 @@ func UnsolicitedNeighbors(t *utesting.T) { } } -// This test sends FINDNODE with an expiration timestamp in the past. +// FindnodePastExpiration sends FINDNODE with an expiration timestamp in the past. // The remote node should not respond. func FindnodePastExpiration(t *utesting.T) { te := newTestEnv(Remote, Listen1, Listen2) @@ -426,7 +426,7 @@ func bond(t *utesting.T, te *testenv) { } } -// This test attempts to perform a traffic amplification attack against a +// FindnodeAmplificationInvalidPongHash attempts to perform a traffic amplification attack against a // 'victim' endpoint using FINDNODE. In this attack scenario, the attacker // attempts to complete the endpoint proof non-interactively by sending a PONG // with mismatching reply token from the 'victim' endpoint. The attack works if @@ -478,7 +478,7 @@ func FindnodeAmplificationInvalidPongHash(t *utesting.T) { } } -// This test attempts to perform a traffic amplification attack using FINDNODE. +// FindnodeAmplificationWrongIP attempts to perform a traffic amplification attack using FINDNODE. // The attack works if the remote node does not verify the IP address of FINDNODE // against the endpoint verification proof done by PING/PONG. func FindnodeAmplificationWrongIP(t *utesting.T) { diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 48564eb5eb..bbadb1cc19 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -230,11 +230,10 @@ func initGenesis(ctx *cli.Context) error { triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle()) defer triedb.Close() - _, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) + _, hash, _, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) if err != nil { utils.Fatalf("Failed to write genesis block: %v", err) } - log.Info("Successfully wrote genesis state", "database", "chaindata", "hash", hash) return nil diff --git a/cmd/utils/history_test.go b/cmd/utils/history_test.go index 1074a358ec..07cf71234e 100644 --- a/cmd/utils/history_test.go +++ b/cmd/utils/history_test.go @@ -170,7 +170,7 @@ func TestHistoryImportAndExport(t *testing.T) { db2.Close() }) - genesis.MustCommit(db2, triedb.NewDatabase(db, triedb.HashDefaults)) + genesis.MustCommit(db2, triedb.NewDatabase(db2, triedb.HashDefaults)) imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil) if err != nil { t.Fatalf("unable to initialize chain: %v", err) diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 6c46d1db4f..a83d6ca736 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -467,7 +467,6 @@ func (tt *cliqueTest) run(t *testing.T) { for j := 0; j < len(batches)-1; j++ { if k, err := chain.InsertChain(batches[j]); err != nil { t.Fatalf("failed to import batch %d, block %d: %v", j, k, err) - break } } if _, err = chain.InsertChain(batches[len(batches)-1]); err != tt.failure { diff --git a/core/blockchain.go b/core/blockchain.go index 0fe4812626..b056b7ed0c 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -269,14 +269,19 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis cacheConfig = defaultCacheConfig } // Open trie database with provided config - triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(genesis != nil && genesis.IsVerkle())) + enableVerkle, err := EnableVerkleAtGenesis(db, genesis) + if err != nil { + return nil, err + } + triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(enableVerkle)) - // Setup the genesis block, commit the provided genesis specification - // to database if the genesis block is not present yet, or load the - // stored one from database. - chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides) - if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { - return nil, genesisErr + // Write the supplied genesis to the database if it has not been initialized + // yet. The corresponding chain config will be returned, either from the + // provided genesis or from the locally stored configuration if the genesis + // has already been initialized. + chainConfig, genesisHash, compatErr, err := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides) + if err != nil { + return nil, err } log.Info("") log.Info(strings.Repeat("-", 153)) @@ -303,7 +308,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis vmConfig: vmConfig, logger: vmConfig.Tracer, } - var err error bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped) if err != nil { return nil, err @@ -453,16 +457,15 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } // Rewind the chain in case of an incompatible config upgrade. - if compat, ok := genesisErr.(*params.ConfigCompatError); ok { - log.Warn("Rewinding chain to upgrade configuration", "err", compat) - if compat.RewindToTime > 0 { - bc.SetHeadWithTimestamp(compat.RewindToTime) + if compatErr != nil { + log.Warn("Rewinding chain to upgrade configuration", "err", compatErr) + if compatErr.RewindToTime > 0 { + bc.SetHeadWithTimestamp(compatErr.RewindToTime) } else { - bc.SetHead(compat.RewindToBlock) + bc.SetHead(compatErr.RewindToBlock) } rawdb.WriteChainConfig(db, genesisHash, chainConfig) } - // Start tx indexer if it's enabled. if txLookupLimit != nil { bc.txIndexer = newTxIndexer(*txLookupLimit, bc) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index fc0e3d8446..7805a7c6e8 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2535,7 +2535,7 @@ func testReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T, scheme strin } // Benchmarks large blocks with value transfers to non-existing accounts -func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) { +func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address) { var ( signer = types.HomesteadSigner{} testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -2598,10 +2598,7 @@ func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) { recipientFn := func(nonce uint64) common.Address { return common.BigToAddress(new(big.Int).SetUint64(1337 + nonce)) } - dataFn := func(nonce uint64) []byte { - return nil - } - benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) + benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn) } func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) { @@ -2615,10 +2612,7 @@ func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) { recipientFn := func(nonce uint64) common.Address { return common.BigToAddress(new(big.Int).SetUint64(1337)) } - dataFn := func(nonce uint64) []byte { - return nil - } - benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) + benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn) } func BenchmarkBlockChain_1x1000Executions(b *testing.B) { @@ -2632,10 +2626,7 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { recipientFn := func(nonce uint64) common.Address { return common.BigToAddress(new(big.Int).SetUint64(0xc0de)) } - dataFn := func(nonce uint64) []byte { - return nil - } - benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) + benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn) } // Tests that importing a some old blocks, where all blocks are before the @@ -4274,12 +4265,11 @@ func TestEIP7702(t *testing.T) { // 2. addr1:0xaaaa calls into addr2:0xbbbb // 3. addr2:0xbbbb writes to storage auth1, _ := types.SignSetCode(key1, types.SetCodeAuthorization{ - ChainID: gspec.Config.ChainID.Uint64(), + ChainID: *uint256.MustFromBig(gspec.Config.ChainID), Address: aa, Nonce: 1, }) auth2, _ := types.SignSetCode(key2, types.SetCodeAuthorization{ - ChainID: 0, Address: bb, Nonce: 0, }) @@ -4287,7 +4277,7 @@ func TestEIP7702(t *testing.T) { _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { b.SetCoinbase(aa) txdata := &types.SetCodeTx{ - ChainID: gspec.Config.ChainID.Uint64(), + ChainID: uint256.MustFromBig(gspec.Config.ChainID), Nonce: 0, To: addr1, Gas: 500000, diff --git a/core/genesis.go b/core/genesis.go index 85ef049ba6..02cdc74d86 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -127,8 +127,12 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { } // Create an ephemeral in-memory database for computing hash, // all the derived states will be discarded to not pollute disk. + emptyRoot := types.EmptyRootHash + if isVerkle { + emptyRoot = types.EmptyVerkleHash + } db := rawdb.NewMemoryDatabase() - statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb.NewDatabase(db, config), nil)) + statedb, err := state.New(emptyRoot, state.NewDatabase(triedb.NewDatabase(db, config), nil)) if err != nil { return common.Hash{}, err } @@ -148,7 +152,11 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { // flushAlloc is very similar with hash, but the main difference is all the // generated states will be persisted into the given database. func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, error) { - statedb, err := state.New(types.EmptyRootHash, state.NewDatabase(triedb, nil)) + emptyRoot := types.EmptyRootHash + if triedb.IsVerkle() { + emptyRoot = types.EmptyVerkleHash + } + statedb, err := state.New(emptyRoot, state.NewDatabase(triedb, nil)) if err != nil { return common.Hash{}, err } @@ -239,6 +247,24 @@ type ChainOverrides struct { OverrideVerkle *uint64 } +// apply applies the chain overrides on the supplied chain config. +func (o *ChainOverrides) apply(cfg *params.ChainConfig) (*params.ChainConfig, error) { + if o == nil || cfg == nil { + return cfg, nil + } + cpy := *cfg + if o.OverrideCancun != nil { + cpy.CancunTime = o.OverrideCancun + } + if o.OverrideVerkle != nil { + cpy.VerkleTime = o.OverrideVerkle + } + if err := cpy.CheckConfigForkOrder(); err != nil { + return nil, err + } + return &cpy, nil +} + // SetupGenesisBlock writes or updates the genesis block in db. // The block that will be used is: // @@ -250,109 +276,102 @@ type ChainOverrides struct { // The stored chain configuration will be updated if it is compatible (i.e. does not // specify a fork block below the local head block). In case of a conflict, the // error is a *params.ConfigCompatError and the new, unwritten config is returned. -// -// The returned chain configuration is never nil. -func SetupGenesisBlock(db ethdb.Database, triedb *triedb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { +func SetupGenesisBlock(db ethdb.Database, triedb *triedb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { return SetupGenesisBlockWithOverride(db, triedb, genesis, nil) } -func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, error) { +func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { + // Sanitize the supplied genesis, ensuring it has the associated chain + // config attached. if genesis != nil && genesis.Config == nil { - return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig + return nil, common.Hash{}, nil, errGenesisNoConfig } - applyOverrides := func(config *params.ChainConfig) { - if config != nil { - if overrides != nil && overrides.OverrideCancun != nil { - config.CancunTime = overrides.OverrideCancun - } - if overrides != nil && overrides.OverrideVerkle != nil { - config.VerkleTime = overrides.OverrideVerkle - } - } - } - // Just commit the new block if there is no stored genesis block. - stored := rawdb.ReadCanonicalHash(db, 0) - if (stored == common.Hash{}) { + // Commit the genesis if the database is empty + ghash := rawdb.ReadCanonicalHash(db, 0) + if (ghash == common.Hash{}) { if genesis == nil { log.Info("Writing default main-net genesis block") genesis = DefaultGenesisBlock() } else { log.Info("Writing custom genesis block") } + chainCfg, err := overrides.apply(genesis.Config) + if err != nil { + return nil, common.Hash{}, nil, err + } + genesis.Config = chainCfg - applyOverrides(genesis.Config) block, err := genesis.Commit(db, triedb) if err != nil { - return genesis.Config, common.Hash{}, err + return nil, common.Hash{}, nil, err } - return genesis.Config, block.Hash(), nil + return chainCfg, block.Hash(), nil, nil } - // The genesis block is present(perhaps in ancient database) while the - // state database is not initialized yet. It can happen that the node - // is initialized with an external ancient store. Commit genesis state - // in this case. - header := rawdb.ReadHeader(db, stored, 0) - if header.Root != types.EmptyRootHash && !triedb.Initialized(header.Root) { + // Commit the genesis if the genesis block exists in the ancient database + // but the key-value database is empty without initializing the genesis + // fields. This scenario can occur when the node is created from scratch + // with an existing ancient store. + storedCfg := rawdb.ReadChainConfig(db, ghash) + if storedCfg == nil { + // Ensure the stored genesis block matches with the given genesis. Private + // networks must explicitly specify the genesis in the config file, mainnet + // genesis will be used as default and the initialization will always fail. if genesis == nil { + log.Info("Writing default main-net genesis block") genesis = DefaultGenesisBlock() + } else { + log.Info("Writing custom genesis block") } - applyOverrides(genesis.Config) - // Ensure the stored genesis matches with the given one. - hash := genesis.ToBlock().Hash() - if hash != stored { - return genesis.Config, hash, &GenesisMismatchError{stored, hash} + chainCfg, err := overrides.apply(genesis.Config) + if err != nil { + return nil, common.Hash{}, nil, err + } + genesis.Config = chainCfg + + if hash := genesis.ToBlock().Hash(); hash != ghash { + return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash} } block, err := genesis.Commit(db, triedb) if err != nil { - return genesis.Config, hash, err + return nil, common.Hash{}, nil, err } - return genesis.Config, block.Hash(), nil + return chainCfg, block.Hash(), nil, nil } - // Check whether the genesis block is already written. + // The genesis block has already been committed previously. Verify that the + // provided genesis with chain overrides matches the existing one, and update + // the stored chain config if necessary. if genesis != nil { - applyOverrides(genesis.Config) - hash := genesis.ToBlock().Hash() - if hash != stored { - return genesis.Config, hash, &GenesisMismatchError{stored, hash} + chainCfg, err := overrides.apply(genesis.Config) + if err != nil { + return nil, common.Hash{}, nil, err + } + genesis.Config = chainCfg + + if hash := genesis.ToBlock().Hash(); hash != ghash { + return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash} } - } - // Get the existing chain configuration. - newcfg := genesis.configOrDefault(stored) - applyOverrides(newcfg) - if err := newcfg.CheckConfigForkOrder(); err != nil { - return newcfg, common.Hash{}, err - } - storedcfg := rawdb.ReadChainConfig(db, stored) - if storedcfg == nil { - log.Warn("Found genesis block without chain config") - rawdb.WriteChainConfig(db, stored, newcfg) - return newcfg, stored, nil - } - storedData, _ := json.Marshal(storedcfg) - // Special case: if a private network is being used (no genesis and also no - // mainnet hash in the database), we must not apply the `configOrDefault` - // chain config as that would be AllProtocolChanges (applying any new fork - // on top of an existing private network genesis block). In that case, only - // apply the overrides. - if genesis == nil && stored != params.MainnetGenesisHash { - newcfg = storedcfg - applyOverrides(newcfg) } // Check config compatibility and write the config. Compatibility errors // are returned to the caller unless we're already at block zero. head := rawdb.ReadHeadHeader(db) if head == nil { - return newcfg, stored, errors.New("missing head header") + return nil, common.Hash{}, nil, errors.New("missing head header") } - compatErr := storedcfg.CheckCompatible(newcfg, head.Number.Uint64(), head.Time) + newCfg := genesis.chainConfigOrDefault(ghash, storedCfg) + + // TODO(rjl493456442) better to define the comparator of chain config + // and short circuit if the chain config is not changed. + compatErr := storedCfg.CheckCompatible(newCfg, head.Number.Uint64(), head.Time) if compatErr != nil && ((head.Number.Uint64() != 0 && compatErr.RewindToBlock != 0) || (head.Time != 0 && compatErr.RewindToTime != 0)) { - return newcfg, stored, compatErr + return newCfg, ghash, compatErr, nil } - // Don't overwrite if the old is identical to the new - if newData, _ := json.Marshal(newcfg); !bytes.Equal(storedData, newData) { - rawdb.WriteChainConfig(db, stored, newcfg) + // Don't overwrite if the old is identical to the new. It's useful + // for the scenarios that database is opened in the read-only mode. + storedData, _ := json.Marshal(storedCfg) + if newData, _ := json.Marshal(newCfg); !bytes.Equal(storedData, newData) { + rawdb.WriteChainConfig(db, ghash, newCfg) } - return newcfg, stored, nil + return newCfg, ghash, nil, nil } // LoadChainConfig loads the stored chain config if it is already present in @@ -388,7 +407,10 @@ func LoadChainConfig(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, return params.MainnetChainConfig, nil } -func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { +// chainConfigOrDefault retrieves the attached chain configuration. If the genesis +// object is null, it returns the default chain configuration based on the given +// genesis hash, or the locally stored config if it's not a pre-defined network. +func (g *Genesis) chainConfigOrDefault(ghash common.Hash, stored *params.ChainConfig) *params.ChainConfig { switch { case g != nil: return g.Config @@ -399,14 +421,14 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { case ghash == params.SepoliaGenesisHash: return params.SepoliaChainConfig default: - return params.AllEthashProtocolChanges + return stored } } // IsVerkle indicates whether the state is already stored in a verkle // tree at genesis time. func (g *Genesis) IsVerkle() bool { - return g.Config.IsVerkle(new(big.Int).SetUint64(g.Number), g.Timestamp) + return g.Config.IsVerkleGenesis() } // ToBlock returns the genesis block according to genesis specification. @@ -486,7 +508,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo } config := g.Config if config == nil { - config = params.AllEthashProtocolChanges + return nil, errors.New("invalid genesis without chain config") } if err := config.CheckConfigForkOrder(); err != nil { return nil, err @@ -506,16 +528,17 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo if err != nil { return nil, err } - rawdb.WriteGenesisStateSpec(db, block.Hash(), blob) - rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) - rawdb.WriteBlock(db, block) - rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil) - rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) - rawdb.WriteHeadBlockHash(db, block.Hash()) - rawdb.WriteHeadFastBlockHash(db, block.Hash()) - rawdb.WriteHeadHeaderHash(db, block.Hash()) - rawdb.WriteChainConfig(db, block.Hash(), config) - return block, nil + batch := db.NewBatch() + rawdb.WriteGenesisStateSpec(batch, block.Hash(), blob) + rawdb.WriteTd(batch, block.Hash(), block.NumberU64(), block.Difficulty()) + rawdb.WriteBlock(batch, block) + rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), nil) + rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64()) + rawdb.WriteHeadBlockHash(batch, block.Hash()) + rawdb.WriteHeadFastBlockHash(batch, block.Hash()) + rawdb.WriteHeadHeaderHash(batch, block.Hash()) + rawdb.WriteChainConfig(batch, block.Hash(), config) + return block, batch.Write() } // MustCommit writes the genesis block and state to db, panicking on error. @@ -528,6 +551,29 @@ func (g *Genesis) MustCommit(db ethdb.Database, triedb *triedb.Database) *types. return block } +// EnableVerkleAtGenesis indicates whether the verkle fork should be activated +// at genesis. This is a temporary solution only for verkle devnet testing, where +// verkle fork is activated at genesis, and the configured activation date has +// already passed. +// +// In production networks (mainnet and public testnets), verkle activation always +// occurs after the genesis block, making this function irrelevant in those cases. +func EnableVerkleAtGenesis(db ethdb.Database, genesis *Genesis) (bool, error) { + if genesis != nil { + if genesis.Config == nil { + return false, errGenesisNoConfig + } + return genesis.Config.EnableVerkleAtGenesis, nil + } + if ghash := rawdb.ReadCanonicalHash(db, 0); ghash != (common.Hash{}) { + chainCfg := rawdb.ReadChainConfig(db, ghash) + if chainCfg != nil { + return chainCfg.EnableVerkleAtGenesis, nil + } + } + return false, nil +} + // DefaultGenesisBlock returns the Ethereum main net genesis block. func DefaultGenesisBlock() *Genesis { return &Genesis{ diff --git a/core/genesis_test.go b/core/genesis_test.go index 3ec87474e5..964ef928c7 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -54,23 +54,23 @@ func testSetupGenesis(t *testing.T, scheme string) { oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)} tests := []struct { - name string - fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error) - wantConfig *params.ChainConfig - wantHash common.Hash - wantErr error + name string + fn func(ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) + wantConfig *params.ChainConfig + wantHash common.Hash + wantErr error + wantCompactErr *params.ConfigCompatError }{ { name: "genesis without ChainConfig", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), new(Genesis)) }, - wantErr: errGenesisNoConfig, - wantConfig: params.AllEthashProtocolChanges, + wantErr: errGenesisNoConfig, }, { name: "no block in DB, genesis == nil", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil) }, wantHash: params.MainnetGenesisHash, @@ -78,7 +78,7 @@ func testSetupGenesis(t *testing.T, scheme string) { }, { name: "mainnet block in DB, genesis == nil", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { DefaultGenesisBlock().MustCommit(db, triedb.NewDatabase(db, newDbConfig(scheme))) return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil) }, @@ -87,7 +87,7 @@ func testSetupGenesis(t *testing.T, scheme string) { }, { name: "custom block in DB, genesis == nil", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { tdb := triedb.NewDatabase(db, newDbConfig(scheme)) customg.Commit(db, tdb) return SetupGenesisBlock(db, tdb, nil) @@ -97,18 +97,16 @@ func testSetupGenesis(t *testing.T, scheme string) { }, { name: "custom block in DB, genesis == sepolia", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { tdb := triedb.NewDatabase(db, newDbConfig(scheme)) customg.Commit(db, tdb) return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock()) }, - wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash}, - wantHash: params.SepoliaGenesisHash, - wantConfig: params.SepoliaChainConfig, + wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash}, }, { name: "compatible config in DB", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { tdb := triedb.NewDatabase(db, newDbConfig(scheme)) oldcustomg.Commit(db, tdb) return SetupGenesisBlock(db, tdb, &customg) @@ -118,7 +116,7 @@ func testSetupGenesis(t *testing.T, scheme string) { }, { name: "incompatible config in DB", - fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { + fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { // Commit the 'old' genesis block with Homestead transition at #2. // Advance to block #4, past the homestead transition block of customg. tdb := triedb.NewDatabase(db, newDbConfig(scheme)) @@ -135,7 +133,7 @@ func testSetupGenesis(t *testing.T, scheme string) { }, wantHash: customghash, wantConfig: customg.Config, - wantErr: ¶ms.ConfigCompatError{ + wantCompactErr: ¶ms.ConfigCompatError{ What: "Homestead fork block", StoredBlock: big.NewInt(2), NewBlock: big.NewInt(3), @@ -146,12 +144,16 @@ func testSetupGenesis(t *testing.T, scheme string) { for _, test := range tests { db := rawdb.NewMemoryDatabase() - config, hash, err := test.fn(db) + config, hash, compatErr, err := test.fn(db) // Check the return values. if !reflect.DeepEqual(err, test.wantErr) { spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true} t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr)) } + if !reflect.DeepEqual(compatErr, test.wantCompactErr) { + spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true} + t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(compatErr), spew.NewFormatter(test.wantCompactErr)) + } if !reflect.DeepEqual(config, test.wantConfig) { t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig) } @@ -279,6 +281,7 @@ func TestVerkleGenesisCommit(t *testing.T) { PragueTime: &verkleTime, VerkleTime: &verkleTime, TerminalTotalDifficulty: big.NewInt(0), + EnableVerkleAtGenesis: true, Ethash: nil, Clique: nil, } diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index d6370cee33..c5a72eff7e 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -87,6 +87,10 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui ) // Ensure the datadir is not a symbolic link if it exists. if info, err := os.Lstat(datadir); !os.IsNotExist(err) { + if info == nil { + log.Warn("Could not Lstat the database", "path", datadir) + return nil, errors.New("lstat failed") + } if info.Mode()&os.ModeSymlink != 0 { log.Warn("Symbolic link ancient database is not supported", "path", datadir) return nil, errSymlinkDatadir diff --git a/core/state/stateupdate.go b/core/state/stateupdate.go index a320b72f11..45de660ca5 100644 --- a/core/state/stateupdate.go +++ b/core/state/stateupdate.go @@ -20,7 +20,6 @@ import ( "maps" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/triedb" ) @@ -133,8 +132,8 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common } } return &stateUpdate{ - originRoot: types.TrieRootHash(originRoot), - root: types.TrieRootHash(root), + originRoot: originRoot, + root: root, accounts: accounts, accountsOrigin: accountsOrigin, storages: storages, diff --git a/core/state_transition.go b/core/state_transition.go index 93d72d16b7..b6203e6aae 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -470,7 +470,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { if msg.SetCodeAuthorizations != nil { for _, auth := range msg.SetCodeAuthorizations { // Note errors are ignored, we simply skip invalid authorizations here. - st.applyAuthorization(msg, &auth) + st.applyAuthorization(&auth) } } @@ -529,8 +529,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { // validateAuthorization validates an EIP-7702 authorization against the state. func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, err error) { - // Verify chain ID is 0 or equal to current chain ID. - if auth.ChainID != 0 && st.evm.ChainConfig().ChainID.Uint64() != auth.ChainID { + // Verify chain ID is null or equal to current chain ID. + if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 { return authority, ErrAuthorizationWrongChainID } // Limit nonce to 2^64-1 per EIP-2681. @@ -559,7 +559,7 @@ func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio } // applyAuthorization applies an EIP-7702 code delegation to the state. -func (st *stateTransition) applyAuthorization(msg *Message, auth *types.SetCodeAuthorization) error { +func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) error { authority, err := st.validateAuthorization(auth) if err != nil { return err diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 728f15069b..4343edfe86 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -293,7 +293,7 @@ const ( GasChangeCallLeftOverRefunded GasChangeReason = 7 // GasChangeCallContractCreation is the amount of gas that will be burned for a CREATE. GasChangeCallContractCreation GasChangeReason = 8 - // GasChangeContractCreation is the amount of gas that will be burned for a CREATE2. + // GasChangeCallContractCreation2 is the amount of gas that will be burned for a CREATE2. GasChangeCallContractCreation2 GasChangeReason = 9 // GasChangeCallCodeStorage is the amount of gas that will be charged for code storage. GasChangeCallCodeStorage GasChangeReason = 10 diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 02d339f99c..4ab14bbcc0 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1751,7 +1751,7 @@ func (p *BlobPool) Clear() { // The transaction addition may attempt to reserve the sender addr which // can't happen until Clear releases the reservation lock. Clear cannot // acquire the subpool lock until the transaction addition is completed. - for acct, _ := range p.index { + for acct := range p.index { p.reserve(acct, false) } p.lookup = newLookup() diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 70be7034ee..71cca7d1db 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -1986,7 +1986,7 @@ func (pool *LegacyPool) Clear() { senderAddr, _ := types.Sender(pool.signer, tx) pool.reserve(senderAddr, false) } - for localSender, _ := range pool.locals.accounts { + for localSender := range pool.locals.accounts { pool.reserve(localSender, false) } diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index 1377479da1..8af9624994 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -162,12 +162,12 @@ func TestTransactionZAttack(t *testing.T) { var ivpendingNum int pendingtxs, _ := pool.Content() for account, txs := range pendingtxs { - cur_balance := new(big.Int).Set(pool.currentState.GetBalance(account).ToBig()) + curBalance := new(big.Int).Set(pool.currentState.GetBalance(account).ToBig()) for _, tx := range txs { - if cur_balance.Cmp(tx.Value()) <= 0 { + if curBalance.Cmp(tx.Value()) <= 0 { ivpendingNum++ } else { - cur_balance.Sub(cur_balance, tx.Value()) + curBalance.Sub(curBalance, tx.Value()) } } } diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 39673d176d..abbde8cae3 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -1243,33 +1243,28 @@ func TestAllowedTxSize(t *testing.T) { account := crypto.PubkeyToAddress(key.PublicKey) testAddBalance(pool, account, big.NewInt(1000000000)) - // Compute maximal data size for transactions (lower bound). - // - // It is assumed the fields in the transaction (except of the data) are: - // - nonce <= 32 bytes - // - gasTip <= 32 bytes - // - gasLimit <= 32 bytes - // - recipient == 20 bytes - // - value <= 32 bytes - // - signature == 65 bytes - // All those fields are summed up to at most 213 bytes. - baseSize := uint64(213) - dataSize := txMaxSize - baseSize + // Find the maximum data length for the kind of transaction which will + // be generated in the pool.addRemoteSync calls below. + const largeDataLength = txMaxSize - 200 // enough to have a 5 bytes RLP encoding of the data length number + txWithLargeData := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, largeDataLength) + maxTxLengthWithoutData := txWithLargeData.Size() - largeDataLength // 103 bytes + maxTxDataLength := txMaxSize - maxTxLengthWithoutData // 131072 - 103 = 130953 bytes + // Try adding a transaction with maximal allowed size - tx := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, dataSize) + tx := pricedDataTransaction(0, pool.currentHead.Load().GasLimit, big.NewInt(1), key, maxTxDataLength) if err := pool.addRemoteSync(tx); err != nil { t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err) } // Try adding a transaction with random allowed size - if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentHead.Load().GasLimit, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil { + if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentHead.Load().GasLimit, big.NewInt(1), key, uint64(rand.Intn(int(maxTxDataLength+1))))); err != nil { t.Fatalf("failed to add transaction of random allowed size: %v", err) } - // Try adding a transaction of minimal not allowed size - if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, txMaxSize)); err == nil { + // Try adding a transaction above maximum size by one + if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, maxTxDataLength+1)); err == nil { t.Fatalf("expected rejection on slightly oversize transaction") } - // Try adding a transaction of random not allowed size - if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { + // Try adding a transaction above maximum size by more than one + if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentHead.Load().GasLimit, big.NewInt(1), key, maxTxDataLength+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { t.Fatalf("expected rejection on oversize transaction") } // Run some sanity checks on the pool internals diff --git a/core/types/deposit.go b/core/types/deposit.go index 3bba2c7aa4..8015f29ca7 100644 --- a/core/types/deposit.go +++ b/core/types/deposit.go @@ -24,7 +24,7 @@ const ( depositRequestSize = 192 ) -// UnpackIntoDeposit unpacks a serialized DepositEvent. +// DepositLogToRequest unpacks a serialized DepositEvent. func DepositLogToRequest(data []byte) ([]byte, error) { if len(data) != 576 { return nil, fmt.Errorf("deposit wrong length: want 576, have %d", len(data)) diff --git a/core/types/gen_authorization.go b/core/types/gen_authorization.go index be5467c50d..57069cbb1f 100644 --- a/core/types/gen_authorization.go +++ b/core/types/gen_authorization.go @@ -16,7 +16,7 @@ var _ = (*authorizationMarshaling)(nil) // MarshalJSON marshals as JSON. func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) { type SetCodeAuthorization struct { - ChainID hexutil.Uint64 `json:"chainId" gencodec:"required"` + ChainID hexutil.U256 `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"` V hexutil.Uint64 `json:"yParity" gencodec:"required"` @@ -24,7 +24,7 @@ func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) { S hexutil.U256 `json:"s" gencodec:"required"` } var enc SetCodeAuthorization - enc.ChainID = hexutil.Uint64(s.ChainID) + enc.ChainID = hexutil.U256(s.ChainID) enc.Address = s.Address enc.Nonce = hexutil.Uint64(s.Nonce) enc.V = hexutil.Uint64(s.V) @@ -36,7 +36,7 @@ func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error { type SetCodeAuthorization struct { - ChainID *hexutil.Uint64 `json:"chainId" gencodec:"required"` + ChainID *hexutil.U256 `json:"chainId" gencodec:"required"` Address *common.Address `json:"address" gencodec:"required"` Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` V *hexutil.Uint64 `json:"yParity" gencodec:"required"` @@ -50,7 +50,7 @@ func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error { if dec.ChainID == nil { return errors.New("missing required field 'chainId' for SetCodeAuthorization") } - s.ChainID = uint64(*dec.ChainID) + s.ChainID = uint256.Int(*dec.ChainID) if dec.Address == nil { return errors.New("missing required field 'address' for SetCodeAuthorization") } diff --git a/core/types/hashes.go b/core/types/hashes.go index 55506d63d0..05cfaeed74 100644 --- a/core/types/hashes.go +++ b/core/types/hashes.go @@ -19,7 +19,6 @@ package types import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" ) var ( @@ -47,13 +46,3 @@ var ( // EmptyVerkleHash is the known hash of an empty verkle trie. EmptyVerkleHash = common.Hash{} ) - -// TrieRootHash returns the hash itself if it's non-empty or the predefined -// emptyHash one instead. -func TrieRootHash(hash common.Hash) common.Hash { - if hash == (common.Hash{}) { - log.Error("Zero trie root hash!") - return EmptyRootHash - } - return hash -} diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index a6949414f3..c846ecd0c5 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -111,7 +111,7 @@ func TestFuzzDeriveSha(t *testing.T) { exp := types.DeriveSha(newDummy(i), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil))) got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { - printList(newDummy(seed)) + printList(t, newDummy(seed)) t.Fatalf("seed %d: got %x exp %x", seed, got, exp) } } @@ -192,15 +192,21 @@ func (d *dummyDerivableList) EncodeIndex(i int, w *bytes.Buffer) { io.CopyN(w, mrand.New(src), size) } -func printList(l types.DerivableList) { - fmt.Printf("list length: %d\n", l.Len()) - fmt.Printf("{\n") +func printList(t *testing.T, l types.DerivableList) { + var buf bytes.Buffer + _, _ = fmt.Fprintf(&buf, "list length: %d, ", l.Len()) + buf.WriteString("list: [") for i := 0; i < l.Len(); i++ { - var buf bytes.Buffer - l.EncodeIndex(i, &buf) - fmt.Printf("\"%#x\",\n", buf.Bytes()) + var itemBuf bytes.Buffer + l.EncodeIndex(i, &itemBuf) + if i == l.Len()-1 { + _, _ = fmt.Fprintf(&buf, "\"%#x\"", itemBuf.Bytes()) + } else { + _, _ = fmt.Fprintf(&buf, "\"%#x\",", itemBuf.Bytes()) + } } - fmt.Printf("},\n") + buf.WriteString("]") + t.Log(buf.String()) } type flatList []string diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 993d633c6f..1bbb97a3ec 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -155,7 +155,7 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { enc.Proofs = itx.Sidecar.Proofs } case *SetCodeTx: - enc.ChainID = (*hexutil.Big)(new(big.Int).SetUint64(itx.ChainID)) + enc.ChainID = (*hexutil.Big)(itx.ChainID.ToBig()) enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) enc.To = tx.To() enc.Gas = (*hexutil.Uint64)(&itx.Gas) @@ -353,7 +353,11 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } - itx.ChainID = uint256.MustFromBig((*big.Int)(dec.ChainID)) + var overflow bool + itx.ChainID, overflow = uint256.FromBig(dec.ChainID.ToInt()) + if overflow { + return errors.New("'chainId' value overflows uint256") + } if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } @@ -395,7 +399,6 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { itx.BlobHashes = dec.BlobVersionedHashes // signature R - var overflow bool if dec.R == nil { return errors.New("missing required field 'r' in transaction") } @@ -432,7 +435,11 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } - itx.ChainID = dec.ChainID.ToInt().Uint64() + var overflow bool + itx.ChainID, overflow = uint256.FromBig(dec.ChainID.ToInt()) + if overflow { + return errors.New("'chainId' value overflows uint256") + } if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } @@ -470,7 +477,6 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { itx.AuthList = dec.AuthorizationList // signature R - var overflow bool if dec.R == nil { return errors.New("missing required field 'r' in transaction") } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index d72643b4a8..4d70f37bd3 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -219,7 +219,7 @@ func (s pragueSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big } // Check that chain ID of tx matches the signer. We also accept ID zero here, // because it indicates that the chain ID was not specified in the tx. - if txdata.ChainID != 0 && new(big.Int).SetUint64(txdata.ChainID).Cmp(s.chainId) != 0 { + if txdata.ChainID != nil && txdata.ChainID.CmpBig(s.chainId) != 0 { return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) } R, S, _ = decodeSignature(sig) diff --git a/core/types/tx_blob.go b/core/types/tx_blob.go index ce1f287caa..88251ab957 100644 --- a/core/types/tx_blob.go +++ b/core/types/tx_blob.go @@ -47,9 +47,9 @@ type BlobTx struct { Sidecar *BlobTxSidecar `rlp:"-"` // Signature values - V *uint256.Int `json:"v" gencodec:"required"` - R *uint256.Int `json:"r" gencodec:"required"` - S *uint256.Int `json:"s" gencodec:"required"` + V *uint256.Int + R *uint256.Int + S *uint256.Int } // BlobTxSidecar contains the blobs of a blob transaction. diff --git a/core/types/tx_dynamic_fee.go b/core/types/tx_dynamic_fee.go index 8b5b514fde..981755cf70 100644 --- a/core/types/tx_dynamic_fee.go +++ b/core/types/tx_dynamic_fee.go @@ -37,9 +37,9 @@ type DynamicFeeTx struct { AccessList AccessList // Signature values - V *big.Int `json:"v" gencodec:"required"` - R *big.Int `json:"r" gencodec:"required"` - S *big.Int `json:"s" gencodec:"required"` + V *big.Int + R *big.Int + S *big.Int } // copy creates a deep copy of the transaction data and initializes all fields. diff --git a/core/types/tx_setcode.go b/core/types/tx_setcode.go index f14ae3bc9d..0fb5362c26 100644 --- a/core/types/tx_setcode.go +++ b/core/types/tx_setcode.go @@ -49,7 +49,7 @@ func AddressToDelegation(addr common.Address) []byte { // SetCodeTx implements the EIP-7702 transaction type which temporarily installs // the code at the signer's address. type SetCodeTx struct { - ChainID uint64 + ChainID *uint256.Int Nonce uint64 GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas GasFeeCap *uint256.Int // a.k.a. maxFeePerGas @@ -61,16 +61,16 @@ type SetCodeTx struct { AuthList []SetCodeAuthorization // Signature values - V *uint256.Int `json:"v" gencodec:"required"` - R *uint256.Int `json:"r" gencodec:"required"` - S *uint256.Int `json:"s" gencodec:"required"` + V *uint256.Int + R *uint256.Int + S *uint256.Int } //go:generate go run github.com/fjl/gencodec -type SetCodeAuthorization -field-override authorizationMarshaling -out gen_authorization.go // SetCodeAuthorization is an authorization from an account to deploy code at its address. type SetCodeAuthorization struct { - ChainID uint64 `json:"chainId" gencodec:"required"` + ChainID uint256.Int `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce uint64 `json:"nonce" gencodec:"required"` V uint8 `json:"yParity" gencodec:"required"` @@ -80,7 +80,7 @@ type SetCodeAuthorization struct { // field type overrides for gencodec type authorizationMarshaling struct { - ChainID hexutil.Uint64 + ChainID hexutil.U256 Nonce hexutil.Uint64 V hexutil.Uint64 R hexutil.U256 @@ -180,7 +180,7 @@ func (tx *SetCodeTx) copy() TxData { // accessors for innerTx. func (tx *SetCodeTx) txType() byte { return SetCodeTxType } -func (tx *SetCodeTx) chainID() *big.Int { return big.NewInt(int64(tx.ChainID)) } +func (tx *SetCodeTx) chainID() *big.Int { return tx.ChainID.ToBig() } func (tx *SetCodeTx) accessList() AccessList { return tx.AccessList } func (tx *SetCodeTx) data() []byte { return tx.Data } func (tx *SetCodeTx) gas() uint64 { return tx.Gas } @@ -207,7 +207,7 @@ func (tx *SetCodeTx) rawSignatureValues() (v, r, s *big.Int) { } func (tx *SetCodeTx) setSignatureValues(chainID, v, r, s *big.Int) { - tx.ChainID = chainID.Uint64() + tx.ChainID = uint256.MustFromBig(chainID) tx.V.SetFromBig(v) tx.R.SetFromBig(r) tx.S.SetFromBig(s) diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index 5088231207..02e94963c4 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -57,6 +57,7 @@ var ( ShanghaiTime: u64(0), VerkleTime: u64(0), TerminalTotalDifficulty: common.Big0, + EnableVerkleAtGenesis: true, // TODO uncomment when proof generation is merged // ProofInBlocks: true, } @@ -77,6 +78,7 @@ var ( ShanghaiTime: u64(0), VerkleTime: u64(0), TerminalTotalDifficulty: common.Big0, + EnableVerkleAtGenesis: true, } ) diff --git a/core/vm/eof_validation.go b/core/vm/eof_validation.go index fa534edce9..514f9fb58c 100644 --- a/core/vm/eof_validation.go +++ b/core/vm/eof_validation.go @@ -109,8 +109,8 @@ func validateCode(code []byte, section int, container *Container, jt *JumpTable, return nil, err } case RJUMPV: - max_size := int(code[i+1]) - length := max_size + 1 + maxSize := int(code[i+1]) + length := maxSize + 1 if len(code) <= i+length { return nil, fmt.Errorf("%w: jump table truncated, op %s, pos %d", errTruncatedImmediate, op, i) } @@ -120,7 +120,7 @@ func validateCode(code []byte, section int, container *Container, jt *JumpTable, return nil, err } } - i += 2 * max_size + i += 2 * maxSize case CALLF: arg, _ := parseUint16(code[i+1:]) if arg >= len(container.types) { diff --git a/core/vm/program/program.go b/core/vm/program/program.go index acc7fd25fc..3b00bbae6f 100644 --- a/core/vm/program/program.go +++ b/core/vm/program/program.go @@ -19,6 +19,7 @@ // - There are not package guarantees. We might iterate heavily on this package, and do backwards-incompatible changes without warning // - There are no quality-guarantees. These utilities may produce evm-code that is non-functional. YMMV. // - There are no stability-guarantees. The utility will `panic` if the inputs do not align / make sense. + package program import ( @@ -204,7 +205,7 @@ func (p *Program) StaticCall(gas *uint256.Int, address, inOffset, inSize, outOff return p.Op(vm.STATICCALL) } -// StaticCall is a convenience function to make a callcode. If 'gas' is nil, the opcode GAS will +// CallCode is a convenience function to make a callcode. If 'gas' is nil, the opcode GAS will // be used to provide all gas. func (p *Program) CallCode(gas *uint256.Int, address, value, inOffset, inSize, outOffset, outSize any) *Program { if outOffset == outSize && inSize == outSize && inOffset == outSize { @@ -263,7 +264,7 @@ func (p *Program) InputAddressToStack(inputOffset uint32) *Program { return p.Op(vm.AND) } -// MStore stores the provided data (into the memory area starting at memStart). +// Mstore stores the provided data (into the memory area starting at memStart). func (p *Program) Mstore(data []byte, memStart uint32) *Program { var idx = 0 // We need to store it in chunks of 32 bytes diff --git a/crypto/blake2b/blake2b.go b/crypto/blake2b/blake2b.go index 7ecaab8139..c24a88b99d 100644 --- a/crypto/blake2b/blake2b.go +++ b/crypto/blake2b/blake2b.go @@ -23,13 +23,13 @@ import ( ) const ( - // The blocksize of BLAKE2b in bytes. + // BlockSize the blocksize of BLAKE2b in bytes. BlockSize = 128 - // The hash size of BLAKE2b-512 in bytes. + // Size the hash size of BLAKE2b-512 in bytes. Size = 64 - // The hash size of BLAKE2b-384 in bytes. + // Size384 the hash size of BLAKE2b-384 in bytes. Size384 = 48 - // The hash size of BLAKE2b-256 in bytes. + // Size256 the hash size of BLAKE2b-256 in bytes. Size256 = 32 ) diff --git a/crypto/bn256/gnark/pairing.go b/crypto/bn256/gnark/pairing.go index 39e8a657f4..439ce0a39d 100644 --- a/crypto/bn256/gnark/pairing.go +++ b/crypto/bn256/gnark/pairing.go @@ -4,7 +4,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254" ) -// Computes the following relation: ∏ᵢ e(Pᵢ, Qᵢ) =? 1 +// PairingCheck computes the following relation: ∏ᵢ e(Pᵢ, Qᵢ) =? 1 // // To explain why gnark returns a (bool, error): // diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 1b6c9e97c1..76f934c72d 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -60,12 +60,12 @@ type PublicKey struct { Params *ECIESParams } -// Export an ECIES public key as an ECDSA public key. +// ExportECDSA exports an ECIES public key as an ECDSA public key. func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey { return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y} } -// Import an ECDSA public key as an ECIES public key. +// ImportECDSAPublic imports an ECDSA public key as an ECIES public key. func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey { return &PublicKey{ X: pub.X, @@ -81,20 +81,20 @@ type PrivateKey struct { D *big.Int } -// Export an ECIES private key as an ECDSA private key. +// ExportECDSA exports an ECIES private key as an ECDSA private key. func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey { pub := &prv.PublicKey pubECDSA := pub.ExportECDSA() return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D} } -// Import an ECDSA private key as an ECIES private key. +// ImportECDSA imports an ECDSA private key as an ECIES private key. func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey { pub := ImportECDSAPublic(&prv.PublicKey) return &PrivateKey{*pub, prv.D} } -// Generate an elliptic curve public / private keypair. If params is nil, +// GenerateKey generates an elliptic curve public / private keypair. If params is nil, // the recommended default parameters for the key will be chosen. func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) { sk, err := ecdsa.GenerateKey(curve, rand) @@ -119,7 +119,7 @@ func MaxSharedKeyLength(pub *PublicKey) int { return (pub.Curve.Params().BitSize + 7) / 8 } -// ECDH key agreement method used to establish secret keys for encryption. +// GenerateShared ECDH key agreement method used to establish secret keys for encryption. func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) { if prv.PublicKey.Curve != pub.Curve { return nil, ErrInvalidCurve diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index fe2e4d408a..4fd3df7428 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -120,16 +120,23 @@ func NewOracle(backend OracleBackend, params Config, startPrice *big.Int) *Oracl cache := lru.NewCache[cacheKey, processedFees](2048) headEvent := make(chan core.ChainHeadEvent, 1) - backend.SubscribeChainHeadEvent(headEvent) - go func() { - var lastHead common.Hash - for ev := range headEvent { - if ev.Header.ParentHash != lastHead { - cache.Purge() + sub := backend.SubscribeChainHeadEvent(headEvent) + if sub != nil { // the gasprice testBackend doesn't support subscribing to head events + go func() { + var lastHead common.Hash + for { + select { + case ev := <-headEvent: + if ev.Header.ParentHash != lastHead { + cache.Purge() + } + lastHead = ev.Header.Hash() + case <-sub.Err(): + return + } } - lastHead = ev.Header.Hash() - } - }() + }() + } return &Oracle{ backend: backend, diff --git a/eth/protocols/eth/dispatcher.go b/eth/protocols/eth/dispatcher.go index 146eec3f60..cba40596fc 100644 --- a/eth/protocols/eth/dispatcher.go +++ b/eth/protocols/eth/dispatcher.go @@ -174,6 +174,8 @@ func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) erro return <-res.Done // Response delivered, return any errors case <-res.Req.cancel: return nil // Request cancelled, silently discard response + case <-p.term: + return errDisconnected } } diff --git a/eth/sync_test.go b/eth/sync_test.go index 57eea73790..cad3a4732e 100644 --- a/eth/sync_test.go +++ b/eth/sync_test.go @@ -88,7 +88,7 @@ func testSnapSyncDisabling(t *testing.T, ethVer uint, snapVer uint) { if err := empty.handler.downloader.BeaconSync(ethconfig.SnapSync, full.chain.CurrentBlock(), nil); err != nil { t.Fatal("sync failed:", err) } - empty.handler.enableSyncedFeatures() + time.Sleep(time.Second * 5) // Downloader internally has to wait a timer (3s) to be expired before exiting if empty.handler.snapSync.Load() { t.Fatalf("snap sync not disabled after successful synchronisation") diff --git a/eth/tracers/dir.go b/eth/tracers/dir.go index 55bcb44d23..1cdfab5454 100644 --- a/eth/tracers/dir.go +++ b/eth/tracers/dir.go @@ -34,7 +34,7 @@ type Context struct { TxHash common.Hash // Hash of the transaction being traced (zero if dangling call) } -// The set of methods that must be exposed by a tracer +// Tracer represents the set of methods that must be exposed by a tracer // for it to be available through the RPC interface. // This involves a method to retrieve results and one to // stop tracing. diff --git a/eth/tracers/internal/util.go b/eth/tracers/internal/util.go index 347af43d51..cff6295566 100644 --- a/eth/tracers/internal/util.go +++ b/eth/tracers/internal/util.go @@ -13,6 +13,7 @@ // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . + package internal import ( diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 07de871f14..596ee97146 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -19,6 +19,7 @@ package logger import ( "encoding/hex" "encoding/json" + "errors" "fmt" "io" "maps" @@ -350,7 +351,7 @@ func (l *StructLogger) GetResult() (json.RawMessage, error) { returnData := common.CopyBytes(l.output) // Return data when successful and revert reason when reverted, otherwise empty. returnVal := fmt.Sprintf("%x", returnData) - if failed && l.err != vm.ErrExecutionReverted { + if failed && !errors.Is(l.err, vm.ErrExecutionReverted) { returnVal = "" } return json.Marshal(&ExecutionResult{ diff --git a/internal/era/builder.go b/internal/era/builder.go index 75782a08c2..33261555ba 100644 --- a/internal/era/builder.go +++ b/internal/era/builder.go @@ -12,7 +12,8 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . +// along with go-ethereum. If not, see . + package era import ( diff --git a/internal/ethapi/override/override_test.go b/internal/ethapi/override/override_test.go index 07ed6442b2..02a17c1331 100644 --- a/internal/ethapi/override/override_test.go +++ b/internal/ethapi/override/override_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/triedb" ) @@ -36,7 +37,7 @@ func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil func TestStateOverrideMovePrecompile(t *testing.T) { db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil) - statedb, err := state.New(common.Hash{}, db) + statedb, err := state.New(types.EmptyRootHash, db) if err != nil { t.Fatalf("failed to create statedb: %v", err) } diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 5bd0079a93..130eaa9724 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -45,7 +45,7 @@ const ( maxSimulateBlocks = 256 // timestampIncrement is the default increment between block timestamps. - timestampIncrement = 1 + timestampIncrement = 12 ) // simBlock is a batch of calls to be simulated sequentially. diff --git a/internal/ethapi/simulate_test.go b/internal/ethapi/simulate_test.go index 52ae40cad0..c747b76477 100644 --- a/internal/ethapi/simulate_test.go +++ b/internal/ethapi/simulate_test.go @@ -41,19 +41,19 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { baseNumber: 10, baseTimestamp: 50, blocks: []simBlock{{}, {}, {}}, - expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}}, + expected: []result{{number: 11, timestamp: 62}, {number: 12, timestamp: 74}, {number: 13, timestamp: 86}}, }, { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}}, - expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 70}, {number: 14, timestamp: 71}}, + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(80)}}, {}}, + expected: []result{{number: 11, timestamp: 62}, {number: 12, timestamp: 74}, {number: 13, timestamp: 80}, {number: 14, timestamp: 92}}, }, { baseNumber: 10, baseTimestamp: 50, blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(14)}}, {}}, - expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}, {number: 14, timestamp: 54}, {number: 15, timestamp: 55}}, + expected: []result{{number: 11, timestamp: 62}, {number: 12, timestamp: 74}, {number: 13, timestamp: 86}, {number: 14, timestamp: 98}, {number: 15, timestamp: 110}}, }, { baseNumber: 10, @@ -64,8 +64,8 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(52)}}}, - err: "block timestamps must be in order: 52 <= 52", + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(74)}}}, + err: "block timestamps must be in order: 74 <= 74", }, { baseNumber: 10, @@ -76,8 +76,8 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(61)}}}, - err: "block timestamps must be in order: 61 <= 61", + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(72)}}}, + err: "block timestamps must be in order: 72 <= 72", }, } { sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}} diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index a39a6666f4..175ac13a0f 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -503,7 +503,7 @@ func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction { } data = &types.SetCodeTx{ To: *args.To, - ChainID: args.ChainID.ToInt().Uint64(), + ChainID: uint256.MustFromBig(args.ChainID.ToInt()), Nonce: uint64(*args.Nonce), Gas: uint64(*args.Gas), GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)), diff --git a/internal/jsre/jsre.go b/internal/jsre/jsre.go index f6e21d2ef7..0dfeae8e1b 100644 --- a/internal/jsre/jsre.go +++ b/internal/jsre/jsre.go @@ -67,7 +67,19 @@ type evalReq struct { done chan bool } -// runtime must be stopped with Stop() after use and cannot be used after stopping +// New creates and initializes a new JavaScript runtime environment (JSRE). +// The runtime is configured with the provided assetPath for loading scripts and +// an output writer for logging or printing results. +// +// The returned JSRE must be stopped by calling Stop() after use to release resources. +// Attempting to use the JSRE after stopping it will result in undefined behavior. +// +// Parameters: +// - assetPath: The path to the directory containing script assets. +// - output: The writer used for logging or printing runtime output. +// +// Returns: +// - A pointer to the newly created JSRE instance. func New(assetPath string, output io.Writer) *JSRE { re := &JSRE{ assetPath: assetPath, @@ -251,8 +263,15 @@ func (re *JSRE) Stop(waitForCallbacks bool) { } } -// Exec(file) loads and runs the contents of a file -// if a relative path is given, the jsre's assetPath is used +// Exec loads and executes the contents of a JavaScript file. +// If a relative path is provided, the file is resolved relative to the JSRE's assetPath. +// The file is read, compiled, and executed in the JSRE's runtime environment. +// +// Parameters: +// - file: The path to the JavaScript file to execute. Can be an absolute path or relative to assetPath. +// +// Returns: +// - error: An error if the file cannot be read, compiled, or executed. func (re *JSRE) Exec(file string) error { code, err := os.ReadFile(common.AbsolutePath(re.assetPath, file)) if err != nil { diff --git a/internal/reexec/reexec.go b/internal/reexec/reexec.go index af8d347986..7dc6d9222e 100644 --- a/internal/reexec/reexec.go +++ b/internal/reexec/reexec.go @@ -7,6 +7,7 @@ // we require because of the forking limitations of using Go. Handlers can be // registered with a name and the argv 0 of the exec of the binary will be used // to find and execute custom init paths. + package reexec import ( diff --git a/metrics/exp/exp.go b/metrics/exp/exp.go index 5213979aa2..85cabca6b1 100644 --- a/metrics/exp/exp.go +++ b/metrics/exp/exp.go @@ -1,5 +1,6 @@ // Hook go-metrics into expvar // on any /debug/metrics request, load all vars from the registry into expvar, and execute regular expvar handler + package exp import ( diff --git a/metrics/gauge_info.go b/metrics/gauge_info.go index 2f78455649..1862ed55c5 100644 --- a/metrics/gauge_info.go +++ b/metrics/gauge_info.go @@ -39,7 +39,7 @@ func NewRegisteredGaugeInfo(name string, r Registry) *GaugeInfo { return c } -// gaugeInfoSnapshot is a read-only copy of another GaugeInfo. +// GaugeInfoSnapshot is a read-only copy of another GaugeInfo. type GaugeInfoSnapshot GaugeInfoValue // Value returns the value at the time the snapshot was taken. diff --git a/metrics/log.go b/metrics/log.go index 3380bbf9c4..08f3effb81 100644 --- a/metrics/log.go +++ b/metrics/log.go @@ -12,7 +12,7 @@ func Log(r Registry, freq time.Duration, l Logger) { LogScaled(r, freq, time.Nanosecond, l) } -// Output each metric in the given registry periodically using the given +// LogScaled outputs each metric in the given registry periodically using the given // logger. Print timings in `scale` units (eg time.Millisecond) rather than nanos. func LogScaled(r Registry, freq time.Duration, scale time.Duration, l Logger) { du := float64(scale) diff --git a/metrics/metrics.go b/metrics/metrics.go index a9d6623173..c4c43b7576 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -3,6 +3,7 @@ // // // Coda Hale's original work: + package metrics import ( diff --git a/metrics/resetting_timer.go b/metrics/resetting_timer.go index 1b3e87bc3d..66458bdb91 100644 --- a/metrics/resetting_timer.go +++ b/metrics/resetting_timer.go @@ -53,14 +53,14 @@ func (t *ResettingTimer) Snapshot() *ResettingTimerSnapshot { return snapshot } -// Record the duration of the execution of the given function. +// Time records the duration of the execution of the given function. func (t *ResettingTimer) Time(f func()) { ts := time.Now() f() t.Update(time.Since(ts)) } -// Record the duration of an event. +// Update records the duration of an event. func (t *ResettingTimer) Update(d time.Duration) { if !metricsEnabled { return @@ -71,7 +71,7 @@ func (t *ResettingTimer) Update(d time.Duration) { t.sum += int64(d) } -// Record the duration of an event that started at a time and ends now. +// UpdateSince records the duration of an event that started at a time and ends now. func (t *ResettingTimer) UpdateSince(ts time.Time) { t.Update(time.Since(ts)) } diff --git a/metrics/syslog.go b/metrics/syslog.go index 0bc4ed0da5..b265328f87 100644 --- a/metrics/syslog.go +++ b/metrics/syslog.go @@ -9,7 +9,7 @@ import ( "time" ) -// Output each metric in the given registry to syslog periodically using +// Syslog outputs each metric in the given registry to syslog periodically using // the given syslogger. func Syslog(r Registry, d time.Duration, w *syslog.Writer) { for range time.Tick(d) { diff --git a/miner/miner_test.go b/miner/miner_test.go index b92febdd12..04d84e2e1d 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -145,7 +145,7 @@ func createMiner(t *testing.T) *Miner { chainDB := rawdb.NewMemoryDatabase() triedb := triedb.NewDatabase(chainDB, nil) genesis := minerTestGenesisBlock(15, 11_500_000, common.HexToAddress("12345")) - chainConfig, _, err := core.SetupGenesisBlock(chainDB, triedb, genesis) + chainConfig, _, _, err := core.SetupGenesisBlock(chainDB, triedb, genesis) if err != nil { t.Fatalf("can't create new chain config: %v", err) } diff --git a/p2p/discover/v5wire/encoding_test.go b/p2p/discover/v5wire/encoding_test.go index c66a0da9d3..df97e40e89 100644 --- a/p2p/discover/v5wire/encoding_test.go +++ b/p2p/discover/v5wire/encoding_test.go @@ -249,20 +249,20 @@ func TestHandshake_BadHandshakeAttack(t *testing.T) { net.nodeA.expectDecode(t, WhoareyouPacket, whoareyou) // A -> B FINDNODE - incorrect_challenge := &Whoareyou{ + incorrectChallenge := &Whoareyou{ IDNonce: [16]byte{5, 6, 7, 8, 9, 6, 11, 12}, RecordSeq: challenge.RecordSeq, Node: challenge.Node, sent: challenge.sent, } - incorrect_findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, incorrect_challenge, &Findnode{}) - incorrect_findnode2 := make([]byte, len(incorrect_findnode)) - copy(incorrect_findnode2, incorrect_findnode) + incorrectFindNode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, incorrectChallenge, &Findnode{}) + incorrectFindNode2 := make([]byte, len(incorrectFindNode)) + copy(incorrectFindNode2, incorrectFindNode) - net.nodeB.expectDecodeErr(t, errInvalidNonceSig, incorrect_findnode) + net.nodeB.expectDecodeErr(t, errInvalidNonceSig, incorrectFindNode) // Reject new findnode as previous handshake is now deleted. - net.nodeB.expectDecodeErr(t, errUnexpectedHandshake, incorrect_findnode2) + net.nodeB.expectDecodeErr(t, errUnexpectedHandshake, incorrectFindNode2) // The findnode packet is again rejected even with a valid challenge this time. findnode, _ := net.nodeA.encodeWithChallenge(t, net.nodeB, challenge, &Findnode{}) diff --git a/params/config.go b/params/config.go index 9b3b92484a..f1e139608c 100644 --- a/params/config.go +++ b/params/config.go @@ -326,6 +326,19 @@ type ChainConfig struct { DepositContractAddress common.Address `json:"depositContractAddress,omitempty"` + // EnableVerkleAtGenesis is a flag that specifies whether the network uses + // the Verkle tree starting from the genesis block. If set to true, the + // genesis state will be committed using the Verkle tree, eliminating the + // need for any Verkle transition later. + // + // This is a temporary flag only for verkle devnet testing, where verkle is + // activated at genesis, and the configured activation date has already passed. + // + // In production networks (mainnet and public testnets), verkle activation + // always occurs after the genesis block, making this flag irrelevant in + // those cases. + EnableVerkleAtGenesis bool `json:"enableVerkleAtGenesis,omitempty"` + // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` @@ -525,6 +538,20 @@ func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) } +// IsVerkleGenesis checks whether the verkle fork is activated at the genesis block. +// +// Verkle mode is considered enabled if the verkle fork time is configured, +// regardless of whether the local time has surpassed the fork activation time. +// This is a temporary workaround for verkle devnet testing, where verkle is +// activated at genesis, and the configured activation date has already passed. +// +// In production networks (mainnet and public testnets), verkle activation +// always occurs after the genesis block, making this function irrelevant in +// those cases. +func (c *ChainConfig) IsVerkleGenesis() bool { + return c.EnableVerkleAtGenesis +} + // IsEIP4762 returns whether eip 4762 has been activated at given block. func (c *ChainConfig) IsEIP4762(num *big.Int, time uint64) bool { return c.IsVerkle(num, time) diff --git a/params/protocol_params.go b/params/protocol_params.go index b46e8d66b2..030083aa9a 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -179,7 +179,7 @@ const ( HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935. ) -// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations +// Bls12381MultiExpDiscountTable gas discount table for BLS12-381 G1 and G2 multi exponentiation operations var Bls12381MultiExpDiscountTable = [128]uint64{1200, 888, 764, 641, 594, 547, 500, 453, 438, 423, 408, 394, 379, 364, 349, 334, 330, 326, 322, 318, 314, 310, 306, 302, 298, 294, 289, 285, 281, 277, 273, 269, 268, 266, 265, 263, 262, 260, 259, 257, 256, 254, 253, 251, 250, 248, 247, 245, 244, 242, 241, 239, 238, 236, 235, 233, 232, 231, 229, 228, 226, 225, 223, 222, 221, 220, 219, 219, 218, 217, 216, 216, 215, 214, 213, 213, 212, 211, 211, 210, 209, 208, 208, 207, 206, 205, 205, 204, 203, 202, 202, 201, 200, 199, 199, 198, 197, 196, 196, 195, 194, 193, 193, 192, 191, 191, 190, 189, 188, 188, 187, 186, 185, 185, 184, 183, 182, 182, 181, 180, 179, 179, 178, 177, 176, 176, 175, 174} // Difficulty parameters. diff --git a/signer/core/api.go b/signer/core/api.go index def2d6041f..12acf925f0 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -664,7 +664,7 @@ func (api *SignerAPI) SignGnosisSafeTx(ctx context.Context, signerAddress common return &gnosisTx, nil } -// Returns the external api version. This method does not require user acceptance. Available methods are +// Version returns the external api version. This method does not require user acceptance. Available methods are // available via enumeration anyway, and this info does not contain user-specific data func (api *SignerAPI) Version(ctx context.Context) (string, error) { return ExternalAPIVersion, nil diff --git a/signer/core/uiapi.go b/signer/core/uiapi.go index 43edfe7d97..2f511c7e19 100644 --- a/signer/core/uiapi.go +++ b/signer/core/uiapi.go @@ -48,7 +48,7 @@ func NewUIServerAPI(extapi *SignerAPI) *UIServerAPI { return &UIServerAPI{extapi, extapi.am} } -// List available accounts. As opposed to the external API definition, this method delivers +// ListAccounts lists available accounts. As opposed to the external API definition, this method delivers // the full Account object and not only Address. // Example call // {"jsonrpc":"2.0","method":"clef_listAccounts","params":[], "id":4} diff --git a/tests/gen_stauthorization.go b/tests/gen_stauthorization.go index fbafd6fdea..4f2c50bd9f 100644 --- a/tests/gen_stauthorization.go +++ b/tests/gen_stauthorization.go @@ -16,7 +16,7 @@ var _ = (*stAuthorizationMarshaling)(nil) // MarshalJSON marshals as JSON. func (s stAuthorization) MarshalJSON() ([]byte, error) { type stAuthorization struct { - ChainID math.HexOrDecimal64 + ChainID *math.HexOrDecimal256 `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce math.HexOrDecimal64 `json:"nonce" gencodec:"required"` V math.HexOrDecimal64 `json:"v" gencodec:"required"` @@ -24,7 +24,7 @@ func (s stAuthorization) MarshalJSON() ([]byte, error) { S *math.HexOrDecimal256 `json:"s" gencodec:"required"` } var enc stAuthorization - enc.ChainID = math.HexOrDecimal64(s.ChainID) + enc.ChainID = (*math.HexOrDecimal256)(s.ChainID) enc.Address = s.Address enc.Nonce = math.HexOrDecimal64(s.Nonce) enc.V = math.HexOrDecimal64(s.V) @@ -36,7 +36,7 @@ func (s stAuthorization) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (s *stAuthorization) UnmarshalJSON(input []byte) error { type stAuthorization struct { - ChainID *math.HexOrDecimal64 + ChainID *math.HexOrDecimal256 `json:"chainId" gencodec:"required"` Address *common.Address `json:"address" gencodec:"required"` Nonce *math.HexOrDecimal64 `json:"nonce" gencodec:"required"` V *math.HexOrDecimal64 `json:"v" gencodec:"required"` @@ -47,9 +47,10 @@ func (s *stAuthorization) UnmarshalJSON(input []byte) error { if err := json.Unmarshal(input, &dec); err != nil { return err } - if dec.ChainID != nil { - s.ChainID = uint64(*dec.ChainID) + if dec.ChainID == nil { + return errors.New("missing required field 'chainId' for stAuthorization") } + s.ChainID = (*big.Int)(dec.ChainID) if dec.Address == nil { return errors.New("missing required field 'address' for stAuthorization") } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 6e66bbaa72..740ebd4afd 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -140,7 +140,7 @@ type stTransactionMarshaling struct { // Authorization is an authorization from an account to deploy code at it's address. type stAuthorization struct { - ChainID uint64 + ChainID *big.Int `json:"chainId" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"` Nonce uint64 `json:"nonce" gencodec:"required"` V uint8 `json:"v" gencodec:"required"` @@ -150,7 +150,7 @@ type stAuthorization struct { // field type overrides for gencodec type stAuthorizationMarshaling struct { - ChainID math.HexOrDecimal64 + ChainID *math.HexOrDecimal256 Nonce math.HexOrDecimal64 V math.HexOrDecimal64 R *math.HexOrDecimal256 @@ -446,7 +446,7 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess authList = make([]types.SetCodeAuthorization, len(tx.AuthorizationList)) for i, auth := range tx.AuthorizationList { authList[i] = types.SetCodeAuthorization{ - ChainID: auth.ChainID, + ChainID: *uint256.MustFromBig(auth.ChainID), Address: auth.Address, Nonce: auth.Nonce, V: auth.V, diff --git a/trie/trie_reader.go b/trie/trie_reader.go index 4b8ba808df..a42cdb0cf9 100644 --- a/trie/trie_reader.go +++ b/trie/trie_reader.go @@ -19,7 +19,6 @@ package trie import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/triedb/database" ) @@ -34,9 +33,6 @@ type trieReader struct { // newTrieReader initializes the trie reader with the given node reader. func newTrieReader(stateRoot, owner common.Hash, db database.NodeDatabase) (*trieReader, error) { if stateRoot == (common.Hash{}) || stateRoot == types.EmptyRootHash { - if stateRoot == (common.Hash{}) { - log.Error("Zero state root hash!") - } return &trieReader{owner: owner}, nil } reader, err := db.NodeReader(stateRoot) diff --git a/triedb/database.go b/triedb/database.go index b448d7cd07..f8ccc5ad33 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -64,10 +64,6 @@ type backend interface { // state. An error will be returned if the specified state is not available. StateReader(root common.Hash) (database.StateReader, error) - // Initialized returns an indicator if the state data is already initialized - // according to the state scheme. - Initialized(genesisRoot common.Hash) bool - // Size returns the current storage size of the diff layers on top of the // disk layer and the storage size of the nodes cached in the disk layer. // @@ -178,12 +174,6 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize, common.Stora return diffs, nodes, preimages } -// Initialized returns an indicator if the state data is already initialized -// according to the state scheme. -func (db *Database) Initialized(genesisRoot common.Hash) bool { - return db.backend.Initialized(genesisRoot) -} - // Scheme returns the node scheme used in the database. func (db *Database) Scheme() string { if db.config.PathDB != nil { diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index fb718f4e74..38392aa519 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -532,12 +532,6 @@ func (c *cleaner) Delete(key []byte) error { panic("not implemented") } -// Initialized returns an indicator if state data is already initialized -// in hash-based scheme by checking the presence of genesis state. -func (db *Database) Initialized(genesisRoot common.Hash) bool { - return rawdb.HasLegacyTrieNode(db.diskdb, genesisRoot) -} - // Update inserts the dirty nodes in provided nodeset into database and link the // account trie with multiple storage tries if necessary. func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet) error { diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 914b17de5b..b0d84eb879 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie/trienode" + "github.com/ethereum/go-verkle" ) const ( @@ -148,6 +149,29 @@ var Defaults = &Config{ // ReadOnly is the config in order to open database in read only mode. var ReadOnly = &Config{ReadOnly: true} +// nodeHasher is the function to compute the hash of supplied node blob. +type nodeHasher func([]byte) (common.Hash, error) + +// merkleNodeHasher computes the hash of the given merkle node. +func merkleNodeHasher(blob []byte) (common.Hash, error) { + if len(blob) == 0 { + return types.EmptyRootHash, nil + } + return crypto.Keccak256Hash(blob), nil +} + +// verkleNodeHasher computes the hash of the given verkle node. +func verkleNodeHasher(blob []byte) (common.Hash, error) { + if len(blob) == 0 { + return types.EmptyVerkleHash, nil + } + n, err := verkle.ParseNode(blob, 0) + if err != nil { + return common.Hash{}, err + } + return n.Commit().Bytes(), nil +} + // Database is a multiple-layered structure for maintaining in-memory states // along with its dirty trie nodes. It consists of one persistent base layer // backed by a key-value store, on top of which arbitrarily many in-memory diff @@ -164,9 +188,10 @@ type Database struct { // readOnly is the flag whether the mutation is allowed to be applied. // It will be set automatically when the database is journaled during // the shutdown to reject all following unexpected mutations. - readOnly bool // Flag if database is opened in read only mode - waitSync bool // Flag if database is deactivated due to initial state sync - isVerkle bool // Flag if database is used for verkle tree + readOnly bool // Flag if database is opened in read only mode + waitSync bool // Flag if database is deactivated due to initial state sync + isVerkle bool // Flag if database is used for verkle tree + hasher nodeHasher // Trie node hasher config *Config // Configuration for database diskdb ethdb.Database // Persistent storage for matured trie nodes @@ -184,19 +209,21 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { } config = config.sanitize() + db := &Database{ + readOnly: config.ReadOnly, + isVerkle: isVerkle, + config: config, + diskdb: diskdb, + hasher: merkleNodeHasher, + } // Establish a dedicated database namespace tailored for verkle-specific // data, ensuring the isolation of both verkle and merkle tree data. It's // important to note that the introduction of a prefix won't lead to // substantial storage overhead, as the underlying database will efficiently // compress the shared key prefix. if isVerkle { - diskdb = rawdb.NewTable(diskdb, string(rawdb.VerklePrefix)) - } - db := &Database{ - readOnly: config.ReadOnly, - isVerkle: isVerkle, - config: config, - diskdb: diskdb, + db.diskdb = rawdb.NewTable(diskdb, string(rawdb.VerklePrefix)) + db.hasher = verkleNodeHasher } // Construct the layer tree by resolving the in-disk singleton state // and in-memory layer journal. @@ -277,6 +304,8 @@ func (db *Database) repairHistory() error { // // The passed in maps(nodes, states) will be retained to avoid copying everything. // Therefore, these maps must not be changed afterwards. +// +// The supplied parentRoot and root must be a valid trie hash value. func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *StateSetWithOrigin) error { // Hold the lock to prevent concurrent mutations. db.lock.Lock() @@ -350,10 +379,9 @@ func (db *Database) Enable(root common.Hash) error { return errDatabaseReadOnly } // Ensure the provided state root matches the stored one. - root = types.TrieRootHash(root) - stored := types.EmptyRootHash - if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 { - stored = crypto.Keccak256Hash(blob) + stored, err := db.hasher(rawdb.ReadAccountTrieNode(db.diskdb, nil)) + if err != nil { + return err } if stored != root { return fmt.Errorf("state root mismatch: stored %x, synced %x", stored, root) @@ -389,6 +417,8 @@ func (db *Database) Enable(root common.Hash) error { // Recover rollbacks the database to a specified historical point. // The state is supported as the rollback destination only if it's // canonical state and the corresponding trie histories are existent. +// +// The supplied root must be a valid trie hash value. func (db *Database) Recover(root common.Hash) error { db.lock.Lock() defer db.lock.Unlock() @@ -401,7 +431,6 @@ func (db *Database) Recover(root common.Hash) error { return errors.New("state rollback is non-supported") } // Short circuit if the target state is not recoverable - root = types.TrieRootHash(root) if !db.Recoverable(root) { return errStateUnrecoverable } @@ -434,9 +463,10 @@ func (db *Database) Recover(root common.Hash) error { } // Recoverable returns the indicator if the specified state is recoverable. +// +// The supplied root must be a valid trie hash value. func (db *Database) Recoverable(root common.Hash) bool { // Ensure the requested state is a known state. - root = types.TrieRootHash(root) id := rawdb.ReadStateID(db.diskdb, root) if id == nil { return false @@ -499,21 +529,6 @@ func (db *Database) Size() (diffs common.StorageSize, nodes common.StorageSize) return diffs, nodes } -// Initialized returns an indicator if the state data is already -// initialized in path-based scheme. -func (db *Database) Initialized(genesisRoot common.Hash) bool { - var inited bool - db.tree.forEach(func(layer layer) { - if layer.rootHash() != types.EmptyRootHash { - inited = true - } - }) - if !inited { - inited = rawdb.ReadSnapSyncStatusFlag(db.diskdb) != rawdb.StateSyncUnknown - } - return inited -} - // modifyAllowed returns the indicator if mutation is allowed. This function // assumes the db.lock is already held. func (db *Database) modifyAllowed() error { diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 648230df15..a6b1d3c045 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -222,7 +222,12 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode dirties = make(map[common.Hash]struct{}) ) for i := 0; i < 20; i++ { - switch rand.Intn(opLen) { + // Start with account creation always + op := createAccountOp + if i > 0 { + op = rand.Intn(opLen) + } + switch op { case createAccountOp: // account creation addr := testrand.Address() @@ -453,8 +458,8 @@ func TestDatabaseRecoverable(t *testing.T) { // Initial state should be recoverable {types.EmptyRootHash, true}, - // Initial state should be recoverable - {common.Hash{}, true}, + // common.Hash{} is not a valid state root for revert + {common.Hash{}, false}, // Layers below current disk layer are recoverable {tester.roots[index-1], true}, diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go index 779a262fdd..267d675bc2 100644 --- a/triedb/pathdb/journal.go +++ b/triedb/pathdb/journal.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" ) @@ -93,9 +92,9 @@ func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) { // loadLayers loads a pre-existing state layer backed by a key-value store. func (db *Database) loadLayers() layer { // Retrieve the root node of persistent state. - var root = types.EmptyRootHash - if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 { - root = crypto.Keccak256Hash(blob) + root, err := db.hasher(rawdb.ReadAccountTrieNode(db.diskdb, nil)) + if err != nil { + log.Crit("Failed to compute node hash", "err", err) } // Load the layers by resolving the journal head, err := db.loadJournal(root) @@ -236,6 +235,8 @@ func (dl *diffLayer) journal(w io.Writer) error { // This is meant to be used during shutdown to persist the layer without // flattening everything down (bad for reorgs). And this function will mark the // database as read-only to prevent all following mutation to disk. +// +// The supplied root must be a valid trie hash value. func (db *Database) Journal(root common.Hash) error { // Retrieve the head layer to journal from. l := db.tree.get(root) @@ -265,9 +266,9 @@ func (db *Database) Journal(root common.Hash) error { } // Secondly write out the state root in disk, ensure all layers // on top are continuous with disk. - diskRoot := types.EmptyRootHash - if blob := rawdb.ReadAccountTrieNode(db.diskdb, nil); len(blob) > 0 { - diskRoot = crypto.Keccak256Hash(blob) + diskRoot, err := db.hasher(rawdb.ReadAccountTrieNode(db.diskdb, nil)) + if err != nil { + return err } if err := rlp.Encode(journal, diskRoot); err != nil { return err diff --git a/triedb/pathdb/layertree.go b/triedb/pathdb/layertree.go index cf6b14e744..0bd086c2f3 100644 --- a/triedb/pathdb/layertree.go +++ b/triedb/pathdb/layertree.go @@ -22,7 +22,6 @@ import ( "sync" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/trie/trienode" ) @@ -62,7 +61,7 @@ func (tree *layerTree) get(root common.Hash) layer { tree.lock.RLock() defer tree.lock.RUnlock() - return tree.layers[types.TrieRootHash(root)] + return tree.layers[root] } // forEach iterates the stored layers inside and applies the @@ -92,7 +91,6 @@ func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint6 // // Although we could silently ignore this internally, it should be the caller's // responsibility to avoid even attempting to insert such a layer. - root, parentRoot = types.TrieRootHash(root), types.TrieRootHash(parentRoot) if root == parentRoot { return errors.New("layer cycle") } @@ -112,7 +110,6 @@ func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint6 // are crossed. All diffs beyond the permitted number are flattened downwards. func (tree *layerTree) cap(root common.Hash, layers int) error { // Retrieve the head layer to cap from - root = types.TrieRootHash(root) l := tree.get(root) if l == nil { return fmt.Errorf("triedb layer [%#x] missing", root)