Merge remote-tracking branch 'origin/develop' into feature/old-consensus-engine

This commit is contained in:
philip-morlier 2023-06-13 22:52:01 -07:00
commit 1bf1a5634e
255 changed files with 2797 additions and 2450 deletions

2
.github/CODEOWNERS vendored
View File

@ -10,7 +10,7 @@ core/ @karalabe @holiman @rjl493456442
eth/ @karalabe @holiman @rjl493456442 eth/ @karalabe @holiman @rjl493456442
eth/catalyst/ @gballet eth/catalyst/ @gballet
eth/tracers/ @s1na eth/tracers/ @s1na
graphql/ @gballet @s1na graphql/ @s1na
les/ @zsfelfoldi @rjl493456442 les/ @zsfelfoldi @rjl493456442
light/ @zsfelfoldi @rjl493456442 light/ @zsfelfoldi @rjl493456442
node/ @fjl node/ @fjl

1
.gitignore vendored
View File

@ -47,3 +47,4 @@ profile.cov
/dashboard/assets/package-lock.json /dashboard/assets/package-lock.json
**/yarn-error.log **/yarn-error.log
logs/

391
README.md
View File

@ -1,367 +1,56 @@
## Go Ethereum # PluGeth
Official Golang execution layer implementation of the Ethereum protocol. PluGeth is a fork of the [Go Ethereum Client](https://github.com/ethereum/go-ethereum)
(Geth) that implements a plugin architecture, allowing developers to extend
Geth's capabilities in a number of different ways using plugins, rather than
having to create additional, new forks of Geth.
[![API Reference]( Documentation can be found [here](https://plugeth.org).
https://camo.githubusercontent.com/915b7be44ada53c290eb157634330494ebe3e30a/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f676f6c616e672f6764646f3f7374617475732e737667
)](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc)
[![Go Report Card](https://goreportcard.com/badge/github.com/ethereum/go-ethereum)](https://goreportcard.com/report/github.com/ethereum/go-ethereum)
[![Travis](https://travis-ci.com/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.com/ethereum/go-ethereum)
[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/nthXNEv)
Automated builds are available for stable releases and the unstable master branch. Binary ## Design Goals
archives are published at https://geth.ethereum.org/downloads/.
## Building the source The upstream Geth client exists primarily to serve as a client for the Ethereum
mainnet, though it also supports a number of popular testnets. Supporting the
Ethereum mainnet is a big enough challenge in its own right that the Geth team
generally avoids changes to support other networks, or to provide features only
a small handful of users would be interested in.
For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth). The result is that many projects have forked Geth. Some implement their own
consensus protocols or alter the behavior of the EVM to support other networks.
Others are designed to extract information from the Ethereum mainnet in ways
the standard Geth client does not support.
Building `geth` requires both a Go (version 1.19 or later) and a C compiler. You can install PluGeth aims to provide a single Geth fork that developers can choose to extend
them using your favourite package manager. Once the dependencies are installed, run rather than forking the Geth project. Out of the box, PluGeth behaves exactly
like upstream Geth, but by installing plugins written in Golang, developers can
extend its functionality in a wide variety of way.
```shell ### Contact Us
make geth
```
or, to build the full suite of utilities: If you're trying to do something that isn't supported by the current plugin system, Reach out to us on [Discord](https://discord.gg/Epf7b7Gr) and we'll help you figure out how to make it work.
```shell ## System Requirements
make all
```
## Executables System requirements will vary depending on which network you are connecting to.
On the Ethereum mainnet, you should have at least 8 GB RAM, 2 CPUs, and 350 GB
of SSD disks.
The go-ethereum project comes with several wrappers/executables found in the `cmd` PluGeth relies on Golang's Plugin implementation, which is only supported on
directory. Linux, FreeBSD, and macOS. Windows support is unlikely to be added in the
foreseeable future.
| Command | Description | # Licensing Considerations
| :--------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`geth`** | Our main Ethereum CLI client. It is the entry point into the Ethereum network (main-, test- or private net), capable of running as a full node (default), archive node (retaining all historical state) or a light node (retrieving data live). It can be used by other processes as a gateway into the Ethereum network via JSON RPC endpoints exposed on top of HTTP, WebSocket and/or IPC transports. `geth --help` and the [CLI page](https://geth.ethereum.org/docs/fundamentals/command-line-options) for command line options. |
| `clef` | Stand-alone signing tool, which can be used as a backend signer for `geth`. |
| `devp2p` | Utilities to interact with nodes on the networking layer, without running a full blockchain. |
| `abigen` | Source code generator to convert Ethereum contract definitions into easy-to-use, compile-time type-safe Go packages. It operates on plain [Ethereum contract ABIs](https://docs.soliditylang.org/en/develop/abi-spec.html) with expanded functionality if the contract bytecode is also available. However, it also accepts Solidity source files, making development much more streamlined. Please see our [Native DApps](https://geth.ethereum.org/docs/developers/dapp-developer/native-bindings) page for details. |
| `bootnode` | Stripped down version of our Ethereum client implementation that only takes part in the network node discovery protocol, but does not run any of the higher level application protocols. It can be used as a lightweight bootstrap node to aid in finding peers in private networks. |
| `evm` | Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode. Its purpose is to allow isolated, fine-grained debugging of EVM opcodes (e.g. `evm --code 60ff60ff --debug run`). |
| `rlpdump` | Developer utility tool to convert binary RLP ([Recursive Length Prefix](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp)) dumps (data encoding used by the Ethereum protocol both network as well as consensus wise) to user-friendlier hierarchical representation (e.g. `rlpdump --hex CE0183FFFFFFC4C304050583616263`). |
## Running `geth` The Geth codebase is licensed under the LGPL. By linking with Geth, you have an
obligation to enable anyone you provide your plugin binaries to run against
their own modified versions of Geth. Because of how Golang plugins work
running against updated versions of Geth may require recompiling the plugin.
Going through all the possible command line flags is out of scope here (please consult our If you plan to license your plugin under the LGPL or a more permissive license,
[CLI Wiki page](https://geth.ethereum.org/docs/fundamentals/command-line-options)), you should be able to meet these requirements. If you plan to use your plugin
but we've enumerated a few common parameter combos to get you up to speed quickly privately without distributing it, you should be fine. If you plan to release
on how you can run your own `geth` instance. your plugin without making the source available, you may find yourself in
violation of Geth's license unless you can provide a way to relink it against
more recent versions of Geth.
### Hardware Requirements
Minimum:
* CPU with 2+ cores
* 4GB RAM
* 1TB free storage space to sync the Mainnet
* 8 MBit/sec download Internet service
Recommended:
* Fast CPU with 4+ cores
* 16GB+ RAM
* High-performance SSD with at least 1TB of free space
* 25+ MBit/sec download Internet service
### Full node on the main Ethereum network
By far the most common scenario is people wanting to simply interact with the Ethereum
network: create accounts; transfer funds; deploy and interact with contracts. For this
particular use case, the user doesn't care about years-old historical data, so we can
sync quickly to the current state of the network. To do so:
```shell
$ geth console
```
This command will:
* Start `geth` in snap sync mode (default, can be changed with the `--syncmode` flag),
causing it to download more data in exchange for avoiding processing the entire history
of the Ethereum network, which is very CPU intensive.
* Start the built-in interactive [JavaScript console](https://geth.ethereum.org/docs/interacting-with-geth/javascript-console),
(via the trailing `console` subcommand) through which you can interact using [`web3` methods](https://github.com/ChainSafe/web3.js/blob/0.20.7/DOCUMENTATION.md)
(note: the `web3` version bundled within `geth` is very old, and not up to date with official docs),
as well as `geth`'s own [management APIs](https://geth.ethereum.org/docs/interacting-with-geth/rpc).
This tool is optional and if you leave it out you can always attach it to an already running
`geth` instance with `geth attach`.
### A Full node on the Görli test network
Transitioning towards developers, if you'd like to play around with creating Ethereum
contracts, you almost certainly would like to do that without any real money involved until
you get the hang of the entire system. In other words, instead of attaching to the main
network, you want to join the **test** network with your node, which is fully equivalent to
the main network, but with play-Ether only.
```shell
$ geth --goerli console
```
The `console` subcommand has the same meaning as above and is equally
useful on the testnet too.
Specifying the `--goerli` flag, however, will reconfigure your `geth` instance a bit:
* Instead of connecting to the main Ethereum network, the client will connect to the Görli
test network, which uses different P2P bootnodes, different network IDs and genesis
states.
* Instead of using the default data directory (`~/.ethereum` on Linux for example), `geth`
will nest itself one level deeper into a `goerli` subfolder (`~/.ethereum/goerli` on
Linux). Note, on OSX and Linux this also means that attaching to a running testnet node
requires the use of a custom endpoint since `geth attach` will try to attach to a
production node endpoint by default, e.g.,
`geth attach <datadir>/goerli/geth.ipc`. Windows users are not affected by
this.
*Note: Although some internal protective measures prevent transactions from
crossing over between the main network and test network, you should always
use separate accounts for play and real money. Unless you manually move
accounts, `geth` will by default correctly separate the two networks and will not make any
accounts available between them.*
### Full node on the Rinkeby test network
Go Ethereum also supports connecting to the older proof-of-authority based test network
called [*Rinkeby*](https://www.rinkeby.io) which is operated by members of the community.
```shell
$ geth --rinkeby console
```
### Configuration
As an alternative to passing the numerous flags to the `geth` binary, you can also pass a
configuration file via:
```shell
$ geth --config /path/to/your_config.toml
```
To get an idea of how the file should look like you can use the `dumpconfig` subcommand to
export your existing configuration:
```shell
$ 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
Docker:
```shell
docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \
-p 8545:8545 -p 30303:30303 \
ethereum/client-go
```
This will start `geth` in snap-sync mode with a DB memory allowance of 1GB, as the
above command does. It will also create a persistent volume in your home directory for
saving your blockchain as well as map the default ports. There is also an `alpine` tag
available for a slim version of the image.
Do not forget `--http.addr 0.0.0.0`, if you want to access RPC from other containers
and/or hosts. By default, `geth` binds to the local interface and RPC endpoints are not
accessible from the outside.
### Programmatically interfacing `geth` nodes
As a developer, sooner rather than later you'll want to start interacting with `geth` and the
Ethereum network via your own programs and not manually through the console. To aid
this, `geth` has built-in support for a JSON-RPC based APIs ([standard APIs](https://ethereum.github.io/execution-apis/api-documentation/)
and [`geth` specific APIs](https://geth.ethereum.org/docs/interacting-with-geth/rpc)).
These can be exposed via HTTP, WebSockets and IPC (UNIX sockets on UNIX based
platforms, and named pipes on Windows).
The IPC interface is enabled by default and exposes all the APIs supported by `geth`,
whereas the HTTP and WS interfaces need to manually be enabled and only expose a
subset of APIs due to security reasons. These can be turned on/off and configured as
you'd expect.
HTTP based JSON-RPC API options:
* `--http` Enable the HTTP-RPC server
* `--http.addr` HTTP-RPC server listening interface (default: `localhost`)
* `--http.port` HTTP-RPC server listening port (default: `8545`)
* `--http.api` API's offered over the HTTP-RPC interface (default: `eth,net,web3`)
* `--http.corsdomain` Comma separated list of domains from which to accept cross origin requests (browser enforced)
* `--ws` Enable the WS-RPC server
* `--ws.addr` WS-RPC server listening interface (default: `localhost`)
* `--ws.port` WS-RPC server listening port (default: `8546`)
* `--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
connect via HTTP, WS or IPC to a `geth` node configured with the above flags and you'll
need to speak [JSON-RPC](https://www.jsonrpc.org/specification) on all transports. You
can reuse the same connection for multiple requests!
**Note: Please understand the security implications of opening up an HTTP/WS based
transport before doing so! Hackers on the internet are actively trying to subvert
Ethereum nodes with exposed APIs! Further, all browser tabs can access locally
running web servers, so malicious web pages could try to subvert locally available
APIs!**
### Operating a private network
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
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`):
```json
{
"config": {
"chainId": <arbitrary positive integer>,
"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
$ bootnode --genkey=boot.key
$ bootnode --nodekey=boot.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 also use a full-fledged `geth` node as a bootnode, but it's the less
recommended way.*
#### Starting up your member nodes
With the bootnode operational and externally reachable (you can try
`telnet <ip> <port>` 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=<bootnode-enode-url-from-above>
```
*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 <usual-flags> --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`).
## Contribution
Thank you for considering helping out with the source code! We welcome contributions
from anyone on the internet, and are grateful for even the smallest of fixes!
If you'd like to contribute to go-ethereum, please fork, fix, commit and send a pull request
for the maintainers to review and merge into the main code base. If you wish to submit
more complex changes though, please check up with the core devs first on [our Discord Server](https://discord.gg/invite/nthXNEv)
to ensure those changes are in line with the general philosophy of the project and/or get
some early feedback which can make both your efforts much lighter as well as our review
and merge procedures quick and simple.
Please make sure your contributions adhere to our coding guidelines:
* Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting)
guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
* Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary)
guidelines.
* Pull requests need to be based on and opened against the `master` branch.
* Commit messages should be prefixed with the package(s) they modify.
* E.g. "eth, rpc: make trace configs optional"
Please see the [Developers' Guide](https://geth.ethereum.org/docs/developers/geth-developer/dev-guide)
for more details on configuring your environment, managing project dependencies, and
testing procedures.
### Contributing to geth.ethereum.org
For contributions to the [go-ethereum website](https://geth.ethereum.org), please checkout and raise pull requests against the `website` branch.
For more detailed instructions please see the `website` branch [README](https://github.com/ethereum/go-ethereum/tree/website#readme) or the
[contributing](https://geth.ethereum.org/docs/developers/geth-developer/contributing) page of the website.
## License
The go-ethereum library (i.e. all code outside of the `cmd` directory) is licensed under the
[GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html),
also included in our repository in the `COPYING.LESSER` file.
The go-ethereum binaries (i.e. all code inside of the `cmd` directory) are licensed under the
[GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), also
included in our repository in the `COPYING` file.

View File

@ -34,6 +34,11 @@ import (
const basefeeWiggleMultiplier = 2 const basefeeWiggleMultiplier = 2
var (
errNoEventSignature = errors.New("no event signature")
errEventSignatureMismatch = errors.New("event signature mismatch")
)
// SignerFn is a signer function callback when a contract requires a method to // SignerFn is a signer function callback when a contract requires a method to
// sign the transaction before submission. // sign the transaction before submission.
type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error) type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error)
@ -488,8 +493,12 @@ func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]inter
// UnpackLog unpacks a retrieved log into the provided output structure. // UnpackLog unpacks a retrieved log into the provided output structure.
func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error {
// Anonymous events are not supported.
if len(log.Topics) == 0 {
return errNoEventSignature
}
if log.Topics[0] != c.abi.Events[event].ID { if log.Topics[0] != c.abi.Events[event].ID {
return fmt.Errorf("event signature mismatch") return errEventSignatureMismatch
} }
if len(log.Data) > 0 { if len(log.Data) > 0 {
if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil { if err := c.abi.UnpackIntoInterface(out, event, log.Data); err != nil {
@ -507,8 +516,12 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log)
// UnpackLogIntoMap unpacks a retrieved log into the provided map. // UnpackLogIntoMap unpacks a retrieved log into the provided map.
func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error { func (c *BoundContract) UnpackLogIntoMap(out map[string]interface{}, event string, log types.Log) error {
// Anonymous events are not supported.
if len(log.Topics) == 0 {
return errNoEventSignature
}
if log.Topics[0] != c.abi.Events[event].ID { if log.Topics[0] != c.abi.Events[event].ID {
return fmt.Errorf("event signature mismatch") return errEventSignatureMismatch
} }
if len(log.Data) > 0 { if len(log.Data) > 0 {
if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil { if err := c.abi.UnpackIntoMap(out, event, log.Data); err != nil {

View File

@ -186,6 +186,23 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) {
unpackAndCheck(t, bc, expectedReceivedMap, mockLog) unpackAndCheck(t, bc, expectedReceivedMap, mockLog)
} }
func TestUnpackAnonymousLogIntoMap(t *testing.T) {
mockLog := newMockLog(nil, common.HexToHash("0x0"))
abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]`
parsedAbi, _ := abi.JSON(strings.NewReader(abiString))
bc := bind.NewBoundContract(common.HexToAddress("0x0"), parsedAbi, nil, nil, nil)
var received map[string]interface{}
err := bc.UnpackLogIntoMap(received, "received", mockLog)
if err == nil {
t.Error("unpacking anonymous event is not supported")
}
if err.Error() != "no event signature" {
t.Errorf("expected error 'no event signature', got '%s'", err)
}
}
func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) {
sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"}) sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"})
if err != nil { if err != nil {

View File

@ -1,19 +1,19 @@
# This file contains sha256 checksums of optional build dependencies. # This file contains sha256 checksums of optional build dependencies.
4d0e2850d197b4ddad3bdb0196300179d095bb3aefd4dfbc3b36702c3728f8ab go1.20.2.src.tar.gz e447b498cde50215c4f7619e5124b0fc4e25fb5d16ea47271c47f278e7aa763a go1.20.3.src.tar.gz
c93b8ced9517d07e1cd4c362c6e2d5242cb139e29b417a328fbf19aded08764c go1.20.2.darwin-amd64.tar.gz c1e1161d6d859deb576e6cfabeb40e3d042ceb1c6f444f617c3c9d76269c3565 go1.20.3.darwin-amd64.tar.gz
7343c87f19e79c0063532e82e1c4d6f42175a32d99f7a4d15e658e88bf97f885 go1.20.2.darwin-arm64.tar.gz 86b0ed0f2b2df50fa8036eea875d1cf2d76cefdacf247c44639a1464b7e36b95 go1.20.3.darwin-arm64.tar.gz
14f9be2004e042b3a64d0facb0c020756a9084a5c7333e33b0752b393b6016ea go1.20.2.freebsd-386.tar.gz 340e80abd047c597fdc0f50a6cc59617f06c297d62f7fc77f4a0164e2da6f7aa go1.20.3.freebsd-386.tar.gz
b41b67b4f1b56797a7cecf6ee7f47fcf4f93960b2788a3683c07dd009d30b2a4 go1.20.2.freebsd-amd64.tar.gz 2169fcd8b6c94c5fbe07c0b470ccfb6001d343f6548ad49f3d9ab78e3b5753c7 go1.20.3.freebsd-amd64.tar.gz
ee240ed33ae57504c41f04c12236aeaa17fbeb6ea9fcd096cd9dc7a89d10d4db go1.20.2.linux-386.tar.gz e12384311403f1389d14cc1c1295bfb4e0dd5ab919403b80da429f671a223507 go1.20.3.linux-386.tar.gz
4eaea32f59cde4dc635fbc42161031d13e1c780b87097f4b4234cfce671f1768 go1.20.2.linux-amd64.tar.gz 979694c2c25c735755bf26f4f45e19e64e4811d661dd07b8c010f7a8e18adfca go1.20.3.linux-amd64.tar.gz
78d632915bb75e9a6356a47a42625fd1a785c83a64a643fedd8f61e31b1b3bef go1.20.2.linux-arm64.tar.gz eb186529f13f901e7a2c4438a05c2cd90d74706aaa0a888469b2a4a617b6ee54 go1.20.3.linux-arm64.tar.gz
d79d56bafd6b52b8d8cbe3f8e967caaac5383a23d7a4fa9ac0e89778cd16a076 go1.20.2.linux-armv6l.tar.gz b421e90469a83671641f81b6e20df6500f033e9523e89cbe7b7223704dd1035c go1.20.3.linux-armv6l.tar.gz
850564ddb760cb703db63bf20182dc4407abd2ff090a95fa66d6634d172fd095 go1.20.2.linux-ppc64le.tar.gz 943c89aa1624ea544a022b31e3d6e16a037200e436370bdd5fd67f3fa60be282 go1.20.3.linux-ppc64le.tar.gz
8da24c5c4205fe8115f594237e5db7bcb1d23df67bc1fa9a999954b1976896e8 go1.20.2.linux-s390x.tar.gz 126cf823a5634ef2544b866db107b9d351d3ea70d9e240b0bdcfb46f4dcae54b go1.20.3.linux-s390x.tar.gz
31838b291117495bbb93683603e98d5118bfabd2eb318b4d07540bfd524bab86 go1.20.2.windows-386.zip 37e9146e1f9d681cfcaa6fee6c7b890c44c64bc50228c9588f3c4231346d33bd go1.20.3.windows-386.zip
fe439f0e438f7555a7f5f7194ddb6f4a07b0de1fa414385d19f2aeb26d9f43db go1.20.2.windows-amd64.zip 143a2837821c7dbacf7744cbb1a8421c1f48307c6fdfaeffc5f8c2f69e1b7932 go1.20.3.windows-amd64.zip
ac5010c8b8b22849228a8dea698d58b9c7be2195d30c6d778cce0f709858fa64 go1.20.2.windows-arm64.zip 158cb159e00bc979f473e0f5b5a561613129c5e51067967b72b8e072e5a4db81 go1.20.3.windows-arm64.zip
fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz
75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz 75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz

View File

@ -139,7 +139,7 @@ var (
// This is the version of Go that will be downloaded by // This is the version of Go that will be downloaded by
// //
// go run ci.go install -dlgo // go run ci.go install -dlgo
dlgoVersion = "1.20.2" dlgoVersion = "1.20.3"
// This is the version of Go that will be used to bootstrap the PPA builder. // This is the version of Go that will be used to bootstrap the PPA builder.
// //
@ -465,10 +465,6 @@ func maybeSkipArchive(env build.Environment) {
log.Printf("skipping archive creation because this is a PR build") log.Printf("skipping archive creation because this is a PR build")
os.Exit(0) os.Exit(0)
} }
if env.IsCronJob {
log.Printf("skipping archive creation because this is a cron job")
os.Exit(0)
}
if env.Branch != "master" && !strings.HasPrefix(env.Tag, "v1.") { if env.Branch != "master" && !strings.HasPrefix(env.Tag, "v1.") {
log.Printf("skipping archive creation because branch %q, tag %q is not on the inclusion list", env.Branch, env.Tag) log.Printf("skipping archive creation because branch %q, tag %q is not on the inclusion list", env.Branch, env.Tag)
os.Exit(0) os.Exit(0)

View File

@ -141,7 +141,7 @@ loop:
"added", atomic.LoadUint64(&added), "added", atomic.LoadUint64(&added),
"updated", atomic.LoadUint64(&updated), "updated", atomic.LoadUint64(&updated),
"removed", atomic.LoadUint64(&removed), "removed", atomic.LoadUint64(&removed),
"ignored(recent)", atomic.LoadUint64(&removed), "ignored(recent)", atomic.LoadUint64(&recent),
"ignored(incompatible)", atomic.LoadUint64(&skipped)) "ignored(incompatible)", atomic.LoadUint64(&skipped))
} }
} }

View File

@ -144,7 +144,7 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string)
_, err = c.CreateDNSRecord(context.Background(), c.zoneID, record) _, err = c.CreateDNSRecord(context.Background(), c.zoneID, record)
} else if old.Content != val { } else if old.Content != val {
// Entry already exists, only change its content. // Entry already exists, only change its content.
log.Debug(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val)) log.Info(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val))
updated++ updated++
old.Content = val old.Content = val
err = c.UpdateDNSRecord(context.Background(), c.zoneID, old.ID, old) err = c.UpdateDNSRecord(context.Background(), c.zoneID, old.ID, old)

View File

@ -221,7 +221,13 @@ func (c *route53Client) computeChanges(name string, records map[string]string, e
} }
records = lrecords records = lrecords
var changes []types.Change var (
changes []types.Change
inserts int
upserts int
skips int
)
for path, newValue := range records { for path, newValue := range records {
prevRecords, exists := existing[path] prevRecords, exists := existing[path]
prevValue := strings.Join(prevRecords.values, "") prevValue := strings.Join(prevRecords.values, "")
@ -237,20 +243,30 @@ func (c *route53Client) computeChanges(name string, records map[string]string, e
if !exists { if !exists {
// Entry is unknown, push a new one // Entry is unknown, push a new one
log.Info(fmt.Sprintf("Creating %s = %s", path, newValue)) log.Debug(fmt.Sprintf("Creating %s = %s", path, newValue))
changes = append(changes, newTXTChange("CREATE", path, ttl, newValue)) changes = append(changes, newTXTChange("CREATE", path, ttl, newValue))
inserts++
} else if prevValue != newValue || prevRecords.ttl != ttl { } else if prevValue != newValue || prevRecords.ttl != ttl {
// Entry already exists, only change its content. // Entry already exists, only change its content.
log.Info(fmt.Sprintf("Updating %s from %s to %s", path, prevValue, newValue)) log.Info(fmt.Sprintf("Updating %s from %s to %s", path, prevValue, newValue))
changes = append(changes, newTXTChange("UPSERT", path, ttl, newValue)) changes = append(changes, newTXTChange("UPSERT", path, ttl, newValue))
upserts++
} else { } else {
log.Debug(fmt.Sprintf("Skipping %s = %s", path, newValue)) log.Debug(fmt.Sprintf("Skipping %s = %s", path, newValue))
skips++
} }
} }
// Iterate over the old records and delete anything stale. // Iterate over the old records and delete anything stale.
changes = append(changes, makeDeletionChanges(existing, records)...) deletions := makeDeletionChanges(existing, records)
changes = append(changes, deletions...)
log.Info("Computed DNS changes",
"changes", len(changes),
"inserts", inserts,
"skips", skips,
"deleted", len(deletions),
"upserts", upserts)
// Ensure changes are in the correct order. // Ensure changes are in the correct order.
sortChanges(changes) sortChanges(changes)
return changes return changes
@ -263,7 +279,7 @@ func makeDeletionChanges(records map[string]recordSet, keep map[string]string) [
if _, ok := keep[path]; ok { if _, ok := keep[path]; ok {
continue continue
} }
log.Info(fmt.Sprintf("Deleting %s = %s", path, strings.Join(set.values, ""))) log.Debug(fmt.Sprintf("Deleting %s = %s", path, strings.Join(set.values, "")))
changes = append(changes, newTXTChange("DELETE", path, set.ttl, set.values...)) changes = append(changes, newTXTChange("DELETE", path, set.ttl, set.values...))
} }
return changes return changes

View File

@ -174,7 +174,6 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
return nil, nil, err return nil, nil, err
} }
vmConfig.Tracer = tracer vmConfig.Tracer = tracer
vmConfig.Debug = (tracer != nil)
statedb.SetTxContext(tx.Hash(), txIndex) statedb.SetTxContext(tx.Hash(), txIndex)
var ( var (

View File

@ -180,7 +180,6 @@ func Transition(ctx *cli.Context) error {
vmConfig := vm.Config{ vmConfig := vm.Config{
Tracer: tracer, Tracer: tracer,
Debug: (tracer != nil),
} }
// Construct the chainconfig // Construct the chainconfig
var chainConfig *params.ChainConfig var chainConfig *params.ChainConfig
@ -250,9 +249,9 @@ func Transition(ctx *cli.Context) error {
if chainConfig.IsLondon(big.NewInt(int64(prestate.Env.Number))) { if chainConfig.IsLondon(big.NewInt(int64(prestate.Env.Number))) {
if prestate.Env.BaseFee != nil { if prestate.Env.BaseFee != nil {
// Already set, base fee has precedent over parent base fee. // Already set, base fee has precedent over parent base fee.
} else if prestate.Env.ParentBaseFee != nil { } else if prestate.Env.ParentBaseFee != nil && prestate.Env.Number != 0 {
parent := &types.Header{ parent := &types.Header{
Number: new(big.Int).SetUint64(prestate.Env.Number), Number: new(big.Int).SetUint64(prestate.Env.Number - 1),
BaseFee: prestate.Env.ParentBaseFee, BaseFee: prestate.Env.ParentBaseFee,
GasUsed: prestate.Env.ParentGasUsed, GasUsed: prestate.Env.ParentGasUsed,
GasLimit: prestate.Env.ParentGasLimit, GasLimit: prestate.Env.ParentGasLimit,

View File

@ -40,6 +40,7 @@ import (
"github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -125,6 +126,7 @@ func runCmd(ctx *cli.Context) error {
sender = common.BytesToAddress([]byte("sender")) sender = common.BytesToAddress([]byte("sender"))
receiver = common.BytesToAddress([]byte("receiver")) receiver = common.BytesToAddress([]byte("receiver"))
genesisConfig *core.Genesis genesisConfig *core.Genesis
preimages = ctx.Bool(DumpFlag.Name)
) )
if ctx.Bool(MachineFlag.Name) { if ctx.Bool(MachineFlag.Name) {
tracer = logger.NewJSONLogger(logconfig, os.Stdout) tracer = logger.NewJSONLogger(logconfig, os.Stdout)
@ -139,10 +141,12 @@ func runCmd(ctx *cli.Context) error {
genesisConfig = gen genesisConfig = gen
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
genesis := gen.MustCommit(db) genesis := gen.MustCommit(db)
statedb, _ = state.New(genesis.Root(), state.NewDatabase(db), nil) sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: preimages})
statedb, _ = state.New(genesis.Root(), sdb, nil)
chainConfig = gen.Config chainConfig = gen.Config
} else { } else {
statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) sdb := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: preimages})
statedb, _ = state.New(common.Hash{}, sdb, nil)
genesisConfig = new(core.Genesis) genesisConfig = new(core.Genesis)
} }
if ctx.String(SenderFlag.Name) != "" { if ctx.String(SenderFlag.Name) != "" {
@ -214,7 +218,6 @@ func runCmd(ctx *cli.Context) error {
BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), BlockNumber: new(big.Int).SetUint64(genesisConfig.Number),
EVMConfig: vm.Config{ EVMConfig: vm.Config{
Tracer: tracer, Tracer: tracer,
Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name),
}, },
} }

View File

@ -92,7 +92,6 @@ func stateTestCmd(ctx *cli.Context) error {
// Iterate over all the tests, run them and aggregate the results // Iterate over all the tests, run them and aggregate the results
cfg := vm.Config{ cfg := vm.Config{
Tracer: tracer, Tracer: tracer,
Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name),
} }
results := make([]StatetestResult, 0, len(tests)) results := make([]StatetestResult, 0, len(tests))
for key, test := range tests { for key, test := range tests {

View File

@ -301,7 +301,11 @@ func accountUpdate(ctx *cli.Context) error {
utils.Fatalf("No accounts specified to update") utils.Fatalf("No accounts specified to update")
} }
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) backends := stack.AccountManager().Backends(keystore.KeyStoreType)
if len(backends) == 0 {
utils.Fatalf("Keystore is not available")
}
ks := backends[0].(*keystore.KeyStore)
for _, addr := range ctx.Args().Slice() { for _, addr := range ctx.Args().Slice() {
account, oldPassword := unlockAccount(ks, addr, 0, nil) account, oldPassword := unlockAccount(ks, addr, 0, nil)
@ -326,7 +330,11 @@ func importWallet(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
passphrase := utils.GetPassPhraseWithList("", false, 0, utils.MakePasswordList(ctx)) passphrase := utils.GetPassPhraseWithList("", false, 0, utils.MakePasswordList(ctx))
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) backends := stack.AccountManager().Backends(keystore.KeyStoreType)
if len(backends) == 0 {
utils.Fatalf("Keystore is not available")
}
ks := backends[0].(*keystore.KeyStore)
acct, err := ks.ImportPreSaleKey(keyJSON, passphrase) acct, err := ks.ImportPreSaleKey(keyJSON, passphrase)
if err != nil { if err != nil {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
@ -347,7 +355,11 @@ func accountImport(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
passphrase := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) passphrase := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) backends := stack.AccountManager().Backends(keystore.KeyStoreType)
if len(backends) == 0 {
utils.Fatalf("Keystore is not available")
}
ks := backends[0].(*keystore.KeyStore)
acct, err := ks.ImportECDSA(key, passphrase) acct, err := ks.ImportECDSA(key, passphrase)
if err != nil { if err != nil {
utils.Fatalf("Could not create the account: %v", err) utils.Fatalf("Could not create the account: %v", err)

View File

@ -355,9 +355,10 @@ func geth(ctx *cli.Context) error {
defer stack.Close() defer stack.Close()
defer pluginsOnShutdown() defer pluginsOnShutdown()
stack.RegisterAPIs(pluginGetAPIs(stack, wrapperBackend)) stack.RegisterAPIs(pluginGetAPIs(stack, wrapperBackend))
//end PluGeth code injection
startNode(ctx, stack, backend, false) startNode(ctx, stack, backend, false)
pluginBlockChain()
pluginHookTester() pluginHookTester()
//end PluGeth code injection
stack.Wait() stack.Wait()
return nil return nil
} }
@ -481,7 +482,12 @@ func unlockAccounts(ctx *cli.Context, stack *node.Node) {
if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() { if !stack.Config().InsecureUnlockAllowed && stack.Config().ExtRPCEnabled() {
utils.Fatalf("Account unlock with HTTP access is forbidden!") utils.Fatalf("Account unlock with HTTP access is forbidden!")
} }
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) backends := stack.AccountManager().Backends(keystore.KeyStoreType)
if len(backends) == 0 {
log.Warn("Failed to unlock accounts, keystore is not available")
return
}
ks := backends[0].(*keystore.KeyStore)
passwords := utils.MakePasswordList(ctx) passwords := utils.MakePasswordList(ctx)
for i, account := range unlocks { for i, account := range unlocks {
unlockAccount(ks, account, i, passwords) unlockAccount(ks, account, i, passwords)

View File

@ -103,8 +103,8 @@ func pluginsOnShutdown() {
OnShutdown(plugins.DefaultPluginLoader) OnShutdown(plugins.DefaultPluginLoader)
} }
func HookTester(pl *plugins.PluginLoader) { func BlockChain(pl *plugins.PluginLoader) {
fnList := pl.Lookup("HookTester", func(item interface{}) bool { fnList := pl.Lookup("BlockChain", func(item interface{}) bool {
_, ok := item.(func()) _, ok := item.(func())
return ok return ok
}) })
@ -113,11 +113,10 @@ func HookTester(pl *plugins.PluginLoader) {
} }
} }
func pluginHookTester() { func pluginBlockChain() {
if plugins.DefaultPluginLoader == nil { if plugins.DefaultPluginLoader == nil {
log.Warn("Attempting HookTester, but default PluginLoader has not been initialized") log.Warn("Attempting BlockChain, but default PluginLoader has not been initialized")
return return
} }
HookTester(plugins.DefaultPluginLoader) BlockChain(plugins.DefaultPluginLoader)
} }

View File

@ -17,19 +17,10 @@
package common package common
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
) )
// MakeName creates a node name that follows the ethereum convention
// for such names. It adds the operation system name and Go runtime version
// the name.
func MakeName(name, version string) string {
return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version())
}
// FileExist checks if a file exists at filePath. // FileExist checks if a file exists at filePath.
func FileExist(filePath string) bool { func FileExist(filePath string) bool {
_, err := os.Stat(filePath) _, err := os.Stat(filePath)

View File

@ -400,7 +400,7 @@ func (ma *MixedcaseAddress) UnmarshalJSON(input []byte) error {
} }
// MarshalJSON marshals the original value // MarshalJSON marshals the original value
func (ma *MixedcaseAddress) MarshalJSON() ([]byte, error) { func (ma MixedcaseAddress) MarshalJSON() ([]byte, error) {
if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") { if strings.HasPrefix(ma.original, "0x") || strings.HasPrefix(ma.original, "0X") {
return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:])) return json.Marshal(fmt.Sprintf("0x%s", ma.original[2:]))
} }

View File

@ -154,6 +154,31 @@ func BenchmarkAddressHex(b *testing.B) {
} }
} }
// Test checks if the customized json marshaller of MixedcaseAddress object
// is invoked correctly. In golang the struct pointer will inherit the
// non-pointer receiver methods, the reverse is not true. In the case of
// MixedcaseAddress, it must define the MarshalJSON method in the object
// but not the pointer level, so that this customized marshalled can be used
// for both MixedcaseAddress object and pointer.
func TestMixedcaseAddressMarshal(t *testing.T) {
var (
output string
input = "0xae967917c465db8578ca9024c205720b1a3651A9"
)
addr, err := NewMixedcaseAddressFromString(input)
if err != nil {
t.Fatal(err)
}
blob, err := json.Marshal(*addr)
if err != nil {
t.Fatal(err)
}
json.Unmarshal(blob, &output)
if output != input {
t.Fatal("Failed to marshal/unmarshal MixedcaseAddress object")
}
}
func TestMixedcaseAccount_Address(t *testing.T) { func TestMixedcaseAccount_Address(t *testing.T) {
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md
// Note: 0X{checksum_addr} is not valid according to spec above // Note: 0X{checksum_addr} is not valid according to spec above
@ -177,7 +202,7 @@ func TestMixedcaseAccount_Address(t *testing.T) {
} }
} }
//These should throw exceptions: // These should throw exceptions:
var r2 []MixedcaseAddress var r2 []MixedcaseAddress
for _, r := range []string{ for _, r := range []string{
`["0x11111111111111111111122222222222233333"]`, // Too short `["0x11111111111111111111122222222222233333"]`, // Too short

View File

@ -263,11 +263,19 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
// Verify existence / non-existence of withdrawalsHash. // Verify existence / non-existence of withdrawalsHash.
shanghai := chain.Config().IsShanghai(header.Time) shanghai := chain.Config().IsShanghai(header.Time)
if shanghai && header.WithdrawalsHash == nil { if shanghai && header.WithdrawalsHash == nil {
return fmt.Errorf("missing withdrawalsHash") return errors.New("missing withdrawalsHash")
} }
if !shanghai && header.WithdrawalsHash != nil { if !shanghai && header.WithdrawalsHash != nil {
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash) return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
} }
// Verify the existence / non-existence of excessDataGas
cancun := chain.Config().IsCancun(header.Time)
if cancun && header.ExcessDataGas == nil {
return errors.New("missing excessDataGas")
}
if !cancun && header.ExcessDataGas != nil {
return fmt.Errorf("invalid excessDataGas: have %d, expected nil", header.ExcessDataGas)
}
return nil return nil
} }

View File

@ -301,9 +301,8 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
if chain.Config().IsShanghai(header.Time) { if chain.Config().IsShanghai(header.Time) {
return fmt.Errorf("clique does not support shanghai fork") return fmt.Errorf("clique does not support shanghai fork")
} }
// If all checks passed, validate any special fields for hard forks if chain.Config().IsCancun(header.Time) {
if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil { return fmt.Errorf("clique does not support cancun fork")
return err
} }
// All basic checks passed, verify cascading fields // All basic checks passed, verify cascading fields
return c.verifyCascadingFields(chain, header, parents) return c.verifyCascadingFields(chain, header, parents)

View File

@ -163,7 +163,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) {
rows := int(size) / hashBytes rows := int(size) / hashBytes
// Start a monitoring goroutine to report progress on low end devices // Start a monitoring goroutine to report progress on low end devices
var progress uint32 var progress atomic.Uint32
done := make(chan struct{}) done := make(chan struct{})
defer close(done) defer close(done)
@ -174,7 +174,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) {
case <-done: case <-done:
return return
case <-time.After(3 * time.Second): case <-time.After(3 * time.Second):
logger.Info("Generating ethash verification cache", "percentage", atomic.LoadUint32(&progress)*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start))) logger.Info("Generating ethash verification cache", "percentage", progress.Load()*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start)))
} }
} }
}() }()
@ -185,7 +185,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) {
keccak512(cache, seed) keccak512(cache, seed)
for offset := uint64(hashBytes); offset < size; offset += hashBytes { for offset := uint64(hashBytes); offset < size; offset += hashBytes {
keccak512(cache[offset:], cache[offset-hashBytes:offset]) keccak512(cache[offset:], cache[offset-hashBytes:offset])
atomic.AddUint32(&progress, 1) progress.Add(1)
} }
// Use a low-round version of randmemohash // Use a low-round version of randmemohash
temp := make([]byte, hashBytes) temp := make([]byte, hashBytes)
@ -200,7 +200,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) {
bitutil.XORBytes(temp, cache[srcOff:srcOff+hashBytes], cache[xorOff:xorOff+hashBytes]) bitutil.XORBytes(temp, cache[srcOff:srcOff+hashBytes], cache[xorOff:xorOff+hashBytes])
keccak512(cache[dstOff:], temp) keccak512(cache[dstOff:], temp)
atomic.AddUint32(&progress, 1) progress.Add(1)
} }
} }
// Swap the byte order on big endian systems and return // Swap the byte order on big endian systems and return
@ -299,7 +299,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
var pend sync.WaitGroup var pend sync.WaitGroup
pend.Add(threads) pend.Add(threads)
var progress uint64 var progress atomic.Uint64
for i := 0; i < threads; i++ { for i := 0; i < threads; i++ {
go func(id int) { go func(id int) {
defer pend.Done() defer pend.Done()
@ -323,7 +323,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
} }
copy(dataset[index*hashBytes:], item) copy(dataset[index*hashBytes:], item)
if status := atomic.AddUint64(&progress, 1); status%percent == 0 { if status := progress.Add(1); status%percent == 0 {
logger.Info("Generating DAG in progress", "percentage", (status*100)/(size/hashBytes), "elapsed", common.PrettyDuration(time.Since(start))) logger.Info("Generating DAG in progress", "percentage", (status*100)/(size/hashBytes), "elapsed", common.PrettyDuration(time.Since(start)))
} }
} }

View File

@ -313,6 +313,9 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
if chain.Config().IsShanghai(header.Time) { if chain.Config().IsShanghai(header.Time) {
return fmt.Errorf("ethash does not support shanghai fork") return fmt.Errorf("ethash does not support shanghai fork")
} }
if chain.Config().IsCancun(header.Time) {
return fmt.Errorf("ethash does not support cancun fork")
}
// Verify the engine specific seal securing the block // Verify the engine specific seal securing the block
if seal { if seal {
if err := ethash.verifySeal(chain, header, false); err != nil { if err := ethash.verifySeal(chain, header, false); err != nil {
@ -323,9 +326,6 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil { if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil {
return err return err
} }
if err := misc.VerifyForkHashes(chain.Config(), header, uncle); err != nil {
return err
}
return nil return nil
} }

View File

@ -313,7 +313,7 @@ type dataset struct {
mmap mmap.MMap // Memory map itself to unmap before releasing mmap mmap.MMap // Memory map itself to unmap before releasing
dataset []uint32 // The actual cache data content dataset []uint32 // The actual cache data content
once sync.Once // Ensures the cache is generated only once once sync.Once // Ensures the cache is generated only once
done uint32 // Atomic flag to determine generation status done atomic.Bool // Atomic flag to determine generation status
} }
// newDataset creates a new ethash mining dataset and returns it as a plain Go // newDataset creates a new ethash mining dataset and returns it as a plain Go
@ -326,7 +326,7 @@ func newDataset(epoch uint64) *dataset {
func (d *dataset) generate(dir string, limit int, lock bool, test bool) { func (d *dataset) generate(dir string, limit int, lock bool, test bool) {
d.once.Do(func() { d.once.Do(func() {
// Mark the dataset generated after we're done. This is needed for remote // Mark the dataset generated after we're done. This is needed for remote
defer atomic.StoreUint32(&d.done, 1) defer d.done.Store(true)
csize := cacheSize(d.epoch*epochLength + 1) csize := cacheSize(d.epoch*epochLength + 1)
dsize := datasetSize(d.epoch*epochLength + 1) dsize := datasetSize(d.epoch*epochLength + 1)
@ -390,7 +390,7 @@ func (d *dataset) generate(dir string, limit int, lock bool, test bool) {
// or not (it may not have been started at all). This is useful for remote miners // or not (it may not have been started at all). This is useful for remote miners
// to default to verification caches instead of blocking on DAG generations. // to default to verification caches instead of blocking on DAG generations.
func (d *dataset) generated() bool { func (d *dataset) generated() bool {
return atomic.LoadUint32(&d.done) == 1 return d.done.Load()
} }
// finalizer closes any file handlers and memory maps open. // finalizer closes any file handlers and memory maps open.

View File

@ -34,7 +34,6 @@ func copyConfig(original *params.ChainConfig) *params.ChainConfig {
DAOForkBlock: original.DAOForkBlock, DAOForkBlock: original.DAOForkBlock,
DAOForkSupport: original.DAOForkSupport, DAOForkSupport: original.DAOForkSupport,
EIP150Block: original.EIP150Block, EIP150Block: original.EIP150Block,
EIP150Hash: original.EIP150Hash,
EIP155Block: original.EIP155Block, EIP155Block: original.EIP155Block,
EIP158Block: original.EIP158Block, EIP158Block: original.EIP158Block,
ByzantiumBlock: original.ByzantiumBlock, ByzantiumBlock: original.ByzantiumBlock,

54
consensus/misc/eip4844.go Normal file
View File

@ -0,0 +1,54 @@
// Copyright 2023 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package misc
import (
"math/big"
"github.com/ethereum/go-ethereum/params"
)
var (
minDataGasPrice = big.NewInt(params.BlobTxMinDataGasprice)
dataGaspriceUpdateFraction = big.NewInt(params.BlobTxDataGaspriceUpdateFraction)
)
// CalcBlobFee calculates the blobfee from the header's excess data gas field.
func CalcBlobFee(excessDataGas *big.Int) *big.Int {
// If this block does not yet have EIP-4844 enabled, return the starting fee
if excessDataGas == nil {
return big.NewInt(params.BlobTxMinDataGasprice)
}
return fakeExponential(minDataGasPrice, excessDataGas, dataGaspriceUpdateFraction)
}
// fakeExponential approximates factor * e ** (numerator / denominator) using
// Taylor expansion.
func fakeExponential(factor, numerator, denominator *big.Int) *big.Int {
var (
output = new(big.Int)
accum = new(big.Int).Mul(factor, denominator)
)
for i := 1; accum.Sign() > 0; i++ {
output.Add(output, accum)
accum.Mul(accum, numerator)
accum.Div(accum, denominator)
accum.Div(accum, big.NewInt(int64(i)))
}
return output.Div(output, denominator)
}

View File

@ -0,0 +1,85 @@
// Copyright 2023 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package misc
import (
"fmt"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/params"
)
func TestCalcBlobFee(t *testing.T) {
tests := []struct {
excessDataGas int64
blobfee int64
}{
{0, 1},
{1542706, 1},
{1542707, 2},
{10 * 1024 * 1024, 111},
}
have := CalcBlobFee(nil)
if have.Int64() != params.BlobTxMinDataGasprice {
t.Errorf("nil test: blobfee mismatch: have %v, want %v", have, params.BlobTxMinDataGasprice)
}
for i, tt := range tests {
have := CalcBlobFee(big.NewInt(tt.excessDataGas))
if have.Int64() != tt.blobfee {
t.Errorf("test %d: blobfee mismatch: have %v want %v", i, have, tt.blobfee)
}
}
}
func TestFakeExponential(t *testing.T) {
tests := []struct {
factor int64
numerator int64
denominator int64
want int64
}{
// When numerator == 0 the return value should always equal the value of factor
{1, 0, 1, 1},
{38493, 0, 1000, 38493},
{0, 1234, 2345, 0}, // should be 0
{1, 2, 1, 6}, // approximate 7.389
{1, 4, 2, 6},
{1, 3, 1, 16}, // approximate 20.09
{1, 6, 2, 18},
{1, 4, 1, 49}, // approximate 54.60
{1, 8, 2, 50},
{10, 8, 2, 542}, // approximate 540.598
{11, 8, 2, 596}, // approximate 600.58
{1, 5, 1, 136}, // approximate 148.4
{1, 5, 2, 11}, // approximate 12.18
{2, 5, 2, 23}, // approximate 24.36
{1, 50000000, 2225652, 5709098764},
}
for i, tt := range tests {
f, n, d := big.NewInt(tt.factor), big.NewInt(tt.numerator), big.NewInt(tt.denominator)
original := fmt.Sprintf("%d %d %d", f, n, d)
have := fakeExponential(f, n, d)
if have.Int64() != tt.want {
t.Errorf("test %d: fake exponential mismatch: have %v want %v", i, have, tt.want)
}
later := fmt.Sprintf("%d %d %d", f, n, d)
if original != later {
t.Errorf("test %d: fake exponential modified arguments: have\n%v\nwant\n%v", i, later, original)
}
}
}

View File

@ -1,43 +0,0 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package misc
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
// VerifyForkHashes verifies that blocks conforming to network hard-forks do have
// the correct hashes, to avoid clients going off on different chains. This is an
// optional feature.
func VerifyForkHashes(config *params.ChainConfig, header *types.Header, uncle bool) error {
// We don't care about uncles
if uncle {
return nil
}
// If the homestead reprice hash is set, validate it
if config.EIP150Block != nil && config.EIP150Block.Cmp(header.Number) == 0 {
if config.EIP150Hash != (common.Hash{}) && config.EIP150Hash != header.Hash() {
return fmt.Errorf("homestead gas reprice fork: have %#x, want %#x", header.Hash(), config.EIP150Hash)
}
}
// All ok, return
return nil
}

View File

@ -174,7 +174,7 @@ type BlockChain struct {
triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc
gcproc time.Duration // Accumulates canonical block processing for trie dumping gcproc time.Duration // Accumulates canonical block processing for trie dumping
lastWrite uint64 // Last block when the state was flushed lastWrite uint64 // Last block when the state was flushed
flushInterval int64 // Time interval (processing time) after which to flush a state flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state
triedb *trie.Database // The database handler for maintaining trie nodes. triedb *trie.Database // The database handler for maintaining trie nodes.
stateCache state.Database // State database to reuse between imports (contains state cache) stateCache state.Database // State database to reuse between imports (contains state cache)
@ -215,8 +215,8 @@ type BlockChain struct {
wg sync.WaitGroup // wg sync.WaitGroup //
quit chan struct{} // shutdown signal, closed in Stop. quit chan struct{} // shutdown signal, closed in Stop.
running int32 // 0 if chain is running, 1 when stopped stopping atomic.Bool // false if chain is running, true when stopped
procInterrupt int32 // interrupt signaler for block processing procInterrupt atomic.Bool // interrupt signaler for block processing
engine consensus.Engine engine consensus.Engine
validator Validator // Block and state validator interface validator Validator // Block and state validator interface
@ -233,7 +233,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
if cacheConfig == nil { if cacheConfig == nil {
cacheConfig = defaultCacheConfig cacheConfig = defaultCacheConfig
} }
// Open trie database with provided config // Open trie database with provided config
triedb := trie.NewDatabaseWithConfig(db, &trie.Config{ triedb := trie.NewDatabaseWithConfig(db, &trie.Config{
Cache: cacheConfig.TrieCleanLimit, Cache: cacheConfig.TrieCleanLimit,
@ -260,7 +259,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
cacheConfig: cacheConfig, cacheConfig: cacheConfig,
db: db, db: db,
triedb: triedb, triedb: triedb,
flushInterval: int64(cacheConfig.TrieTimeLimit),
triegc: prque.New[int64, common.Hash](nil), triegc: prque.New[int64, common.Hash](nil),
quit: make(chan struct{}), quit: make(chan struct{}),
chainmu: syncx.NewClosableMutex(), chainmu: syncx.NewClosableMutex(),
@ -273,6 +271,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
engine: engine, engine: engine,
vmConfig: vmConfig, vmConfig: vmConfig,
} }
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
bc.forker = NewForkChoice(bc, shouldPreserve) bc.forker = NewForkChoice(bc, shouldPreserve)
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
bc.validator = NewBlockValidator(chainConfig, bc, engine) bc.validator = NewBlockValidator(chainConfig, bc, engine)
@ -909,14 +908,14 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) {
headBlockGauge.Update(int64(block.NumberU64())) headBlockGauge.Update(int64(block.NumberU64()))
} }
// stop stops the blockchain service. If any imports are currently in progress // stopWithoutSaving stops the blockchain service. If any imports are currently in progress
// it will abort them using the procInterrupt. This method stops all running // it will abort them using the procInterrupt. This method stops all running
// goroutines, but does not do all the post-stop work of persisting data. // goroutines, but does not do all the post-stop work of persisting data.
// OBS! It is generally recommended to use the Stop method! // OBS! It is generally recommended to use the Stop method!
// This method has been exposed to allow tests to stop the blockchain while simulating // This method has been exposed to allow tests to stop the blockchain while simulating
// a crash. // a crash.
func (bc *BlockChain) stopWithoutSaving() { func (bc *BlockChain) stopWithoutSaving() {
if !atomic.CompareAndSwapInt32(&bc.running, 0, 1) { if !bc.stopping.CompareAndSwap(false, true) {
return return
} }
@ -998,12 +997,12 @@ func (bc *BlockChain) Stop() {
// errInsertionInterrupted as soon as possible. Insertion is permanently disabled after // errInsertionInterrupted as soon as possible. Insertion is permanently disabled after
// calling this method. // calling this method.
func (bc *BlockChain) StopInsert() { func (bc *BlockChain) StopInsert() {
atomic.StoreInt32(&bc.procInterrupt, 1) bc.procInterrupt.Store(true)
} }
// insertStopped returns true after StopInsert has been called. // insertStopped returns true after StopInsert has been called.
func (bc *BlockChain) insertStopped() bool { func (bc *BlockChain) insertStopped() bool {
return atomic.LoadInt32(&bc.procInterrupt) == 1 return bc.procInterrupt.Load()
} }
func (bc *BlockChain) procFutureBlocks() { func (bc *BlockChain) procFutureBlocks() {
@ -1383,7 +1382,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
} }
// Find the next state trie we need to commit // Find the next state trie we need to commit
chosen := current - TriesInMemory chosen := current - TriesInMemory
flushInterval := time.Duration(atomic.LoadInt64(&bc.flushInterval)) flushInterval := time.Duration(bc.flushInterval.Load())
// If we exceeded time allowance, flush an entire trie to disk // If we exceeded time allowance, flush an entire trie to disk
// begin PluGeth code injection // begin PluGeth code injection
@ -1753,68 +1752,69 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
// If we have a followup block, run that against the current state to pre-cache // If we have a followup block, run that against the current state to pre-cache
// transactions and probabilistically some of the account/storage trie nodes. // transactions and probabilistically some of the account/storage trie nodes.
var followupInterrupt uint32 var followupInterrupt atomic.Bool
if !bc.cacheConfig.TrieCleanNoPrefetch { if !bc.cacheConfig.TrieCleanNoPrefetch {
if followup, err := it.peek(); followup != nil && err == nil { if followup, err := it.peek(); followup != nil && err == nil {
throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps) throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps)
go func(start time.Time, followup *types.Block, throwaway *state.StateDB, interrupt *uint32) { go func(start time.Time, followup *types.Block, throwaway *state.StateDB) {
bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt)
blockPrefetchExecuteTimer.Update(time.Since(start)) blockPrefetchExecuteTimer.Update(time.Since(start))
if atomic.LoadUint32(interrupt) == 1 { if followupInterrupt.Load() {
blockPrefetchInterruptMeter.Mark(1) blockPrefetchInterruptMeter.Mark(1)
} }
}(time.Now(), followup, throwaway, &followupInterrupt) }(time.Now(), followup, throwaway)
} }
} }
// Process block using the parent state as reference point // Process block using the parent state as reference point
substart := time.Now() pstart := time.Now()
receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
if err != nil { if err != nil {
bc.reportBlock(block, receipts, err) bc.reportBlock(block, receipts, err)
atomic.StoreUint32(&followupInterrupt, 1) followupInterrupt.Store(true)
return it.index, err return it.index, err
} }
ptime := time.Since(pstart)
// Update the metrics touched during block processing vstart := time.Now()
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete, we can mark them
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete, we can mark them
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete, we can mark them
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete, we can mark them
snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete, we can mark them
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete, we can mark them
triehash := statedb.AccountHashes + statedb.StorageHashes // Save to not double count in validation
trieproc := statedb.SnapshotAccountReads + statedb.AccountReads + statedb.AccountUpdates
trieproc += statedb.SnapshotStorageReads + statedb.StorageReads + statedb.StorageUpdates
blockExecutionTimer.Update(time.Since(substart) - trieproc - triehash)
// Validate the state using the default validator
substart = time.Now()
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
bc.reportBlock(block, receipts, err) bc.reportBlock(block, receipts, err)
atomic.StoreUint32(&followupInterrupt, 1) followupInterrupt.Store(true)
return it.index, err return it.index, err
} }
proctime := time.Since(start) vtime := time.Since(vstart)
proctime := time.Since(start) // processing + validation
// Update the metrics touched during block validation // Update the metrics touched during block processing and validation
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete, we can mark them accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete, we can mark them storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
blockValidationTimer.Update(time.Since(substart) - (statedb.AccountHashes + statedb.StorageHashes - triehash)) snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
// Write the block to the chain and get the status. // Write the block to the chain and get the status.
substart = time.Now() var (
var status WriteStatus wstart = time.Now()
status WriteStatus
)
if !setHead { if !setHead {
// Don't set the head, only insert the block // Don't set the head, only insert the block
err = bc.writeBlockWithState(block, receipts, statedb) err = bc.writeBlockWithState(block, receipts, statedb)
} else { } else {
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false) status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
} }
atomic.StoreUint32(&followupInterrupt, 1) followupInterrupt.Store(true)
if err != nil { if err != nil {
return it.index, err return it.index, err
} }
@ -1822,9 +1822,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them
storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them
snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them
triedbCommitTimer.Update(statedb.TrieDBCommits) // Triedb commits are complete, we can mark them triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them
blockWriteTimer.Update(time.Since(substart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
blockInsertTimer.UpdateSince(start) blockInsertTimer.UpdateSince(start)
// Report the import stats before returning the various results // Report the import stats before returning the various results
@ -2525,5 +2525,5 @@ func (bc *BlockChain) SetBlockValidatorAndProcessorForTesting(v Validator, p Pro
// The interval is in terms of block processing time, not wall clock. // The interval is in terms of block processing time, not wall clock.
// It is thread-safe and can be called repeatedly without side effects. // It is thread-safe and can be called repeatedly without side effects.
func (bc *BlockChain) SetTrieFlushInterval(interval time.Duration) { func (bc *BlockChain) SetTrieFlushInterval(interval time.Duration) {
atomic.StoreInt64(&bc.flushInterval, int64(interval)) bc.flushInterval.Store(int64(interval))
} }

View File

@ -3024,7 +3024,6 @@ func TestDeleteRecreateSlots(t *testing.T) {
}) })
// Import the canonical chain // Import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{
Debug: true,
Tracer: logger.NewJSONLogger(nil, os.Stdout), Tracer: logger.NewJSONLogger(nil, os.Stdout),
}, nil, nil) }, nil, nil)
if err != nil { if err != nil {
@ -3102,7 +3101,6 @@ func TestDeleteRecreateAccount(t *testing.T) {
}) })
// Import the canonical chain // Import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{ chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{
Debug: true,
Tracer: logger.NewJSONLogger(nil, os.Stdout), Tracer: logger.NewJSONLogger(nil, os.Stdout),
}, nil, nil) }, nil, nil)
if err != nil { if err != nil {

View File

@ -83,7 +83,7 @@ type Matcher struct {
retrievals chan chan *Retrieval // Retriever processes waiting for task allocations retrievals chan chan *Retrieval // Retriever processes waiting for task allocations
deliveries chan *Retrieval // Retriever processes waiting for task response deliveries deliveries chan *Retrieval // Retriever processes waiting for task response deliveries
running uint32 // Atomic flag whether a session is live or not running atomic.Bool // Atomic flag whether a session is live or not
} }
// NewMatcher creates a new pipeline for retrieving bloom bit streams and doing // NewMatcher creates a new pipeline for retrieving bloom bit streams and doing
@ -146,10 +146,10 @@ func (m *Matcher) addScheduler(idx uint) {
// channel is closed. // channel is closed.
func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uint64) (*MatcherSession, error) { func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uint64) (*MatcherSession, error) {
// Make sure we're not creating concurrent sessions // Make sure we're not creating concurrent sessions
if atomic.SwapUint32(&m.running, 1) == 1 { if m.running.Swap(true) {
return nil, errors.New("matcher already running") return nil, errors.New("matcher already running")
} }
defer atomic.StoreUint32(&m.running, 0) defer m.running.Store(false)
// Initiate a new matching round // Initiate a new matching round
session := &MatcherSession{ session := &MatcherSession{

View File

@ -160,7 +160,7 @@ func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, in
} }
} }
// Track the number of retrieval requests made // Track the number of retrieval requests made
var requested uint32 var requested atomic.Uint32
// Start the matching session for the filter and the retriever goroutines // Start the matching session for the filter and the retriever goroutines
quit := make(chan struct{}) quit := make(chan struct{})
@ -208,15 +208,15 @@ func testMatcher(t *testing.T, filter [][]bloomIndexes, start, blocks uint64, in
session.Close() session.Close()
close(quit) close(quit)
if retrievals != 0 && requested != retrievals { if retrievals != 0 && requested.Load() != retrievals {
t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, have #%v, want #%v", filter, blocks, intermittent, requested, retrievals) t.Errorf("filter = %v blocks = %v intermittent = %v: request count mismatch, have #%v, want #%v", filter, blocks, intermittent, requested.Load(), retrievals)
} }
return requested return requested.Load()
} }
// startRetrievers starts a batch of goroutines listening for section requests // startRetrievers starts a batch of goroutines listening for section requests
// and serving them. // and serving them.
func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *uint32, batch int) { func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *atomic.Uint32, batch int) {
requests := make(chan chan *Retrieval) requests := make(chan chan *Retrieval)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
@ -238,7 +238,7 @@ func startRetrievers(session *MatcherSession, quit chan struct{}, retrievals *ui
for i, section := range task.Sections { for i, section := range task.Sections {
if rand.Int()%4 != 0 { // Handle occasional missing deliveries if rand.Int()%4 != 0 { // Handle occasional missing deliveries
task.Bitsets[i] = generateBitset(task.Bit, section) task.Bitsets[i] = generateBitset(task.Bit, section)
atomic.AddUint32(retrievals, 1) retrievals.Add(1)
} }
} }
request <- task request <- task

View File

@ -45,13 +45,13 @@ func testScheduler(t *testing.T, clients int, fetchers int, requests int) {
fetch := make(chan *request, 16) fetch := make(chan *request, 16)
defer close(fetch) defer close(fetch)
var delivered uint32 var delivered atomic.Uint32
for i := 0; i < fetchers; i++ { for i := 0; i < fetchers; i++ {
go func() { go func() {
defer fetchPend.Done() defer fetchPend.Done()
for req := range fetch { for req := range fetch {
atomic.AddUint32(&delivered, 1) delivered.Add(1)
f.deliver([]uint64{ f.deliver([]uint64{
req.section + uint64(requests), // Non-requested data (ensure it doesn't go out of bounds) req.section + uint64(requests), // Non-requested data (ensure it doesn't go out of bounds)
@ -97,7 +97,7 @@ func testScheduler(t *testing.T, clients int, fetchers int, requests int) {
} }
pend.Wait() pend.Wait()
if have := atomic.LoadUint32(&delivered); int(have) != requests { if have := delivered.Load(); int(have) != requests {
t.Errorf("request count mismatch: have %v, want %v", have, requests) t.Errorf("request count mismatch: have %v, want %v", have, requests)
} }
} }

View File

@ -75,7 +75,7 @@ type ChainIndexer struct {
backend ChainIndexerBackend // Background processor generating the index data content backend ChainIndexerBackend // Background processor generating the index data content
children []*ChainIndexer // Child indexers to cascade chain updates to children []*ChainIndexer // Child indexers to cascade chain updates to
active uint32 // Flag whether the event loop was started active atomic.Bool // Flag whether the event loop was started
update chan struct{} // Notification channel that headers should be processed update chan struct{} // Notification channel that headers should be processed
quit chan chan error // Quit channel to tear down running goroutines quit chan chan error // Quit channel to tear down running goroutines
ctx context.Context ctx context.Context
@ -166,7 +166,7 @@ func (c *ChainIndexer) Close() error {
errs = append(errs, err) errs = append(errs, err)
} }
// If needed, tear down the secondary event loop // If needed, tear down the secondary event loop
if atomic.LoadUint32(&c.active) != 0 { if c.active.Load() {
c.quit <- errc c.quit <- errc
if err := <-errc; err != nil { if err := <-errc; err != nil {
errs = append(errs, err) errs = append(errs, err)
@ -196,7 +196,7 @@ func (c *ChainIndexer) Close() error {
// queue. // queue.
func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainHeadEvent, sub event.Subscription) { func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainHeadEvent, sub event.Subscription) {
// Mark the chain indexer as active, requiring an additional teardown // Mark the chain indexer as active, requiring an additional teardown
atomic.StoreUint32(&c.active, 1) c.active.Store(true)
defer sub.Unsubscribe() defer sub.Unsubscribe()

View File

@ -45,9 +45,10 @@ func (h *testHasher) Reset() {
h.hasher.Reset() h.hasher.Reset()
} }
func (h *testHasher) Update(key, val []byte) { func (h *testHasher) Update(key, val []byte) error {
h.hasher.Write(key) h.hasher.Write(key)
h.hasher.Write(val) h.hasher.Write(val)
return nil
} }
func (h *testHasher) Hash() common.Hash { func (h *testHasher) Hash() common.Hash {

View File

@ -43,10 +43,7 @@ const (
// The background thread will keep moving ancient chain segments from key-value // The background thread will keep moving ancient chain segments from key-value
// database to flat files for saving space on live database. // database to flat files for saving space on live database.
type chainFreezer struct { type chainFreezer struct {
// WARNING: The `threshold` field is accessed atomically. On 32 bit platforms, only threshold atomic.Uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests)
// 64-bit aligned fields can be atomic. The struct is guaranteed to be so aligned,
// so take advantage of that (https://golang.org/pkg/sync/atomic/#pkg-note-BUG).
threshold uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests)
*Freezer *Freezer
quit chan struct{} quit chan struct{}
@ -60,12 +57,13 @@ func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFre
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &chainFreezer{ cf := chainFreezer{
Freezer: freezer, Freezer: freezer,
threshold: params.FullImmutabilityThreshold,
quit: make(chan struct{}), quit: make(chan struct{}),
trigger: make(chan chan struct{}), trigger: make(chan chan struct{}),
}, nil }
cf.threshold.Store(params.FullImmutabilityThreshold)
return &cf, nil
} }
// Close closes the chain freezer instance and terminates the background thread. // Close closes the chain freezer instance and terminates the background thread.
@ -124,8 +122,8 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
continue continue
} }
number := ReadHeaderNumber(nfdb, hash) number := ReadHeaderNumber(nfdb, hash)
threshold := atomic.LoadUint64(&f.threshold) threshold := f.threshold.Load()
frozen := atomic.LoadUint64(&f.frozen) frozen := f.frozen.Load()
switch { switch {
case number == nil: case number == nil:
log.Error("Current full block number unavailable", "hash", hash) log.Error("Current full block number unavailable", "hash", hash)
@ -186,7 +184,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
// Wipe out side chains also and track dangling side chains // Wipe out side chains also and track dangling side chains
var dangling []common.Hash var dangling []common.Hash
frozen = atomic.LoadUint64(&f.frozen) // Needs reload after during freezeRange frozen = f.frozen.Load() // Needs reload after during freezeRange
for number := first; number < frozen; number++ { for number := first; number < frozen; number++ {
// Always keep the genesis block in active database // Always keep the genesis block in active database
if number != 0 { if number != 0 {

View File

@ -132,11 +132,12 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool
} }
} }
// process runs in parallel // process runs in parallel
nThreadsAlive := int32(threads) var nThreadsAlive atomic.Int32
nThreadsAlive.Store(int32(threads))
process := func() { process := func() {
defer func() { defer func() {
// Last processor closes the result channel // Last processor closes the result channel
if atomic.AddInt32(&nThreadsAlive, -1) == 0 { if nThreadsAlive.Add(-1) == 0 {
close(hashesCh) close(hashesCh)
} }
}() }()

View File

@ -24,7 +24,6 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -72,9 +71,9 @@ func (frdb *freezerdb) Freeze(threshold uint64) error {
} }
// Set the freezer threshold to a temporary value // Set the freezer threshold to a temporary value
defer func(old uint64) { defer func(old uint64) {
atomic.StoreUint64(&frdb.AncientStore.(*chainFreezer).threshold, old) frdb.AncientStore.(*chainFreezer).threshold.Store(old)
}(atomic.LoadUint64(&frdb.AncientStore.(*chainFreezer).threshold)) }(frdb.AncientStore.(*chainFreezer).threshold.Load())
atomic.StoreUint64(&frdb.AncientStore.(*chainFreezer).threshold, threshold) frdb.AncientStore.(*chainFreezer).threshold.Store(threshold)
// Trigger a freeze cycle and block until it's done // Trigger a freeze cycle and block until it's done
trigger := make(chan struct{}, 1) trigger := make(chan struct{}, 1)

View File

@ -62,11 +62,8 @@ const freezerTableSize = 2 * 1000 * 1000 * 1000
// reserving it for go-ethereum. This would also reduce the memory requirements // reserving it for go-ethereum. This would also reduce the memory requirements
// of Geth, and thus also GC overhead. // of Geth, and thus also GC overhead.
type Freezer struct { type Freezer struct {
// WARNING: The `frozen` and `tail` fields are accessed atomically. On 32 bit platforms, only frozen atomic.Uint64 // Number of blocks already frozen
// 64-bit aligned fields can be atomic. The struct is guaranteed to be so aligned, tail atomic.Uint64 // Number of the first stored item in the freezer
// so take advantage of that (https://golang.org/pkg/sync/atomic/#pkg-note-BUG).
frozen uint64 // Number of blocks already frozen
tail uint64 // Number of the first stored item in the freezer
// This lock synchronizes writers and the truncate operation, as well as // This lock synchronizes writers and the truncate operation, as well as
// the "atomic" (batched) read operations. // the "atomic" (batched) read operations.
@ -212,12 +209,12 @@ func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]
// Ancients returns the length of the frozen items. // Ancients returns the length of the frozen items.
func (f *Freezer) Ancients() (uint64, error) { func (f *Freezer) Ancients() (uint64, error) {
return atomic.LoadUint64(&f.frozen), nil return f.frozen.Load(), nil
} }
// Tail returns the number of first stored item in the freezer. // Tail returns the number of first stored item in the freezer.
func (f *Freezer) Tail() (uint64, error) { func (f *Freezer) Tail() (uint64, error) {
return atomic.LoadUint64(&f.tail), nil return f.tail.Load(), nil
} }
// AncientSize returns the ancient size of the specified category. // AncientSize returns the ancient size of the specified category.
@ -251,7 +248,7 @@ func (f *Freezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize
defer f.writeLock.Unlock() defer f.writeLock.Unlock()
// Roll back all tables to the starting position in case of error. // Roll back all tables to the starting position in case of error.
prevItem := atomic.LoadUint64(&f.frozen) prevItem := f.frozen.Load()
defer func() { defer func() {
if err != nil { if err != nil {
// The write operation has failed. Go back to the previous item position. // The write operation has failed. Go back to the previous item position.
@ -275,7 +272,8 @@ func (f *Freezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize
//begin PluGeth code injection //begin PluGeth code injection
pluginCommitUpdate(item) pluginCommitUpdate(item)
//end PluGeth code injection //end PluGeth code injection
atomic.StoreUint64(&f.frozen, item) // atomic.StoreUint64(*f.frozen, item)
f.frozen.Store(item)
return writeSize, nil return writeSize, nil
} }
@ -287,7 +285,7 @@ func (f *Freezer) TruncateHead(items uint64) error {
f.writeLock.Lock() f.writeLock.Lock()
defer f.writeLock.Unlock() defer f.writeLock.Unlock()
if atomic.LoadUint64(&f.frozen) <= items { if f.frozen.Load() <= items {
return nil return nil
} }
for _, table := range f.tables { for _, table := range f.tables {
@ -295,7 +293,7 @@ func (f *Freezer) TruncateHead(items uint64) error {
return err return err
} }
} }
atomic.StoreUint64(&f.frozen, items) f.frozen.Store(items)
return nil return nil
} }
@ -307,7 +305,7 @@ func (f *Freezer) TruncateTail(tail uint64) error {
f.writeLock.Lock() f.writeLock.Lock()
defer f.writeLock.Unlock() defer f.writeLock.Unlock()
if atomic.LoadUint64(&f.tail) >= tail { if f.tail.Load() >= tail {
return nil return nil
} }
for _, table := range f.tables { for _, table := range f.tables {
@ -315,7 +313,7 @@ func (f *Freezer) TruncateTail(tail uint64) error {
return err return err
} }
} }
atomic.StoreUint64(&f.tail, tail) f.tail.Store(tail)
return nil return nil
} }
@ -346,22 +344,22 @@ func (f *Freezer) validate() error {
) )
// Hack to get boundary of any table // Hack to get boundary of any table
for kind, table := range f.tables { for kind, table := range f.tables {
head = atomic.LoadUint64(&table.items) head = table.items.Load()
tail = atomic.LoadUint64(&table.itemHidden) tail = table.itemHidden.Load()
name = kind name = kind
break break
} }
// Now check every table against those boundaries. // Now check every table against those boundaries.
for kind, table := range f.tables { for kind, table := range f.tables {
if head != atomic.LoadUint64(&table.items) { if head != table.items.Load() {
return fmt.Errorf("freezer tables %s and %s have differing head: %d != %d", kind, name, atomic.LoadUint64(&table.items), head) return fmt.Errorf("freezer tables %s and %s have differing head: %d != %d", kind, name, table.items.Load(), head)
} }
if tail != atomic.LoadUint64(&table.itemHidden) { if tail != table.itemHidden.Load() {
return fmt.Errorf("freezer tables %s and %s have differing tail: %d != %d", kind, name, atomic.LoadUint64(&table.itemHidden), tail) return fmt.Errorf("freezer tables %s and %s have differing tail: %d != %d", kind, name, table.itemHidden.Load(), tail)
} }
} }
atomic.StoreUint64(&f.frozen, head) f.frozen.Store(head)
atomic.StoreUint64(&f.tail, tail) f.tail.Store(tail)
return nil return nil
} }
@ -372,11 +370,11 @@ func (f *Freezer) repair() error {
tail = uint64(0) tail = uint64(0)
) )
for _, table := range f.tables { for _, table := range f.tables {
items := atomic.LoadUint64(&table.items) items := table.items.Load()
if head > items { if head > items {
head = items head = items
} }
hidden := atomic.LoadUint64(&table.itemHidden) hidden := table.itemHidden.Load()
if hidden > tail { if hidden > tail {
tail = hidden tail = hidden
} }
@ -389,8 +387,8 @@ func (f *Freezer) repair() error {
return err return err
} }
} }
atomic.StoreUint64(&f.frozen, head) f.frozen.Store(head)
atomic.StoreUint64(&f.tail, tail) f.tail.Store(tail)
return nil return nil
} }
@ -416,7 +414,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error {
// and that error will be returned. // and that error will be returned.
forEach := func(t *freezerTable, offset uint64, fn func(uint64, []byte) error) error { forEach := func(t *freezerTable, offset uint64, fn func(uint64, []byte) error) error {
var ( var (
items = atomic.LoadUint64(&t.items) items = t.items.Load()
batchSize = uint64(1024) batchSize = uint64(1024)
maxBytes = uint64(1024 * 1024) maxBytes = uint64(1024 * 1024)
) )
@ -439,7 +437,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error {
} }
// TODO(s1na): This is a sanity-check since as of now no process does tail-deletion. But the migration // TODO(s1na): This is a sanity-check since as of now no process does tail-deletion. But the migration
// process assumes no deletion at tail and needs to be modified to account for that. // process assumes no deletion at tail and needs to be modified to account for that.
if table.itemOffset > 0 || table.itemHidden > 0 { if table.itemOffset.Load() > 0 || table.itemHidden.Load() > 0 {
return fmt.Errorf("migration not supported for tail-deleted freezers") return fmt.Errorf("migration not supported for tail-deleted freezers")
} }
ancientsPath := filepath.Dir(table.index.Name()) ancientsPath := filepath.Dir(table.index.Name())
@ -455,7 +453,7 @@ func (f *Freezer) MigrateTable(kind string, convert convertLegacyFn) error {
out []byte out []byte
start = time.Now() start = time.Now()
logged = time.Now() logged = time.Now()
offset = newTable.items offset = newTable.items.Load()
) )
if offset > 0 { if offset > 0 {
log.Info("found previous migration attempt", "migrated", offset) log.Info("found previous migration attempt", "migrated", offset)

View File

@ -18,7 +18,6 @@ package rawdb
import ( import (
"fmt" "fmt"
"sync/atomic"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
@ -119,7 +118,7 @@ func (t *freezerTable) newBatch() *freezerTableBatch {
func (batch *freezerTableBatch) reset() { func (batch *freezerTableBatch) reset() {
batch.dataBuffer = batch.dataBuffer[:0] batch.dataBuffer = batch.dataBuffer[:0]
batch.indexBuffer = batch.indexBuffer[:0] batch.indexBuffer = batch.indexBuffer[:0]
batch.curItem = atomic.LoadUint64(&batch.t.items) batch.curItem = batch.t.items.Load()
batch.totalBytes = 0 batch.totalBytes = 0
} }
@ -213,7 +212,7 @@ func (batch *freezerTableBatch) commit() error {
// Update headBytes of table. // Update headBytes of table.
batch.t.headBytes += dataSize batch.t.headBytes += dataSize
atomic.StoreUint64(&batch.t.items, batch.curItem) batch.t.items.Store(batch.curItem)
// Update metrics. // Update metrics.
batch.t.sizeGauge.Inc(dataSize + indexSize) batch.t.sizeGauge.Inc(dataSize + indexSize)

View File

@ -88,18 +88,15 @@ func (i *indexEntry) bounds(end *indexEntry) (startOffset, endOffset, fileId uin
// It consists of a data file (snappy encoded arbitrary data blobs) and an indexEntry // It consists of a data file (snappy encoded arbitrary data blobs) and an indexEntry
// file (uncompressed 64 bit indices into the data file). // file (uncompressed 64 bit indices into the data file).
type freezerTable struct { type freezerTable struct {
// WARNING: The `items` field is accessed atomically. On 32 bit platforms, only items atomic.Uint64 // Number of items stored in the table (including items removed from tail)
// 64-bit aligned fields can be atomic. The struct is guaranteed to be so aligned, itemOffset atomic.Uint64 // Number of items removed from the table
// so take advantage of that (https://golang.org/pkg/sync/atomic/#pkg-note-BUG).
items uint64 // Number of items stored in the table (including items removed from tail)
itemOffset uint64 // Number of items removed from the table
// itemHidden is the number of items marked as deleted. Tail deletion is // itemHidden is the number of items marked as deleted. Tail deletion is
// only supported at file level which means the actual deletion will be // only supported at file level which means the actual deletion will be
// delayed until the entire data file is marked as deleted. Before that // delayed until the entire data file is marked as deleted. Before that
// these items will be hidden to prevent being visited again. The value // these items will be hidden to prevent being visited again. The value
// should never be lower than itemOffset. // should never be lower than itemOffset.
itemHidden uint64 itemHidden atomic.Uint64
noCompression bool // if true, disables snappy compression. Note: does not work retroactively noCompression bool // if true, disables snappy compression. Note: does not work retroactively
readonly bool readonly bool
@ -241,14 +238,14 @@ func (t *freezerTable) repair() error {
// which is not enough in theory but enough in practice. // which is not enough in theory but enough in practice.
// TODO: use uint64 to represent total removed items. // TODO: use uint64 to represent total removed items.
t.tailId = firstIndex.filenum t.tailId = firstIndex.filenum
t.itemOffset = uint64(firstIndex.offset) t.itemOffset.Store(uint64(firstIndex.offset))
// Load metadata from the file // Load metadata from the file
meta, err := loadMetadata(t.meta, t.itemOffset) meta, err := loadMetadata(t.meta, t.itemOffset.Load())
if err != nil { if err != nil {
return err return err
} }
t.itemHidden = meta.VirtualTail t.itemHidden.Store(meta.VirtualTail)
// Read the last index, use the default value in case the freezer is empty // Read the last index, use the default value in case the freezer is empty
if offsetsSize == indexEntrySize { if offsetsSize == indexEntrySize {
@ -331,7 +328,7 @@ func (t *freezerTable) repair() error {
} }
} }
// Update the item and byte counters and return // Update the item and byte counters and return
t.items = t.itemOffset + uint64(offsetsSize/indexEntrySize-1) // last indexEntry points to the end of the data file t.items.Store(t.itemOffset.Load() + uint64(offsetsSize/indexEntrySize-1)) // last indexEntry points to the end of the data file
t.headBytes = contentSize t.headBytes = contentSize
t.headId = lastIndex.filenum t.headId = lastIndex.filenum
@ -346,9 +343,9 @@ func (t *freezerTable) repair() error {
return err return err
} }
if verbose { if verbose {
t.logger.Info("Chain freezer table opened", "items", t.items, "size", t.headBytes) t.logger.Info("Chain freezer table opened", "items", t.items.Load(), "size", t.headBytes)
} else { } else {
t.logger.Debug("Chain freezer table opened", "items", t.items, "size", common.StorageSize(t.headBytes)) t.logger.Debug("Chain freezer table opened", "items", t.items.Load(), "size", common.StorageSize(t.headBytes))
} }
return nil return nil
} }
@ -382,11 +379,11 @@ func (t *freezerTable) truncateHead(items uint64) error {
defer t.lock.Unlock() defer t.lock.Unlock()
// Ensure the given truncate target falls in the correct range // Ensure the given truncate target falls in the correct range
existing := atomic.LoadUint64(&t.items) existing := t.items.Load()
if existing <= items { if existing <= items {
return nil return nil
} }
if items < atomic.LoadUint64(&t.itemHidden) { if items < t.itemHidden.Load() {
return errors.New("truncation below tail") return errors.New("truncation below tail")
} }
// We need to truncate, save the old size for metrics tracking // We need to truncate, save the old size for metrics tracking
@ -403,7 +400,7 @@ func (t *freezerTable) truncateHead(items uint64) error {
// Truncate the index file first, the tail position is also considered // Truncate the index file first, the tail position is also considered
// when calculating the new freezer table length. // when calculating the new freezer table length.
length := items - atomic.LoadUint64(&t.itemOffset) length := items - t.itemOffset.Load()
if err := truncateFreezerFile(t.index, int64(length+1)*indexEntrySize); err != nil { if err := truncateFreezerFile(t.index, int64(length+1)*indexEntrySize); err != nil {
return err return err
} }
@ -438,7 +435,7 @@ func (t *freezerTable) truncateHead(items uint64) error {
} }
// All data files truncated, set internal counters and return // All data files truncated, set internal counters and return
t.headBytes = int64(expected.offset) t.headBytes = int64(expected.offset)
atomic.StoreUint64(&t.items, items) t.items.Store(items)
// Retrieve the new size and update the total size counter // Retrieve the new size and update the total size counter
newSize, err := t.sizeNolock() newSize, err := t.sizeNolock()
@ -455,10 +452,10 @@ func (t *freezerTable) truncateTail(items uint64) error {
defer t.lock.Unlock() defer t.lock.Unlock()
// Ensure the given truncate target falls in the correct range // Ensure the given truncate target falls in the correct range
if atomic.LoadUint64(&t.itemHidden) >= items { if t.itemHidden.Load() >= items {
return nil return nil
} }
if atomic.LoadUint64(&t.items) < items { if t.items.Load() < items {
return errors.New("truncation above head") return errors.New("truncation above head")
} }
// Load the new tail index by the given new tail position // Load the new tail index by the given new tail position
@ -466,10 +463,10 @@ func (t *freezerTable) truncateTail(items uint64) error {
newTailId uint32 newTailId uint32
buffer = make([]byte, indexEntrySize) buffer = make([]byte, indexEntrySize)
) )
if atomic.LoadUint64(&t.items) == items { if t.items.Load() == items {
newTailId = t.headId newTailId = t.headId
} else { } else {
offset := items - atomic.LoadUint64(&t.itemOffset) offset := items - t.itemOffset.Load()
if _, err := t.index.ReadAt(buffer, int64((offset+1)*indexEntrySize)); err != nil { if _, err := t.index.ReadAt(buffer, int64((offset+1)*indexEntrySize)); err != nil {
return err return err
} }
@ -478,7 +475,7 @@ func (t *freezerTable) truncateTail(items uint64) error {
newTailId = newTail.filenum newTailId = newTail.filenum
} }
// Update the virtual tail marker and hidden these entries in table. // Update the virtual tail marker and hidden these entries in table.
atomic.StoreUint64(&t.itemHidden, items) t.itemHidden.Store(items)
if err := writeMetadata(t.meta, newMetadata(items)); err != nil { if err := writeMetadata(t.meta, newMetadata(items)); err != nil {
return err return err
} }
@ -501,7 +498,7 @@ func (t *freezerTable) truncateTail(items uint64) error {
// Count how many items can be deleted from the file. // Count how many items can be deleted from the file.
var ( var (
newDeleted = items newDeleted = items
deleted = atomic.LoadUint64(&t.itemOffset) deleted = t.itemOffset.Load()
) )
for current := items - 1; current >= deleted; current -= 1 { for current := items - 1; current >= deleted; current -= 1 {
if _, err := t.index.ReadAt(buffer, int64((current-deleted+1)*indexEntrySize)); err != nil { if _, err := t.index.ReadAt(buffer, int64((current-deleted+1)*indexEntrySize)); err != nil {
@ -541,7 +538,7 @@ func (t *freezerTable) truncateTail(items uint64) error {
} }
// Release any files before the current tail // Release any files before the current tail
t.tailId = newTailId t.tailId = newTailId
atomic.StoreUint64(&t.itemOffset, newDeleted) t.itemOffset.Store(newDeleted)
t.releaseFilesBefore(t.tailId, true) t.releaseFilesBefore(t.tailId, true)
// Retrieve the new size and update the total size counter // Retrieve the new size and update the total size counter
@ -654,7 +651,7 @@ func (t *freezerTable) releaseFilesBefore(num uint32, remove bool) {
// it will return error. // it will return error.
func (t *freezerTable) getIndices(from, count uint64) ([]*indexEntry, error) { func (t *freezerTable) getIndices(from, count uint64) ([]*indexEntry, error) {
// Apply the table-offset // Apply the table-offset
from = from - t.itemOffset from = from - t.itemOffset.Load()
// For reading N items, we need N+1 indices. // For reading N items, we need N+1 indices.
buffer := make([]byte, (count+1)*indexEntrySize) buffer := make([]byte, (count+1)*indexEntrySize)
if _, err := t.index.ReadAt(buffer, int64(from*indexEntrySize)); err != nil { if _, err := t.index.ReadAt(buffer, int64(from*indexEntrySize)); err != nil {
@ -744,8 +741,8 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i
return nil, nil, errClosed return nil, nil, errClosed
} }
var ( var (
items = atomic.LoadUint64(&t.items) // the total items(head + 1) items = t.items.Load() // the total items(head + 1)
hidden = atomic.LoadUint64(&t.itemHidden) // the number of hidden items hidden = t.itemHidden.Load() // the number of hidden items
) )
// Ensure the start is written, not deleted from the tail, and that the // Ensure the start is written, not deleted from the tail, and that the
// caller actually wants something // caller actually wants something
@ -826,13 +823,16 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i
break break
} }
} }
// Update metrics.
t.readMeter.Mark(int64(totalSize))
return output[:outputSize], sizes, nil return output[:outputSize], sizes, nil
} }
// has returns an indicator whether the specified number data is still accessible // has returns an indicator whether the specified number data is still accessible
// in the freezer table. // in the freezer table.
func (t *freezerTable) has(number uint64) bool { func (t *freezerTable) has(number uint64) bool {
return atomic.LoadUint64(&t.items) > number && atomic.LoadUint64(&t.itemHidden) <= number return t.items.Load() > number && t.itemHidden.Load() <= number
} }
// size returns the total data size in the freezer table. // size returns the total data size in the freezer table.
@ -922,7 +922,7 @@ func (t *freezerTable) dumpIndex(w io.Writer, start, stop int64) {
return return
} }
fmt.Fprintf(w, "Version %d count %d, deleted %d, hidden %d\n", meta.Version, fmt.Fprintf(w, "Version %d count %d, deleted %d, hidden %d\n", meta.Version,
atomic.LoadUint64(&t.items), atomic.LoadUint64(&t.itemOffset), atomic.LoadUint64(&t.itemHidden)) t.items.Load(), t.itemOffset.Load(), t.itemHidden.Load())
buf := make([]byte, indexEntrySize) buf := make([]byte, indexEntrySize)

View File

@ -24,7 +24,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"sync/atomic"
"testing" "testing"
"testing/quick" "testing/quick"
@ -191,7 +190,7 @@ func TestFreezerRepairDanglingHeadLarge(t *testing.T) {
writeChunks(t, f, 255, 15) writeChunks(t, f, 255, 15)
// The last item should be there // The last item should be there
if _, err = f.Retrieve(f.items - 1); err != nil { if _, err = f.Retrieve(f.items.Load() - 1); err != nil {
t.Fatal(err) t.Fatal(err)
} }
f.Close() f.Close()
@ -317,7 +316,7 @@ func TestFreezerRepairDanglingIndex(t *testing.T) {
writeChunks(t, f, 9, 15) writeChunks(t, f, 9, 15)
// The last item should be there // The last item should be there
if _, err = f.Retrieve(f.items - 1); err != nil { if _, err = f.Retrieve(f.items.Load() - 1); err != nil {
f.Close() f.Close()
t.Fatal(err) t.Fatal(err)
} }
@ -350,8 +349,8 @@ func TestFreezerRepairDanglingIndex(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer f.Close() defer f.Close()
if f.items != 7 { if f.items.Load() != 7 {
t.Fatalf("expected %d items, got %d", 7, f.items) t.Fatalf("expected %d items, got %d", 7, f.items.Load())
} }
if err := assertFileSize(fileToCrop, 15); err != nil { if err := assertFileSize(fileToCrop, 15); err != nil {
t.Fatal(err) t.Fatal(err)
@ -374,7 +373,7 @@ func TestFreezerTruncate(t *testing.T) {
writeChunks(t, f, 30, 15) writeChunks(t, f, 30, 15)
// The last item should be there // The last item should be there
if _, err = f.Retrieve(f.items - 1); err != nil { if _, err = f.Retrieve(f.items.Load() - 1); err != nil {
t.Fatal(err) t.Fatal(err)
} }
f.Close() f.Close()
@ -388,8 +387,8 @@ func TestFreezerTruncate(t *testing.T) {
} }
defer f.Close() defer f.Close()
f.truncateHead(10) // 150 bytes f.truncateHead(10) // 150 bytes
if f.items != 10 { if f.items.Load() != 10 {
t.Fatalf("expected %d items, got %d", 10, f.items) t.Fatalf("expected %d items, got %d", 10, f.items.Load())
} }
// 45, 45, 45, 15 -- bytes should be 15 // 45, 45, 45, 15 -- bytes should be 15
if f.headBytes != 15 { if f.headBytes != 15 {
@ -444,9 +443,9 @@ func TestFreezerRepairFirstFile(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if f.items != 1 { if f.items.Load() != 1 {
f.Close() f.Close()
t.Fatalf("expected %d items, got %d", 0, f.items) t.Fatalf("expected %d items, got %d", 0, f.items.Load())
} }
// Write 40 bytes // Write 40 bytes
@ -483,7 +482,7 @@ func TestFreezerReadAndTruncate(t *testing.T) {
writeChunks(t, f, 30, 15) writeChunks(t, f, 30, 15)
// The last item should be there // The last item should be there
if _, err = f.Retrieve(f.items - 1); err != nil { if _, err = f.Retrieve(f.items.Load() - 1); err != nil {
t.Fatal(err) t.Fatal(err)
} }
f.Close() f.Close()
@ -495,9 +494,9 @@ func TestFreezerReadAndTruncate(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if f.items != 30 { if f.items.Load() != 30 {
f.Close() f.Close()
t.Fatalf("expected %d items, got %d", 0, f.items) t.Fatalf("expected %d items, got %d", 0, f.items.Load())
} }
for y := byte(0); y < 30; y++ { for y := byte(0); y < 30; y++ {
f.Retrieve(uint64(y)) f.Retrieve(uint64(y))
@ -1210,13 +1209,13 @@ func runRandTest(rt randTest) bool {
rt[i].err = fmt.Errorf("failed to reload table %v", err) rt[i].err = fmt.Errorf("failed to reload table %v", err)
} }
case opCheckAll: case opCheckAll:
tail := atomic.LoadUint64(&f.itemHidden) tail := f.itemHidden.Load()
head := atomic.LoadUint64(&f.items) head := f.items.Load()
if tail == head { if tail == head {
continue continue
} }
got, err := f.RetrieveItems(atomic.LoadUint64(&f.itemHidden), head-tail, 100000) got, err := f.RetrieveItems(f.itemHidden.Load(), head-tail, 100000)
if err != nil { if err != nil {
rt[i].err = err rt[i].err = err
} else { } else {
@ -1238,7 +1237,7 @@ func runRandTest(rt randTest) bool {
if len(step.items) == 0 { if len(step.items) == 0 {
continue continue
} }
tail := atomic.LoadUint64(&f.itemHidden) tail := f.itemHidden.Load()
for i := 0; i < len(step.items); i++ { for i := 0; i < len(step.items); i++ {
blobs = append(blobs, values[step.items[i]-tail]) blobs = append(blobs, values[step.items[i]-tail])
} }
@ -1254,7 +1253,7 @@ func runRandTest(rt randTest) bool {
case opTruncateHead: case opTruncateHead:
f.truncateHead(step.target) f.truncateHead(step.target)
length := atomic.LoadUint64(&f.items) - atomic.LoadUint64(&f.itemHidden) length := f.items.Load() - f.itemHidden.Load()
values = values[:length] values = values[:length]
case opTruncateHeadAll: case opTruncateHeadAll:
@ -1262,10 +1261,10 @@ func runRandTest(rt randTest) bool {
values = nil values = nil
case opTruncateTail: case opTruncateTail:
prev := atomic.LoadUint64(&f.itemHidden) prev := f.itemHidden.Load()
f.truncateTail(step.target) f.truncateTail(step.target)
truncated := atomic.LoadUint64(&f.itemHidden) - prev truncated := f.itemHidden.Load() - prev
values = values[truncated:] values = values[truncated:]
case opTruncateTailAll: case opTruncateTailAll:

View File

@ -273,10 +273,10 @@ func TestFreezerReadonlyValidate(t *testing.T) {
bBatch := f.tables["b"].newBatch() bBatch := f.tables["b"].newBatch()
require.NoError(t, bBatch.AppendRaw(0, item)) require.NoError(t, bBatch.AppendRaw(0, item))
require.NoError(t, bBatch.commit()) require.NoError(t, bBatch.commit())
if f.tables["a"].items != 3 { if f.tables["a"].items.Load() != 3 {
t.Fatalf("unexpected number of items in table") t.Fatalf("unexpected number of items in table")
} }
if f.tables["b"].items != 1 { if f.tables["b"].items.Load() != 1 {
t.Fatalf("unexpected number of items in table") t.Fatalf("unexpected number of items in table")
} }
require.NoError(t, f.Close()) require.NoError(t, f.Close())

View File

@ -68,36 +68,36 @@ type Trie interface {
// TODO(fjl): remove this when StateTrie is removed // TODO(fjl): remove this when StateTrie is removed
GetKey([]byte) []byte GetKey([]byte) []byte
// TryGet returns the value for key stored in the trie. The value bytes must // GetStorage returns the value for key stored in the trie. The value bytes
// not be modified by the caller. If a node was not found in the database, a // must not be modified by the caller. If a node was not found in the database,
// trie.MissingNodeError is returned. // a trie.MissingNodeError is returned.
TryGet(key []byte) ([]byte, error) GetStorage(addr common.Address, key []byte) ([]byte, error)
// TryGetAccount abstracts an account read from the trie. It retrieves the // GetAccount abstracts an account read from the trie. It retrieves the
// account blob from the trie with provided account address and decodes it // account blob from the trie with provided account address and decodes it
// with associated decoding algorithm. If the specified account is not in // with associated decoding algorithm. If the specified account is not in
// the trie, nil will be returned. If the trie is corrupted(e.g. some nodes // the trie, nil will be returned. If the trie is corrupted(e.g. some nodes
// are missing or the account blob is incorrect for decoding), an error will // are missing or the account blob is incorrect for decoding), an error will
// be returned. // be returned.
TryGetAccount(address common.Address) (*types.StateAccount, error) GetAccount(address common.Address) (*types.StateAccount, error)
// TryUpdate associates key with value in the trie. If value has length zero, any // UpdateStorage associates key with value in the trie. If value has length zero,
// existing value is deleted from the trie. The value bytes must not be modified // any existing value is deleted from the trie. The value bytes must not be modified
// by the caller while they are stored in the trie. If a node was not found in the // by the caller while they are stored in the trie. If a node was not found in the
// database, a trie.MissingNodeError is returned. // database, a trie.MissingNodeError is returned.
TryUpdate(key, value []byte) error UpdateStorage(addr common.Address, key, value []byte) error
// TryUpdateAccount abstracts an account write to the trie. It encodes the // UpdateAccount abstracts an account write to the trie. It encodes the
// provided account object with associated algorithm and then updates it // provided account object with associated algorithm and then updates it
// in the trie with provided address. // in the trie with provided address.
TryUpdateAccount(address common.Address, account *types.StateAccount) error UpdateAccount(address common.Address, account *types.StateAccount) error
// TryDelete removes any existing value for key from the trie. If a node was not // DeleteStorage removes any existing value for key from the trie. If a node
// found in the database, a trie.MissingNodeError is returned. // was not found in the database, a trie.MissingNodeError is returned.
TryDelete(key []byte) error DeleteStorage(addr common.Address, key []byte) error
// TryDeleteAccount abstracts an account deletion from the trie. // DeleteAccount abstracts an account deletion from the trie.
TryDeleteAccount(address common.Address) error DeleteAccount(address common.Address) error
// Hash returns the root hash of the trie. It does not write to the database and // Hash returns the root hash of the trie. It does not write to the database and
// can be used even if the trie doesn't have one. // can be used even if the trie doesn't have one.

View File

@ -371,7 +371,7 @@ func stackTrieGenerate(db ethdb.KeyValueWriter, scheme string, owner common.Hash
} }
t := trie.NewStackTrieWithOwner(nodeWriter, owner) t := trie.NewStackTrieWithOwner(nodeWriter, owner)
for leaf := range in { for leaf := range in {
t.TryUpdate(leaf.key[:], leaf.value) t.Update(leaf.key[:], leaf.value)
} }
var root common.Hash var root common.Hash
if db == nil { if db == nil {

View File

@ -103,7 +103,7 @@ type diffLayer struct {
memory uint64 // Approximate guess as to how much memory we use memory uint64 // Approximate guess as to how much memory we use
root common.Hash // Root hash to which this snapshot diff belongs to root common.Hash // Root hash to which this snapshot diff belongs to
stale uint32 // Signals that the layer became stale (state progressed) stale atomic.Bool // Signals that the layer became stale (state progressed)
// destructSet is a very special helper marker. If an account is marked as // destructSet is a very special helper marker. If an account is marked as
// deleted, then it's recorded in this set. However it's allowed that an account // deleted, then it's recorded in this set. However it's allowed that an account
@ -267,7 +267,7 @@ func (dl *diffLayer) Parent() snapshot {
// Stale return whether this layer has become stale (was flattened across) or if // Stale return whether this layer has become stale (was flattened across) or if
// it's still live. // it's still live.
func (dl *diffLayer) Stale() bool { func (dl *diffLayer) Stale() bool {
return atomic.LoadUint32(&dl.stale) != 0 return dl.stale.Load()
} }
// Account directly retrieves the account associated with a particular hash in // Account directly retrieves the account associated with a particular hash in
@ -449,7 +449,7 @@ func (dl *diffLayer) flatten() snapshot {
// Before actually writing all our data to the parent, first ensure that the // Before actually writing all our data to the parent, first ensure that the
// parent hasn't been 'corrupted' by someone else already flattening into it // parent hasn't been 'corrupted' by someone else already flattening into it
if atomic.SwapUint32(&parent.stale, 1) != 0 { if parent.stale.Swap(true) {
panic("parent diff layer is stale") // we've flattened into the same parent from two children, boo panic("parent diff layer is stale") // we've flattened into the same parent from two children, boo
} }
// Overwrite all the updated accounts blindly, merge the sorted list // Overwrite all the updated accounts blindly, merge the sorted list

View File

@ -230,7 +230,7 @@ func (dl *diskLayer) proveRange(ctx *generatorContext, trieId *trie.ID, prefix [
if origin == nil && !diskMore { if origin == nil && !diskMore {
stackTr := trie.NewStackTrie(nil) stackTr := trie.NewStackTrie(nil)
for i, key := range keys { for i, key := range keys {
stackTr.TryUpdate(key, vals[i]) stackTr.Update(key, vals[i])
} }
if gotRoot := stackTr.Hash(); gotRoot != root { if gotRoot := stackTr.Hash(); gotRoot != root {
return &proofResult{ return &proofResult{

View File

@ -161,7 +161,7 @@ func newHelper() *testHelper {
func (t *testHelper) addTrieAccount(acckey string, acc *Account) { func (t *testHelper) addTrieAccount(acckey string, acc *Account) {
val, _ := rlp.EncodeToBytes(acc) val, _ := rlp.EncodeToBytes(acc)
t.accTrie.Update([]byte(acckey), val) t.accTrie.MustUpdate([]byte(acckey), val)
} }
func (t *testHelper) addSnapAccount(acckey string, acc *Account) { func (t *testHelper) addSnapAccount(acckey string, acc *Account) {
@ -186,7 +186,7 @@ func (t *testHelper) makeStorageTrie(stateRoot, owner common.Hash, keys []string
id := trie.StorageTrieID(stateRoot, owner, common.Hash{}) id := trie.StorageTrieID(stateRoot, owner, common.Hash{})
stTrie, _ := trie.NewStateTrie(id, t.triedb) stTrie, _ := trie.NewStateTrie(id, t.triedb)
for i, k := range keys { for i, k := range keys {
stTrie.Update([]byte(k), []byte(vals[i])) stTrie.MustUpdate([]byte(k), []byte(vals[i]))
} }
if !commit { if !commit {
return stTrie.Hash().Bytes() return stTrie.Hash().Bytes()
@ -491,7 +491,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) {
) )
acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
val, _ := rlp.EncodeToBytes(acc) val, _ := rlp.EncodeToBytes(acc)
helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
// Identical in the snap // Identical in the snap
key := hashData([]byte("acc-1")) key := hashData([]byte("acc-1"))
@ -562,7 +562,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) {
) )
acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()} acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
val, _ := rlp.EncodeToBytes(acc) val, _ := rlp.EncodeToBytes(acc)
helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e helper.accTrie.MustUpdate([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
// Identical in the snap // Identical in the snap
key := hashData([]byte("acc-1")) key := hashData([]byte("acc-1"))
@ -613,8 +613,8 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) {
{ {
acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}
val, _ := rlp.EncodeToBytes(acc) val, _ := rlp.EncodeToBytes(acc)
helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val) helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val)
helper.accTrie.Update(common.HexToHash("0x07").Bytes(), val) helper.accTrie.MustUpdate(common.HexToHash("0x07").Bytes(), val)
rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x01"), val) rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x01"), val)
rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x02"), val) rawdb.WriteAccountSnapshot(helper.diskdb, common.HexToHash("0x02"), val)
@ -650,7 +650,7 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) {
{ {
acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()} acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}
val, _ := rlp.EncodeToBytes(acc) val, _ := rlp.EncodeToBytes(acc)
helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val) helper.accTrie.MustUpdate(common.HexToHash("0x03").Bytes(), val)
junk := make([]byte, 100) junk := make([]byte, 100)
copy(junk, []byte{0xde, 0xad}) copy(junk, []byte{0xde, 0xad})

View File

@ -22,7 +22,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
"sync/atomic"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
@ -272,7 +271,7 @@ func (t *Tree) Disable() {
case *diffLayer: case *diffLayer:
// If the layer is a simple diff, simply mark as stale // If the layer is a simple diff, simply mark as stale
layer.lock.Lock() layer.lock.Lock()
atomic.StoreUint32(&layer.stale, 1) layer.stale.Store(true)
layer.lock.Unlock() layer.lock.Unlock()
default: default:
@ -726,7 +725,7 @@ func (t *Tree) Rebuild(root common.Hash) {
case *diffLayer: case *diffLayer:
// If the layer is a simple diff, simply mark as stale // If the layer is a simple diff, simply mark as stale
layer.lock.Lock() layer.lock.Lock()
atomic.StoreUint32(&layer.stale, 1) layer.stale.Store(true)
layer.lock.Unlock() layer.lock.Unlock()
default: default:

View File

@ -118,7 +118,7 @@ func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) {
if err := snaps.Cap(common.HexToHash("0x02"), 0); err != nil { if err := snaps.Cap(common.HexToHash("0x02"), 0); err != nil {
t.Fatalf("failed to merge diff layer onto disk: %v", err) t.Fatalf("failed to merge diff layer onto disk: %v", err)
} }
// Since the base layer was modified, ensure that data retrieval on the external reference fail // Since the base layer was modified, ensure that data retrievals on the external reference fail
if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale { if acc, err := ref.Account(common.HexToHash("0x01")); err != ErrSnapshotStale {
t.Errorf("stale reference returned account: %#x (err: %v)", acc, err) t.Errorf("stale reference returned account: %#x (err: %v)", acc, err)
} }

View File

@ -201,7 +201,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
s.db.setError(err) s.db.setError(err)
return common.Hash{} return common.Hash{}
} }
enc, err = tr.TryGet(key.Bytes()) enc, err = tr.GetStorage(s.address, key.Bytes())
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
s.db.StorageReads += time.Since(start) s.db.StorageReads += time.Since(start)
} }
@ -253,7 +253,7 @@ func (s *stateObject) finalise(prefetch bool) {
} }
} }
if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
s.db.prefetcher.prefetch(s.addrHash, s.data.Root, slotsToPrefetch) s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch)
} }
if len(s.dirtyStorage) > 0 { if len(s.dirtyStorage) > 0 {
s.dirtyStorage = make(Storage) s.dirtyStorage = make(Storage)
@ -294,7 +294,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
var v []byte var v []byte
if (value == common.Hash{}) { if (value == common.Hash{}) {
if err := tr.TryDelete(key[:]); err != nil { if err := tr.DeleteStorage(s.address, key[:]); err != nil {
s.db.setError(err) s.db.setError(err)
return nil, err return nil, err
} }
@ -302,7 +302,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
} else { } else {
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:])) v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
if err := tr.TryUpdate(key[:], v); err != nil { if err := tr.UpdateStorage(s.address, key[:], v); err != nil {
s.db.setError(err) s.db.setError(err)
return nil, err return nil, err
} }

View File

@ -521,7 +521,7 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
} }
// Encode the account and update the account trie // Encode the account and update the account trie
addr := obj.Address() addr := obj.Address()
if err := s.trie.TryUpdateAccount(addr, &obj.data); err != nil { if err := s.trie.UpdateAccount(addr, &obj.data); err != nil {
s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err)) s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err))
} }
@ -542,7 +542,7 @@ func (s *StateDB) deleteStateObject(obj *stateObject) {
} }
// Delete the account from the trie // Delete the account from the trie
addr := obj.Address() addr := obj.Address()
if err := s.trie.TryDeleteAccount(addr); err != nil { if err := s.trie.DeleteAccount(addr); err != nil {
s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err)) s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err))
} }
} }
@ -596,7 +596,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
if data == nil { if data == nil {
start := time.Now() start := time.Now()
var err error var err error
data, err = s.trie.TryGetAccount(addr) data, err = s.trie.GetAccount(addr)
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
s.AccountReads += time.Since(start) s.AccountReads += time.Since(start)
} }
@ -880,7 +880,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure
} }
if s.prefetcher != nil && len(addressesToPrefetch) > 0 { if s.prefetcher != nil && len(addressesToPrefetch) > 0 {
s.prefetcher.prefetch(common.Hash{}, s.originalRoot, addressesToPrefetch) s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch)
} }
// Invalidate journal because reverting across transactions is not allowed. // Invalidate journal because reverting across transactions is not allowed.
s.clearJournalAndRefund() s.clearJournalAndRefund()

View File

@ -213,14 +213,14 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) {
for i, node := range nodeElements { for i, node := range nodeElements {
if bypath { if bypath {
if len(node.syncPath) == 1 { if len(node.syncPath) == 1 {
data, _, err := srcTrie.TryGetNode(node.syncPath[0]) data, _, err := srcTrie.GetNode(node.syncPath[0])
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[0], err) t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[0], err)
} }
nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data} nodeResults[i] = trie.NodeSyncResult{Path: node.path, Data: data}
} else { } else {
var acc types.StateAccount var acc types.StateAccount
if err := rlp.DecodeBytes(srcTrie.Get(node.syncPath[0]), &acc); err != nil { if err := rlp.DecodeBytes(srcTrie.MustGet(node.syncPath[0]), &acc); err != nil {
t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err) t.Fatalf("failed to decode account on path %x: %v", node.syncPath[0], err)
} }
id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root) id := trie.StorageTrieID(srcRoot, common.BytesToHash(node.syncPath[0]), acc.Root)
@ -228,7 +228,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool) {
if err != nil { if err != nil {
t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err) t.Fatalf("failed to retriev storage trie for path %x: %v", node.syncPath[1], err)
} }
data, _, err := stTrie.TryGetNode(node.syncPath[1]) data, _, err := stTrie.GetNode(node.syncPath[1])
if err != nil { if err != nil {
t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[1], err) t.Fatalf("failed to retrieve node data for path %x: %v", node.syncPath[1], err)
} }

View File

@ -141,7 +141,7 @@ func (p *triePrefetcher) copy() *triePrefetcher {
} }
// prefetch schedules a batch of trie items to prefetch. // prefetch schedules a batch of trie items to prefetch.
func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, keys [][]byte) { func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) {
// If the prefetcher is an inactive one, bail out // If the prefetcher is an inactive one, bail out
if p.fetches != nil { if p.fetches != nil {
return return
@ -150,7 +150,7 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, keys [][]
id := p.trieID(owner, root) id := p.trieID(owner, root)
fetcher := p.fetchers[id] fetcher := p.fetchers[id]
if fetcher == nil { if fetcher == nil {
fetcher = newSubfetcher(p.db, p.root, owner, root) fetcher = newSubfetcher(p.db, p.root, owner, root, addr)
p.fetchers[id] = fetcher p.fetchers[id] = fetcher
} }
fetcher.schedule(keys) fetcher.schedule(keys)
@ -209,6 +209,7 @@ type subfetcher struct {
state common.Hash // Root hash of the state to prefetch state common.Hash // Root hash of the state to prefetch
owner common.Hash // Owner of the trie, usually account hash owner common.Hash // Owner of the trie, usually account hash
root common.Hash // Root hash of the trie to prefetch root common.Hash // Root hash of the trie to prefetch
addr common.Address // Address of the account that the trie belongs to
trie Trie // Trie being populated with nodes trie Trie // Trie being populated with nodes
tasks [][]byte // Items queued up for retrieval tasks [][]byte // Items queued up for retrieval
@ -226,12 +227,13 @@ type subfetcher struct {
// newSubfetcher creates a goroutine to prefetch state items belonging to a // newSubfetcher creates a goroutine to prefetch state items belonging to a
// particular root hash. // particular root hash.
func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash) *subfetcher { func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher {
sf := &subfetcher{ sf := &subfetcher{
db: db, db: db,
state: state, state: state,
owner: owner, owner: owner,
root: root, root: root,
addr: addr,
wake: make(chan struct{}, 1), wake: make(chan struct{}, 1),
stop: make(chan struct{}), stop: make(chan struct{}),
term: make(chan struct{}), term: make(chan struct{}),
@ -336,7 +338,11 @@ func (sf *subfetcher) loop() {
if _, ok := sf.seen[string(task)]; ok { if _, ok := sf.seen[string(task)]; ok {
sf.dups++ sf.dups++
} else { } else {
sf.trie.TryGet(task) if len(task) == common.AddressLength {
sf.trie.GetAccount(common.BytesToAddress(task))
} else {
sf.trie.GetStorage(sf.addr, task)
}
sf.seen[string(task)] = struct{}{} sf.seen[string(task)] = struct{}{}
} }
} }

View File

@ -47,19 +47,19 @@ func TestCopyAndClose(t *testing.T) {
db := filledStateDB() db := filledStateDB()
prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") prefetcher := newTriePrefetcher(db.db, db.originalRoot, "")
skey := common.HexToHash("aaa") skey := common.HexToHash("aaa")
prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()})
prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()})
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
a := prefetcher.trie(common.Hash{}, db.originalRoot) a := prefetcher.trie(common.Hash{}, db.originalRoot)
prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()})
b := prefetcher.trie(common.Hash{}, db.originalRoot) b := prefetcher.trie(common.Hash{}, db.originalRoot)
cpy := prefetcher.copy() cpy := prefetcher.copy()
cpy.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()})
cpy.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) cpy.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()})
c := cpy.trie(common.Hash{}, db.originalRoot) c := cpy.trie(common.Hash{}, db.originalRoot)
prefetcher.close() prefetcher.close()
cpy2 := cpy.copy() cpy2 := cpy.copy()
cpy2.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) cpy2.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()})
d := cpy2.trie(common.Hash{}, db.originalRoot) d := cpy2.trie(common.Hash{}, db.originalRoot)
cpy.close() cpy.close()
cpy2.close() cpy2.close()
@ -72,7 +72,7 @@ func TestUseAfterClose(t *testing.T) {
db := filledStateDB() db := filledStateDB()
prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") prefetcher := newTriePrefetcher(db.db, db.originalRoot, "")
skey := common.HexToHash("aaa") skey := common.HexToHash("aaa")
prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()})
a := prefetcher.trie(common.Hash{}, db.originalRoot) a := prefetcher.trie(common.Hash{}, db.originalRoot)
prefetcher.close() prefetcher.close()
b := prefetcher.trie(common.Hash{}, db.originalRoot) b := prefetcher.trie(common.Hash{}, db.originalRoot)
@ -88,7 +88,7 @@ func TestCopyClose(t *testing.T) {
db := filledStateDB() db := filledStateDB()
prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") prefetcher := newTriePrefetcher(db.db, db.originalRoot, "")
skey := common.HexToHash("aaa") skey := common.HexToHash("aaa")
prefetcher.prefetch(common.Hash{}, db.originalRoot, [][]byte{skey.Bytes()}) prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()})
cpy := prefetcher.copy() cpy := prefetcher.copy()
a := prefetcher.trie(common.Hash{}, db.originalRoot) a := prefetcher.trie(common.Hash{}, db.originalRoot)
b := cpy.trie(common.Hash{}, db.originalRoot) b := cpy.trie(common.Hash{}, db.originalRoot)

View File

@ -47,7 +47,7 @@ func newStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine conse
// Prefetch processes the state changes according to the Ethereum rules by running // Prefetch processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb, but any changes are discarded. The // the transaction messages using the statedb, but any changes are discarded. The
// only goal is to pre-cache transaction signatures and state trie nodes. // only goal is to pre-cache transaction signatures and state trie nodes.
func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32) { func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *atomic.Bool) {
var ( var (
header = block.Header() header = block.Header()
gaspool = new(GasPool).AddGas(block.GasLimit()) gaspool = new(GasPool).AddGas(block.GasLimit())
@ -59,7 +59,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
byzantium := p.config.IsByzantium(block.Number()) byzantium := p.config.IsByzantium(block.Number())
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
// If block precaching was interrupted, abort // If block precaching was interrupted, abort
if interrupt != nil && atomic.LoadUint32(interrupt) == 1 { if interrupt != nil && interrupt.Load() {
return return
} }
// Convert the transaction into an executable message and pre-cache its sender // Convert the transaction into an executable message and pre-cache its sender

View File

@ -75,7 +75,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
blockTracer, ok := pluginGetBlockTracer(header.Hash(), statedb) blockTracer, ok := pluginGetBlockTracer(header.Hash(), statedb)
if ok { if ok {
cfg.Tracer = blockTracer cfg.Tracer = blockTracer
cfg.Debug = true // cfg.Debug = true
} }
// end pluGeth code injection // end pluGeth code injection
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)

View File

@ -136,7 +136,7 @@ type Message struct {
Data []byte Data []byte
AccessList types.AccessList AccessList types.AccessList
// When SkipAccountCheckss is true, the message nonce is not checked against the // When SkipAccountChecks is true, the message nonce is not checked against the
// account nonce in state. It also disables checking that the sender is an EOA. // account nonce in state. It also disables checking that the sender is an EOA.
// This field will be set to true for operations like RPC eth_call. // This field will be set to true for operations like RPC eth_call.
SkipAccountChecks bool SkipAccountChecks bool
@ -332,10 +332,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
return nil, err return nil, err
} }
if st.evm.Config.Debug { if tracer := st.evm.Config.Tracer; tracer != nil {
st.evm.Config.Tracer.CaptureTxStart(st.initialGas) tracer.CaptureTxStart(st.initialGas)
defer func() { defer func() {
st.evm.Config.Tracer.CaptureTxEnd(st.gasRemaining) tracer.CaptureTxEnd(st.gasRemaining)
}() }()
} }

View File

@ -270,10 +270,10 @@ func newList(strict bool) *list {
} }
} }
// Overlaps returns whether the transaction specified has the same nonce as one // Contains returns whether the list contains a transaction
// already contained within the list. // with the provided nonce.
func (l *list) Overlaps(tx *types.Transaction) bool { func (l *list) Contains(nonce uint64) bool {
return l.txs.Get(tx.Nonce()) != nil return l.txs.Get(nonce) != nil
} }
// Add tries to insert a new transaction into the list, returning whether the // Add tries to insert a new transaction into the list, returning whether the

View File

@ -23,6 +23,7 @@ import (
"math/big" "math/big"
"sort" "sort"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -250,14 +251,14 @@ type TxPool struct {
signer types.Signer signer types.Signer
mu sync.RWMutex mu sync.RWMutex
istanbul bool // Fork indicator whether we are in the istanbul stage. istanbul atomic.Bool // Fork indicator whether we are in the istanbul stage.
eip2718 bool // Fork indicator whether we are using EIP-2718 type transactions. eip2718 atomic.Bool // Fork indicator whether we are using EIP-2718 type transactions.
eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions. eip1559 atomic.Bool // Fork indicator whether we are using EIP-1559 type transactions.
shanghai bool // Fork indicator whether we are in the Shanghai stage. shanghai atomic.Bool // Fork indicator whether we are in the Shanghai stage.
currentState *state.StateDB // Current state in the blockchain head currentState *state.StateDB // Current state in the blockchain head
pendingNonces *noncer // Pending state tracking virtual nonces pendingNonces *noncer // Pending state tracking virtual nonces
currentMaxGas uint64 // Current gas limit for transaction caps currentMaxGas atomic.Uint64 // Current gas limit for transaction caps
locals *accountSet // Set of local transaction to exempt from eviction rules locals *accountSet // Set of local transaction to exempt from eviction rules
journal *journal // Journal of local transaction to back up to disk journal *journal // Journal of local transaction to back up to disk
@ -592,15 +593,17 @@ func (pool *TxPool) local() map[common.Address]types.Transactions {
return txs return txs
} }
// validateTx checks whether a transaction is valid according to the consensus // validateTxBasics checks whether a transaction is valid according to the consensus
// rules and adheres to some heuristic limits of the local node (price and size). // rules, but does not check state-dependent validation such as sufficient balance.
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { // This check is meant as an early check which only needs to be performed once,
// and does not require the pool mutex to be held.
func (pool *TxPool) validateTxBasics(tx *types.Transaction, local bool) error {
// Accept only legacy transactions until EIP-2718/2930 activates. // Accept only legacy transactions until EIP-2718/2930 activates.
if !pool.eip2718 && tx.Type() != types.LegacyTxType { if !pool.eip2718.Load() && tx.Type() != types.LegacyTxType {
return core.ErrTxTypeNotSupported return core.ErrTxTypeNotSupported
} }
// Reject dynamic fee transactions until EIP-1559 activates. // Reject dynamic fee transactions until EIP-1559 activates.
if !pool.eip1559 && tx.Type() == types.DynamicFeeTxType { if !pool.eip1559.Load() && tx.Type() == types.DynamicFeeTxType {
return core.ErrTxTypeNotSupported return core.ErrTxTypeNotSupported
} }
// Reject transactions over defined size to prevent DOS attacks // Reject transactions over defined size to prevent DOS attacks
@ -608,7 +611,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
return ErrOversizedData return ErrOversizedData
} }
// Check whether the init code size has been exceeded. // Check whether the init code size has been exceeded.
if pool.shanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { if pool.shanghai.Load() && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
return fmt.Errorf("%w: code size %v limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) return fmt.Errorf("%w: code size %v limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize)
} }
// Transactions can't be negative. This may never happen using RLP decoded // Transactions can't be negative. This may never happen using RLP decoded
@ -617,7 +620,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
return ErrNegativeValue return ErrNegativeValue
} }
// Ensure the transaction doesn't exceed the current block limit gas. // Ensure the transaction doesn't exceed the current block limit gas.
if pool.currentMaxGas < tx.Gas() { if pool.currentMaxGas.Load() < tx.Gas() {
return ErrGasLimit return ErrGasLimit
} }
// Sanity check for extremely large numbers // Sanity check for extremely large numbers
@ -632,14 +635,29 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
return core.ErrTipAboveFeeCap return core.ErrTipAboveFeeCap
} }
// Make sure the transaction is signed properly. // Make sure the transaction is signed properly.
from, err := types.Sender(pool.signer, tx) if _, err := types.Sender(pool.signer, tx); err != nil {
if err != nil {
return ErrInvalidSender return ErrInvalidSender
} }
// Drop non-local transactions under our own minimal accepted gas price or tip // Drop non-local transactions under our own minimal accepted gas price or tip
if !local && tx.GasTipCapIntCmp(pool.gasPrice) < 0 { if !local && tx.GasTipCapIntCmp(pool.gasPrice) < 0 {
return ErrUnderpriced return ErrUnderpriced
} }
// Ensure the transaction has more gas than the basic tx fee.
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul.Load(), pool.shanghai.Load())
if err != nil {
return err
}
if tx.Gas() < intrGas {
return core.ErrIntrinsicGas
}
return nil
}
// validateTx checks whether a transaction is valid according to the consensus
// rules and adheres to some heuristic limits of the local node (price and size).
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// Signature has been checked already, this cannot error.
from, _ := types.Sender(pool.signer, tx)
// Ensure the transaction adheres to nonce ordering // Ensure the transaction adheres to nonce ordering
if pool.currentState.GetNonce(from) > tx.Nonce() { if pool.currentState.GetNonce(from) > tx.Nonce() {
return core.ErrNonceTooLow return core.ErrNonceTooLow
@ -664,15 +682,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
return ErrOverdraft return ErrOverdraft
} }
} }
// Ensure the transaction has more gas than the basic tx fee.
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai)
if err != nil {
return err
}
if tx.Gas() < intrGas {
return core.ErrIntrinsicGas
}
return nil return nil
} }
@ -736,11 +745,11 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
} }
// If the new transaction is a future transaction it should never churn pending transactions // If the new transaction is a future transaction it should never churn pending transactions
if !isLocal && pool.isFuture(from, tx) { if !isLocal && pool.isGapped(from, tx) {
var replacesPending bool var replacesPending bool
for _, dropTx := range drop { for _, dropTx := range drop {
dropSender, _ := types.Sender(pool.signer, dropTx) dropSender, _ := types.Sender(pool.signer, dropTx)
if list := pool.pending[dropSender]; list != nil && list.Overlaps(dropTx) { if list := pool.pending[dropSender]; list != nil && list.Contains(dropTx.Nonce()) {
replacesPending = true replacesPending = true
break break
} }
@ -765,7 +774,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
} }
// Try to replace an existing transaction in the pending pool // Try to replace an existing transaction in the pending pool
if list := pool.pending[from]; list != nil && list.Overlaps(tx) { if list := pool.pending[from]; list != nil && list.Contains(tx.Nonce()) {
// Nonce already pending, check if required price bump is met // Nonce already pending, check if required price bump is met
inserted, old := list.Add(tx, pool.config.PriceBump) inserted, old := list.Add(tx, pool.config.PriceBump)
if !inserted { if !inserted {
@ -808,18 +817,26 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
return replaced, nil return replaced, nil
} }
// isFuture reports whether the given transaction is immediately executable. // isGapped reports whether the given transaction is immediately executable.
func (pool *TxPool) isFuture(from common.Address, tx *types.Transaction) bool { func (pool *TxPool) isGapped(from common.Address, tx *types.Transaction) bool {
list := pool.pending[from] // Short circuit if transaction matches pending nonce and can be promoted
if list == nil { // to pending list as an executable transaction.
return pool.pendingNonces.get(from) != tx.Nonce() next := pool.pendingNonces.get(from)
if tx.Nonce() == next {
return false
} }
// Sender has pending transactions. // The transaction has a nonce gap with pending list, it's only considered
if old := list.txs.Get(tx.Nonce()); old != nil { // as executable if transactions in queue can fill up the nonce gap.
return false // It replaces a pending transaction. queue, ok := pool.queue[from]
if !ok {
return true
} }
// Not replacing, check if parent nonce exists in pending. for nonce := next; nonce < tx.Nonce(); nonce++ {
return list.txs.Get(tx.Nonce()-1) == nil if !queue.Contains(nonce) {
return true // txs in queue can't fill up the nonce gap
}
}
return false
} }
// enqueueTx inserts a new transaction into the non-executable transaction queue. // enqueueTx inserts a new transaction into the non-executable transaction queue.
@ -969,12 +986,12 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error {
knownTxMeter.Mark(1) knownTxMeter.Mark(1)
continue continue
} }
// Exclude transactions with invalid signatures as soon as // Exclude transactions with basic errors, e.g invalid signatures and
// possible and cache senders in transactions before // insufficient intrinsic gas as soon as possible and cache senders
// obtaining lock // in transactions before obtaining lock
_, err := types.Sender(pool.signer, tx)
if err != nil { if err := pool.validateTxBasics(tx, local); err != nil {
errs[i] = ErrInvalidSender errs[i] = err
invalidTxMeter.Mark(1) invalidTxMeter.Mark(1)
continue continue
} }
@ -1364,7 +1381,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
} }
pool.currentState = statedb pool.currentState = statedb
pool.pendingNonces = newNoncer(statedb) pool.pendingNonces = newNoncer(statedb)
pool.currentMaxGas = newHead.GasLimit pool.currentMaxGas.Store(newHead.GasLimit)
// Inject any transactions discarded due to reorgs // Inject any transactions discarded due to reorgs
log.Debug("Reinjecting stale transactions", "count", len(reinject)) log.Debug("Reinjecting stale transactions", "count", len(reinject))
@ -1373,10 +1390,10 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
// Update all fork indicator by next pending block number. // Update all fork indicator by next pending block number.
next := new(big.Int).Add(newHead.Number, big.NewInt(1)) next := new(big.Int).Add(newHead.Number, big.NewInt(1))
pool.istanbul = pool.chainconfig.IsIstanbul(next) pool.istanbul.Store(pool.chainconfig.IsIstanbul(next))
pool.eip2718 = pool.chainconfig.IsBerlin(next) pool.eip2718.Store(pool.chainconfig.IsBerlin(next))
pool.eip1559 = pool.chainconfig.IsLondon(next) pool.eip1559.Store(pool.chainconfig.IsLondon(next))
pool.shanghai = pool.chainconfig.IsShanghai(uint64(time.Now().Unix())) pool.shanghai.Store(pool.chainconfig.IsShanghai(uint64(time.Now().Unix())))
} }
// promoteExecutables moves transactions that have become processable from the // promoteExecutables moves transactions that have become processable from the
@ -1400,7 +1417,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
} }
log.Trace("Removed old queued transactions", "count", len(forwards)) log.Trace("Removed old queued transactions", "count", len(forwards))
// Drop all transactions that are too costly (low balance or out of gas) // Drop all transactions that are too costly (low balance or out of gas)
drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas.Load())
for _, tx := range drops { for _, tx := range drops {
hash := tx.Hash() hash := tx.Hash()
pool.all.Remove(hash) pool.all.Remove(hash)
@ -1597,7 +1614,7 @@ func (pool *TxPool) demoteUnexecutables() {
log.Trace("Removed old pending transaction", "hash", hash) log.Trace("Removed old pending transaction", "hash", hash)
} }
// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later // Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas) drops, invalids := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas.Load())
for _, tx := range drops { for _, tx := range drops {
hash := tx.Hash() hash := tx.Hash()
log.Trace("Removed unpayable pending transaction", "hash", hash) log.Trace("Removed unpayable pending transaction", "hash", hash)

View File

@ -42,7 +42,7 @@ func count(t *testing.T, pool *TxPool) (pending int, queued int) {
return pending, queued return pending, queued
} }
func fillPool(t *testing.T, pool *TxPool) { func fillPool(t testing.TB, pool *TxPool) {
t.Helper() t.Helper()
// Create a number of test accounts, fund them and make transactions // Create a number of test accounts, fund them and make transactions
executableTxs := types.Transactions{} executableTxs := types.Transactions{}
@ -189,7 +189,7 @@ func TestTransactionZAttack(t *testing.T) {
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000)) pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
for j := 0; j < int(pool.config.GlobalSlots); j++ { for j := 0; j < int(pool.config.GlobalSlots); j++ {
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 60000000000, 21000, big.NewInt(500), key)) overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key))
} }
} }
pool.AddRemotesSync(overDraftTxs) pool.AddRemotesSync(overDraftTxs)
@ -210,3 +210,27 @@ func TestTransactionZAttack(t *testing.T) {
newIvPending, ivPending, pool.config.GlobalSlots, newQueued) newIvPending, ivPending, pool.config.GlobalSlots, newQueued)
} }
} }
func BenchmarkFutureAttack(b *testing.B) {
// Create the pool to test the limit enforcement with
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
blockchain := newTestBlockChain(1000000, statedb, new(event.Feed))
config := testTxPoolConfig
config.GlobalQueue = 100
config.GlobalSlots = 100
pool := NewTxPool(config, eip1559Config, blockchain)
defer pool.Stop()
fillPool(b, pool)
key, _ := crypto.GenerateKey()
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
futureTxs := types.Transactions{}
for n := 0; n < b.N; n++ {
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(n), 100000, big.NewInt(500), key))
}
b.ResetTimer()
for i := 0; i < 5; i++ {
pool.AddRemotesSync(futureTxs)
}
}

View File

@ -293,28 +293,29 @@ func TestInvalidTransactions(t *testing.T) {
tx := transaction(0, 100, key) tx := transaction(0, 100, key)
from, _ := deriveSender(tx) from, _ := deriveSender(tx)
// Intrinsic gas too low
testAddBalance(pool, from, big.NewInt(1)) testAddBalance(pool, from, big.NewInt(1))
if err := pool.AddRemote(tx); !errors.Is(err, core.ErrInsufficientFunds) { if err, want := pool.AddRemote(tx), core.ErrIntrinsicGas; !errors.Is(err, want) {
t.Error("expected", core.ErrInsufficientFunds) t.Errorf("want %v have %v", want, err)
} }
balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())) // Insufficient funds
testAddBalance(pool, from, balance) tx = transaction(0, 100000, key)
if err := pool.AddRemote(tx); !errors.Is(err, core.ErrIntrinsicGas) { if err, want := pool.AddRemote(tx), core.ErrInsufficientFunds; !errors.Is(err, want) {
t.Error("expected", core.ErrIntrinsicGas, "got", err) t.Errorf("want %v have %v", want, err)
} }
testSetNonce(pool, from, 1) testSetNonce(pool, from, 1)
testAddBalance(pool, from, big.NewInt(0xffffffffffffff)) testAddBalance(pool, from, big.NewInt(0xffffffffffffff))
tx = transaction(0, 100000, key) tx = transaction(0, 100000, key)
if err := pool.AddRemote(tx); !errors.Is(err, core.ErrNonceTooLow) { if err, want := pool.AddRemote(tx), core.ErrNonceTooLow; !errors.Is(err, want) {
t.Error("expected", core.ErrNonceTooLow) t.Errorf("want %v have %v", want, err)
} }
tx = transaction(1, 100000, key) tx = transaction(1, 100000, key)
pool.gasPrice = big.NewInt(1000) pool.gasPrice = big.NewInt(1000)
if err := pool.AddRemote(tx); err != ErrUnderpriced { if err, want := pool.AddRemote(tx), ErrUnderpriced; !errors.Is(err, want) {
t.Error("expected", ErrUnderpriced, "got", err) t.Errorf("want %v have %v", want, err)
} }
if err := pool.AddLocal(tx); err != nil { if err := pool.AddLocal(tx); err != nil {
t.Error("expected", nil, "got", err) t.Error("expected", nil, "got", err)
@ -1217,22 +1218,22 @@ func TestAllowedTxSize(t *testing.T) {
// All those fields are summed up to at most 213 bytes. // All those fields are summed up to at most 213 bytes.
baseSize := uint64(213) baseSize := uint64(213)
dataSize := txMaxSize - baseSize dataSize := txMaxSize - baseSize
maxGas := pool.currentMaxGas.Load()
// Try adding a transaction with maximal allowed size // Try adding a transaction with maximal allowed size
tx := pricedDataTransaction(0, pool.currentMaxGas, big.NewInt(1), key, dataSize) tx := pricedDataTransaction(0, maxGas, big.NewInt(1), key, dataSize)
if err := pool.addRemoteSync(tx); err != nil { if err := pool.addRemoteSync(tx); err != nil {
t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err) 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 // Try adding a transaction with random allowed size
if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentMaxGas, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil { if err := pool.addRemoteSync(pricedDataTransaction(1, maxGas, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil {
t.Fatalf("failed to add transaction of random allowed size: %v", err) t.Fatalf("failed to add transaction of random allowed size: %v", err)
} }
// Try adding a transaction of minimal not allowed size // Try adding a transaction of minimal not allowed size
if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentMaxGas, big.NewInt(1), key, txMaxSize)); err == nil { if err := pool.addRemoteSync(pricedDataTransaction(2, maxGas, big.NewInt(1), key, txMaxSize)); err == nil {
t.Fatalf("expected rejection on slightly oversize transaction") t.Fatalf("expected rejection on slightly oversize transaction")
} }
// Try adding a transaction of random not allowed size // Try adding a transaction of random not allowed size
if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentMaxGas, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(10*txMaxSize)))); err == nil { if err := pool.addRemoteSync(pricedDataTransaction(2, maxGas, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(10*txMaxSize)))); err == nil {
t.Fatalf("expected rejection on oversize transaction") t.Fatalf("expected rejection on oversize transaction")
} }
// Run some sanity checks on the pool internals // Run some sanity checks on the pool internals

View File

@ -17,6 +17,8 @@
package core package core
import ( import (
"sync/atomic"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -39,7 +41,7 @@ type Prefetcher interface {
// Prefetch processes the state changes according to the Ethereum rules by running // Prefetch processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb, but any changes are discarded. The // the transaction messages using the statedb, but any changes are discarded. The
// only goal is to pre-cache transaction signatures and state trie nodes. // only goal is to pre-cache transaction signatures and state trie nodes.
Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *atomic.Bool)
} }
// Processor is an interface for processing blocks using a given initial state. // Processor is an interface for processing blocks using a given initial state.

View File

@ -85,6 +85,9 @@ type Header struct {
// WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers. // WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers.
WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`
// ExcessDataGas was added by EIP-4844 and is ignored in legacy headers.
ExcessDataGas *big.Int `json:"excessDataGas" rlp:"optional"`
/* /*
TODO (MariusVanDerWijden) Add this field once needed TODO (MariusVanDerWijden) Add this field once needed
// Random was added during the merge and contains the BeaconState randomness // Random was added during the merge and contains the BeaconState randomness

View File

@ -232,9 +232,10 @@ func (h *testHasher) Reset() {
h.hasher.Reset() h.hasher.Reset()
} }
func (h *testHasher) Update(key, val []byte) { func (h *testHasher) Update(key, val []byte) error {
h.hasher.Write(key) h.hasher.Write(key)
h.hasher.Write(val) h.hasher.Write(val)
return nil
} }
func (h *testHasher) Hash() common.Hash { func (h *testHasher) Hash() common.Hash {

View File

@ -62,7 +62,7 @@ func prefixedRlpHash(prefix byte, x interface{}) (h common.Hash) {
// This is internal, do not use. // This is internal, do not use.
type TrieHasher interface { type TrieHasher interface {
Reset() Reset()
Update([]byte, []byte) Update([]byte, []byte) error
Hash() common.Hash Hash() common.Hash
} }
@ -83,7 +83,7 @@ func encodeForDerive(list DerivableList, i int, buf *bytes.Buffer) []byte {
return common.CopyBytes(buf.Bytes()) return common.CopyBytes(buf.Bytes())
} }
// DeriveSha creates the tree hashes of transactions and receipts in a block header. // DeriveSha creates the tree hashes of transactions, receipts, and withdrawals in a block header.
func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash { func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash {
hasher.Reset() hasher.Reset()
@ -93,6 +93,9 @@ func DeriveSha(list DerivableList, hasher TrieHasher) common.Hash {
// StackTrie requires values to be inserted in increasing hash order, which is not the // StackTrie requires values to be inserted in increasing hash order, which is not the
// order that `list` provides hashes in. This insertion sequence ensures that the // order that `list` provides hashes in. This insertion sequence ensures that the
// order is correct. // order is correct.
//
// The error returned by hasher is omitted because hasher will produce an incorrect
// hash in case any error occurs.
var indexBuf []byte var indexBuf []byte
for i := 1; i < list.Len() && i <= 0x7f; i++ { for i := 1; i < list.Len() && i <= 0x7f; i++ {
indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i)) indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i))

View File

@ -219,9 +219,10 @@ func (d *hashToHumanReadable) Reset() {
d.data = make([]byte, 0) d.data = make([]byte, 0)
} }
func (d *hashToHumanReadable) Update(i []byte, i2 []byte) { func (d *hashToHumanReadable) Update(i []byte, i2 []byte) error {
l := fmt.Sprintf("%x %x\n", i, i2) l := fmt.Sprintf("%x %x\n", i, i2)
d.data = append(d.data, []byte(l)...) d.data = append(d.data, []byte(l)...)
return nil
} }
func (d *hashToHumanReadable) Hash() common.Hash { func (d *hashToHumanReadable) Hash() common.Hash {

View File

@ -63,7 +63,7 @@ func (bits *bitvec) codeSegment(pos uint64) bool {
// codeBitmap collects data locations in code. // codeBitmap collects data locations in code.
func codeBitmap(code []byte) bitvec { func codeBitmap(code []byte) bitvec {
// The bitmap is 4 bytes longer than necessary, in case the code // The bitmap is 4 bytes longer than necessary, in case the code
// ends with a PUSH32, the algorithm will push zeroes onto the // ends with a PUSH32, the algorithm will set bits on the
// bitvector outside the bounds of the actual code. // bitvector outside the bounds of the actual code.
bits := make(bitvec, len(code)/8+1+4) bits := make(bitvec, len(code)/8+1+4)
return codeBitmapInternal(code, bits) return codeBitmapInternal(code, bits)

View File

@ -114,8 +114,7 @@ type EVM struct {
// used throughout the execution of the tx. // used throughout the execution of the tx.
interpreter *EVMInterpreter interpreter *EVMInterpreter
// abort is used to abort the EVM calling operations // abort is used to abort the EVM calling operations
// NOTE: must be set atomically abort atomic.Bool
abort int32
// callGasTemp holds the gas available for the current call. This is needed because the // callGasTemp holds the gas available for the current call. This is needed because the
// available gas is calculated in gasCall* according to the 63/64 rule and later // available gas is calculated in gasCall* according to the 63/64 rule and later
// applied in opCall*. // applied in opCall*.
@ -147,12 +146,12 @@ func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) {
// Cancel cancels any running EVM operation. This may be called concurrently and // Cancel cancels any running EVM operation. This may be called concurrently and
// it's safe to be called multiple times. // it's safe to be called multiple times.
func (evm *EVM) Cancel() { func (evm *EVM) Cancel() {
atomic.StoreInt32(&evm.abort, 1) evm.abort.Store(true)
} }
// Cancelled returns true if Cancel has been called // Cancelled returns true if Cancel has been called
func (evm *EVM) Cancelled() bool { func (evm *EVM) Cancelled() bool {
return atomic.LoadInt32(&evm.abort) == 1 return evm.abort.Load()
} }
// Interpreter returns the current interpreter // Interpreter returns the current interpreter
@ -183,11 +182,12 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
} }
snapshot := evm.StateDB.Snapshot() snapshot := evm.StateDB.Snapshot()
p, isPrecompile := evm.precompile(addr) p, isPrecompile := evm.precompile(addr)
debug := evm.Config.Tracer != nil
if !evm.StateDB.Exist(addr) { if !evm.StateDB.Exist(addr) {
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 { if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
// Calling a non existing account, don't do anything, but ping the tracer // Calling a non existing account, don't do anything, but ping the tracer
if evm.Config.Debug { if debug {
if evm.depth == 0 { if evm.depth == 0 {
evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
evm.Config.Tracer.CaptureEnd(ret, 0, nil) evm.Config.Tracer.CaptureEnd(ret, 0, nil)
@ -203,7 +203,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value) evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value)
// Capture the tracer start/end events in debug mode // Capture the tracer start/end events in debug mode
if evm.Config.Debug { if debug {
if evm.depth == 0 { if evm.depth == 0 {
evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value) evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
defer func(startGas uint64) { // Lazy evaluation of the parameters defer func(startGas uint64) { // Lazy evaluation of the parameters
@ -273,7 +273,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
var snapshot = evm.StateDB.Snapshot() var snapshot = evm.StateDB.Snapshot()
// Invoke tracer hooks that signal entering/exiting a call frame // Invoke tracer hooks that signal entering/exiting a call frame
if evm.Config.Debug { if evm.Config.Tracer != nil {
evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value) evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value)
defer func(startGas uint64) { defer func(startGas uint64) {
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
@ -314,7 +314,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
var snapshot = evm.StateDB.Snapshot() var snapshot = evm.StateDB.Snapshot()
// Invoke tracer hooks that signal entering/exiting a call frame // Invoke tracer hooks that signal entering/exiting a call frame
if evm.Config.Debug { if evm.Config.Tracer != nil {
// NOTE: caller must, at all times be a contract. It should never happen // NOTE: caller must, at all times be a contract. It should never happen
// that caller is something other than a Contract. // that caller is something other than a Contract.
parent := caller.(*Contract) parent := caller.(*Contract)
@ -368,7 +368,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
evm.StateDB.AddBalance(addr, big0) evm.StateDB.AddBalance(addr, big0)
// Invoke tracer hooks that signal entering/exiting a call frame // Invoke tracer hooks that signal entering/exiting a call frame
if evm.Config.Debug { if evm.Config.Tracer != nil {
evm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil) evm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil)
defer func(startGas uint64) { defer func(startGas uint64) {
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err) evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
@ -451,7 +451,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
contract := NewContract(caller, AccountRef(address), value, gas) contract := NewContract(caller, AccountRef(address), value, gas)
contract.SetCodeOptionalHash(&address, codeAndHash) contract.SetCodeOptionalHash(&address, codeAndHash)
if evm.Config.Debug { if evm.Config.Tracer != nil {
if evm.depth == 0 { if evm.depth == 0 {
evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value) evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
} else { } else {
@ -494,7 +494,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
} }
} }
if evm.Config.Debug { if evm.Config.Tracer != nil {
if evm.depth == 0 { if evm.depth == 0 {
evm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, err) evm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, err)
} else { } else {

View File

@ -17,8 +17,6 @@
package vm package vm
import ( import (
"sync/atomic"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -531,7 +529,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
} }
func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if atomic.LoadInt32(&interpreter.evm.abort) != 0 { if interpreter.evm.abort.Load() {
return nil, errStopToken return nil, errStopToken
} }
pos := scope.Stack.pop() pos := scope.Stack.pop()
@ -543,7 +541,7 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
} }
func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opJumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if atomic.LoadInt32(&interpreter.evm.abort) != 0 { if interpreter.evm.abort.Load() {
return nil, errStopToken return nil, errStopToken
} }
pos, cond := scope.Stack.pop(), scope.Stack.pop() pos, cond := scope.Stack.pop(), scope.Stack.pop()
@ -824,9 +822,9 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
interpreter.evm.StateDB.Suicide(scope.Contract.Address()) interpreter.evm.StateDB.Suicide(scope.Contract.Address())
if interpreter.evm.Config.Debug { if tracer := interpreter.evm.Config.Tracer; tracer != nil {
interpreter.evm.Config.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
interpreter.evm.Config.Tracer.CaptureExit([]byte{}, 0, nil) tracer.CaptureExit([]byte{}, 0, nil)
} }
return nil, errStopToken return nil, errStopToken
} }

View File

@ -25,7 +25,6 @@ import (
// Config are the configuration options for the Interpreter // Config are the configuration options for the Interpreter
type Config struct { type Config struct {
Debug bool // Enables debugging
Tracer EVMLogger // Opcode logger Tracer EVMLogger // Opcode logger
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
@ -143,6 +142,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
gasCopy uint64 // for EVMLogger to log gas remaining before execution gasCopy uint64 // for EVMLogger to log gas remaining before execution
logged bool // deferred EVMLogger should ignore already logged steps logged bool // deferred EVMLogger should ignore already logged steps
res []byte // result of the opcode execution function res []byte // result of the opcode execution function
debug = in.evm.Config.Tracer != nil
) )
// Don't move this deferred function, it's placed before the capturestate-deferred method, // Don't move this deferred function, it's placed before the capturestate-deferred method,
// so that it get's executed _after_: the capturestate needs the stacks before // so that it get's executed _after_: the capturestate needs the stacks before
@ -152,7 +152,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
}() }()
contract.Input = input contract.Input = input
if in.evm.Config.Debug { if debug {
defer func() { defer func() {
if err != nil { if err != nil {
if !logged { if !logged {
@ -168,7 +168,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// the execution of one of the operations or until the done flag is set by the // the execution of one of the operations or until the done flag is set by the
// parent context. // parent context.
for { for {
if in.evm.Config.Debug { if debug {
// Capture pre-execution values for tracing. // Capture pre-execution values for tracing.
logged, pcCopy, gasCopy = false, pc, contract.Gas logged, pcCopy, gasCopy = false, pc, contract.Gas
} }
@ -213,14 +213,14 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
return nil, ErrOutOfGas return nil, ErrOutOfGas
} }
// Do tracing before memory expansion // Do tracing before memory expansion
if in.evm.Config.Debug { if debug {
in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
logged = true logged = true
} }
if memorySize > 0 { if memorySize > 0 {
mem.Resize(memorySize) mem.Resize(memorySize)
} }
} else if in.evm.Config.Debug { } else if debug {
in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err) in.evm.Config.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
logged = true logged = true
} }

View File

@ -0,0 +1,74 @@
// Copyright 2023 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package vm
import (
"errors"
"github.com/ethereum/go-ethereum/params"
)
// LookupInstructionSet returns the instructionset for the fork configured by
// the rules.
func LookupInstructionSet(rules params.Rules) (JumpTable, error) {
switch {
case rules.IsPrague:
return newShanghaiInstructionSet(), errors.New("prague-fork not defined yet")
case rules.IsCancun:
return newShanghaiInstructionSet(), errors.New("cancun-fork not defined yet")
case rules.IsShanghai:
return newShanghaiInstructionSet(), nil
case rules.IsMerge:
return newMergeInstructionSet(), nil
case rules.IsLondon:
return newLondonInstructionSet(), nil
case rules.IsBerlin:
return newBerlinInstructionSet(), nil
case rules.IsIstanbul:
return newIstanbulInstructionSet(), nil
case rules.IsConstantinople:
return newConstantinopleInstructionSet(), nil
case rules.IsByzantium:
return newByzantiumInstructionSet(), nil
case rules.IsEIP158:
return newSpuriousDragonInstructionSet(), nil
case rules.IsEIP150:
return newTangerineWhistleInstructionSet(), nil
case rules.IsHomestead:
return newHomesteadInstructionSet(), nil
}
return newFrontierInstructionSet(), nil
}
// Stack returns the mininum and maximum stack requirements.
func (op *operation) Stack() (int, int) {
return op.minStack, op.maxStack
}
// HasCost returns true if the opcode has a cost. Opcodes which do _not_ have
// a cost assigned are one of two things:
// - undefined, a.k.a invalid opcodes,
// - the STOP opcode.
// This method can thus be used to check if an opcode is "Invalid (or STOP)".
func (op *operation) HasCost() bool {
// Ideally, we'd check this:
// return op.execute == opUndefined
// However, go-lang does now allow that. So we'll just check some other
// 'indicators' that this is an invalid op. Alas, STOP is impossible to
// filter out
return op.dynamicGas != nil || op.constantGas != 0
}

View File

@ -204,6 +204,12 @@ const (
LOG4 LOG4
) )
// 0xb0 range.
const (
TLOAD OpCode = 0xb3
TSTORE OpCode = 0xb4
)
// 0xf0 range - closures. // 0xf0 range - closures.
const ( const (
CREATE OpCode = 0xf0 CREATE OpCode = 0xf0
@ -219,12 +225,6 @@ const (
SELFDESTRUCT OpCode = 0xff SELFDESTRUCT OpCode = 0xff
) )
// 0xb0 range.
const (
TLOAD OpCode = 0xb3
TSTORE OpCode = 0xb4
)
// Since the opcodes aren't all in order we can't use a regular slice. // Since the opcodes aren't all in order we can't use a regular slice.
var opCodeToString = map[OpCode]string{ var opCodeToString = map[OpCode]string{
// 0x0 range - arithmetic ops. // 0x0 range - arithmetic ops.
@ -291,8 +291,6 @@ var opCodeToString = map[OpCode]string{
// 0x50 range - 'storage' and execution. // 0x50 range - 'storage' and execution.
POP: "POP", POP: "POP",
//DUP: "DUP",
//SWAP: "SWAP",
MLOAD: "MLOAD", MLOAD: "MLOAD",
MSTORE: "MSTORE", MSTORE: "MSTORE",
MSTORE8: "MSTORE8", MSTORE8: "MSTORE8",
@ -306,7 +304,7 @@ var opCodeToString = map[OpCode]string{
JUMPDEST: "JUMPDEST", JUMPDEST: "JUMPDEST",
PUSH0: "PUSH0", PUSH0: "PUSH0",
// 0x60 range - push. // 0x60 range - pushes.
PUSH1: "PUSH1", PUSH1: "PUSH1",
PUSH2: "PUSH2", PUSH2: "PUSH2",
PUSH3: "PUSH3", PUSH3: "PUSH3",
@ -340,6 +338,7 @@ var opCodeToString = map[OpCode]string{
PUSH31: "PUSH31", PUSH31: "PUSH31",
PUSH32: "PUSH32", PUSH32: "PUSH32",
// 0x80 - dups.
DUP1: "DUP1", DUP1: "DUP1",
DUP2: "DUP2", DUP2: "DUP2",
DUP3: "DUP3", DUP3: "DUP3",
@ -357,6 +356,7 @@ var opCodeToString = map[OpCode]string{
DUP15: "DUP15", DUP15: "DUP15",
DUP16: "DUP16", DUP16: "DUP16",
// 0x90 - swaps.
SWAP1: "SWAP1", SWAP1: "SWAP1",
SWAP2: "SWAP2", SWAP2: "SWAP2",
SWAP3: "SWAP3", SWAP3: "SWAP3",
@ -373,6 +373,8 @@ var opCodeToString = map[OpCode]string{
SWAP14: "SWAP14", SWAP14: "SWAP14",
SWAP15: "SWAP15", SWAP15: "SWAP15",
SWAP16: "SWAP16", SWAP16: "SWAP16",
// 0xa0 range - logging ops.
LOG0: "LOG0", LOG0: "LOG0",
LOG1: "LOG1", LOG1: "LOG1",
LOG2: "LOG2", LOG2: "LOG2",
@ -383,7 +385,7 @@ var opCodeToString = map[OpCode]string{
TLOAD: "TLOAD", TLOAD: "TLOAD",
TSTORE: "TSTORE", TSTORE: "TSTORE",
// 0xf0 range. // 0xf0 range - closures.
CREATE: "CREATE", CREATE: "CREATE",
CALL: "CALL", CALL: "CALL",
RETURN: "RETURN", RETURN: "RETURN",
@ -473,8 +475,6 @@ var stringToOp = map[string]OpCode{
"GAS": GAS, "GAS": GAS,
"JUMPDEST": JUMPDEST, "JUMPDEST": JUMPDEST,
"PUSH0": PUSH0, "PUSH0": PUSH0,
"TLOAD": TLOAD,
"TSTORE": TSTORE,
"PUSH1": PUSH1, "PUSH1": PUSH1,
"PUSH2": PUSH2, "PUSH2": PUSH2,
"PUSH3": PUSH3, "PUSH3": PUSH3,
@ -544,6 +544,8 @@ var stringToOp = map[string]OpCode{
"LOG2": LOG2, "LOG2": LOG2,
"LOG3": LOG3, "LOG3": LOG3,
"LOG4": LOG4, "LOG4": LOG4,
"TLOAD": TLOAD,
"TSTORE": TSTORE,
"CREATE": CREATE, "CREATE": CREATE,
"CREATE2": CREATE2, "CREATE2": CREATE2,
"CALL": CALL, "CALL": CALL,

View File

@ -57,7 +57,6 @@ func setDefaults(cfg *Config) {
DAOForkBlock: new(big.Int), DAOForkBlock: new(big.Int),
DAOForkSupport: false, DAOForkSupport: false,
EIP150Block: new(big.Int), EIP150Block: new(big.Int),
EIP150Hash: common.Hash{},
EIP155Block: new(big.Int), EIP155Block: new(big.Int),
EIP158Block: new(big.Int), EIP158Block: new(big.Int),
ByzantiumBlock: new(big.Int), ByzantiumBlock: new(big.Int),

View File

@ -335,7 +335,6 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
b.Fatal(err) b.Fatal(err)
} }
cfg.EVMConfig = vm.Config{ cfg.EVMConfig = vm.Config{
Debug: true,
Tracer: tracer, Tracer: tracer,
} }
} }
@ -511,7 +510,6 @@ func TestEip2929Cases(t *testing.T) {
code, ops) code, ops)
Execute(code, nil, &Config{ Execute(code, nil, &Config{
EVMConfig: vm.Config{ EVMConfig: vm.Config{
Debug: true,
Tracer: logger.NewMarkdownLogger(nil, os.Stdout), Tracer: logger.NewMarkdownLogger(nil, os.Stdout),
ExtraEips: []int{2929}, ExtraEips: []int{2929},
}, },
@ -665,7 +663,6 @@ func TestColdAccountAccessCost(t *testing.T) {
tracer := logger.NewStructLogger(nil) tracer := logger.NewStructLogger(nil)
Execute(tc.code, nil, &Config{ Execute(tc.code, nil, &Config{
EVMConfig: vm.Config{ EVMConfig: vm.Config{
Debug: true,
Tracer: tracer, Tracer: tracer,
}, },
}) })
@ -837,7 +834,6 @@ func TestRuntimeJSTracer(t *testing.T) {
GasLimit: 1000000, GasLimit: 1000000,
State: statedb, State: statedb,
EVMConfig: vm.Config{ EVMConfig: vm.Config{
Debug: true,
Tracer: tracer, Tracer: tracer,
}}) }})
if err != nil { if err != nil {
@ -872,7 +868,6 @@ func TestJSTracerCreateTx(t *testing.T) {
_, _, _, err = Create(code, &Config{ _, _, _, err = Create(code, &Config{
State: statedb, State: statedb,
EVMConfig: vm.Config{ EVMConfig: vm.Config{
Debug: true,
Tracer: tracer, Tracer: tracer,
}}) }})
if err != nil { if err != nil {

View File

@ -327,7 +327,7 @@ func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error)
return b.gpo.SuggestTipCap(ctx) return b.gpo.SuggestTipCap(ctx)
} }
func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) { func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) {
return b.gpo.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles) return b.gpo.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles)
} }

View File

@ -20,7 +20,6 @@ package catalyst
import ( import (
"errors" "errors"
"fmt" "fmt"
"math/big"
"sync" "sync"
"time" "time"
@ -64,11 +63,6 @@ const (
// attached before starting to issue warnings. // attached before starting to issue warnings.
beaconUpdateStartupTimeout = 30 * time.Second beaconUpdateStartupTimeout = 30 * time.Second
// beaconUpdateExchangeTimeout is the max time allowed for a beacon client to
// do a transition config exchange before it's considered offline and the user
// is warned.
beaconUpdateExchangeTimeout = 2 * time.Minute
// beaconUpdateConsensusTimeout is the max time allowed for a beacon client // beaconUpdateConsensusTimeout is the max time allowed for a beacon client
// to send a consensus update before it's considered offline and the user is // to send a consensus update before it's considered offline and the user is
// warned. // warned.
@ -667,14 +661,13 @@ func (api *ConsensusAPI) heartbeat() {
// attached, so no need to print scary warnings to the user. // attached, so no need to print scary warnings to the user.
time.Sleep(beaconUpdateStartupTimeout) time.Sleep(beaconUpdateStartupTimeout)
var (
offlineLogged time.Time
ttd = api.eth.BlockChain().Config().TerminalTotalDifficulty
)
// If the network is not yet merged/merging, don't bother continuing. // If the network is not yet merged/merging, don't bother continuing.
if ttd == nil { if api.eth.BlockChain().Config().TerminalTotalDifficulty == nil {
return return
} }
var offlineLogged time.Time
for { for {
// Sleep a bit and retrieve the last known consensus updates // Sleep a bit and retrieve the last known consensus updates
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
@ -698,20 +691,14 @@ func (api *ConsensusAPI) heartbeat() {
offlineLogged = time.Time{} offlineLogged = time.Time{}
continue continue
} }
if time.Since(lastTransitionUpdate) > beaconUpdateExchangeTimeout {
if time.Since(offlineLogged) > beaconUpdateWarnFrequency { if time.Since(offlineLogged) > beaconUpdateWarnFrequency {
if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() {
if lastTransitionUpdate.IsZero() { if lastTransitionUpdate.IsZero() {
log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!") log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!")
} else { } else {
log.Warn("Previously seen beacon client is offline. Please ensure it is operational to follow the chain!")
}
offlineLogged = time.Now()
}
continue
}
if time.Since(offlineLogged) > beaconUpdateWarnFrequency {
if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() {
log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!") log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!")
}
} else { } else {
log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!") log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!")
} }
@ -719,62 +706,6 @@ func (api *ConsensusAPI) heartbeat() {
} }
continue continue
} }
if time.Since(lastTransitionUpdate) <= beaconUpdateExchangeTimeout {
offlineLogged = time.Time{}
continue
}
if time.Since(offlineLogged) > beaconUpdateWarnFrequency {
// Retrieve the last few blocks and make a rough estimate as
// to when the merge transition should happen
var (
chain = api.eth.BlockChain()
head = chain.CurrentHeader()
htd = chain.GetTd(head.Hash(), head.Number.Uint64())
)
if htd.Cmp(ttd) >= 0 {
if lastTransitionUpdate.IsZero() {
log.Warn("Merge already reached, but no beacon client seen. Please launch one to follow the chain!")
} else {
log.Warn("Merge already reached, but previously seen beacon client is offline. Please ensure it is operational to follow the chain!")
}
offlineLogged = time.Now()
continue
}
var eta time.Duration
if head.Number.Uint64() > 0 {
// Accumulate the last 64 difficulties to estimate the growth
var (
deltaDiff uint64
deltaTime uint64
current = head
)
for i := 0; i < 64; i++ {
parent := chain.GetHeader(current.ParentHash, current.Number.Uint64()-1)
if parent == nil {
break
}
deltaDiff += current.Difficulty.Uint64()
deltaTime += current.Time - parent.Time
current = parent
}
// Estimate an ETA based on the block times and the difficulty growth
if deltaTime > 0 {
growth := deltaDiff / deltaTime
left := new(big.Int).Sub(ttd, htd)
eta = time.Duration(new(big.Int).Div(left, new(big.Int).SetUint64(growth+1)).Uint64()) * time.Second
}
}
message := "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transition arrives!"
if lastTransitionUpdate.IsZero() {
message = "Merge is configured, but no beacon client seen. Please ensure you have one available before the transition arrives!"
}
if eta < time.Second {
log.Warn(message)
} else {
log.Warn(message, "eta", common.PrettyAge(time.Now().Add(-eta))) // weird hack, but duration formatted doesn't handle days
}
offlineLogged = time.Now()
}
} }
} }

View File

@ -879,15 +879,10 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
genesis, preMergeBlocks := generateMergeChain(100, false) genesis, preMergeBlocks := generateMergeChain(100, false)
n, ethservice := startEthService(t, genesis, preMergeBlocks) n, ethservice := startEthService(t, genesis, preMergeBlocks)
defer n.Close() defer n.Close()
api := NewConsensusAPI(ethservice)
ethservice.BlockChain().Config().TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())
var (
api = NewConsensusAPI(ethservice)
parent = preMergeBlocks[len(preMergeBlocks)-1]
)
// Test parent already post TTD in FCU // Test parent already post TTD in FCU
parent := preMergeBlocks[len(preMergeBlocks)-2]
fcState := engine.ForkchoiceStateV1{ fcState := engine.ForkchoiceStateV1{
HeadBlockHash: parent.Hash(), HeadBlockHash: parent.Hash(),
SafeBlockHash: common.Hash{}, SafeBlockHash: common.Hash{},
@ -913,6 +908,28 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
t.Fatalf("error preparing payload, err=%v", err) t.Fatalf("error preparing payload, err=%v", err)
} }
data := *payload.Resolve().ExecutionPayload data := *payload.Resolve().ExecutionPayload
// We need to recompute the blockhash, since the miner computes a wrong (correct) blockhash
txs, _ := decodeTransactions(data.Transactions)
header := &types.Header{
ParentHash: data.ParentHash,
UncleHash: types.EmptyUncleHash,
Coinbase: data.FeeRecipient,
Root: data.StateRoot,
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
ReceiptHash: data.ReceiptsRoot,
Bloom: types.BytesToBloom(data.LogsBloom),
Difficulty: common.Big0,
Number: new(big.Int).SetUint64(data.Number),
GasLimit: data.GasLimit,
GasUsed: data.GasUsed,
Time: data.Timestamp,
BaseFee: data.BaseFeePerGas,
Extra: data.ExtraData,
MixDigest: data.Random,
}
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */)
data.BlockHash = block.Hash()
// Send the new payload
resp2, err := api.NewPayloadV1(data) resp2, err := api.NewPayloadV1(data)
if err != nil { if err != nil {
t.Fatalf("error sending NewPayload, err=%v", err) t.Fatalf("error sending NewPayload, err=%v", err)
@ -1240,9 +1257,10 @@ func TestNilWithdrawals(t *testing.T) {
func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) { func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
genesis, blocks := generateMergeChain(10, true) genesis, blocks := generateMergeChain(10, true)
n, ethservice := startEthService(t, genesis, blocks)
// enable shanghai on the last block // enable shanghai on the last block
ethservice.BlockChain().Config().ShanghaiTime = &blocks[len(blocks)-1].Header().Time time := blocks[len(blocks)-1].Header().Time + 1
genesis.Config.ShanghaiTime = &time
n, ethservice := startEthService(t, genesis, blocks)
var ( var (
parent = ethservice.BlockChain().CurrentBlock() parent = ethservice.BlockChain().CurrentBlock()

View File

@ -19,7 +19,6 @@ package downloader
import ( import (
"fmt" "fmt"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -371,7 +370,7 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error {
continue continue
} }
// If the pivot block is committed, signal header sync termination // If the pivot block is committed, signal header sync termination
if atomic.LoadInt32(&d.committed) == 1 { if d.committed.Load() {
select { select {
case d.headerProcCh <- nil: case d.headerProcCh <- nil:
return nil return nil

View File

@ -98,7 +98,7 @@ type headerTask struct {
} }
type Downloader struct { type Downloader struct {
mode uint32 // Synchronisation mode defining the strategy used (per sync cycle), use d.getMode() to get the SyncMode mode atomic.Uint32 // Synchronisation mode defining the strategy used (per sync cycle), use d.getMode() to get the SyncMode
mux *event.TypeMux // Event multiplexer to announce sync operation events mux *event.TypeMux // Event multiplexer to announce sync operation events
checkpoint uint64 // Checkpoint block number to enforce head against (e.g. snap sync) checkpoint uint64 // Checkpoint block number to enforce head against (e.g. snap sync)
@ -122,9 +122,9 @@ type Downloader struct {
// Status // Status
synchroniseMock func(id string, hash common.Hash) error // Replacement for synchronise during testing synchroniseMock func(id string, hash common.Hash) error // Replacement for synchronise during testing
synchronising int32 synchronising atomic.Bool
notified int32 notified atomic.Bool
committed int32 committed atomic.Bool
ancientLimit uint64 // The maximum block number which can be regarded as ancient data. ancientLimit uint64 // The maximum block number which can be regarded as ancient data.
// Channels // Channels
@ -292,7 +292,7 @@ func (d *Downloader) Progress() ethereum.SyncProgress {
// Synchronising returns whether the downloader is currently retrieving blocks. // Synchronising returns whether the downloader is currently retrieving blocks.
func (d *Downloader) Synchronising() bool { func (d *Downloader) Synchronising() bool {
return atomic.LoadInt32(&d.synchronising) > 0 return d.synchronising.Load()
} }
// RegisterPeer injects a new download peer into the set of block source to be // RegisterPeer injects a new download peer into the set of block source to be
@ -392,13 +392,13 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int,
return d.synchroniseMock(id, hash) return d.synchroniseMock(id, hash)
} }
// Make sure only one goroutine is ever allowed past this point at once // Make sure only one goroutine is ever allowed past this point at once
if !atomic.CompareAndSwapInt32(&d.synchronising, 0, 1) { if !d.synchronising.CompareAndSwap(false, true) {
return errBusy return errBusy
} }
defer atomic.StoreInt32(&d.synchronising, 0) defer d.synchronising.Store(false)
// Post a user notification of the sync (only once per session) // Post a user notification of the sync (only once per session)
if atomic.CompareAndSwapInt32(&d.notified, 0, 1) { if d.notified.CompareAndSwap(false, true) {
log.Info("Block synchronisation started") log.Info("Block synchronisation started")
} }
if mode == SnapSync { if mode == SnapSync {
@ -435,7 +435,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int,
defer d.Cancel() // No matter what, we can't leave the cancel channel open defer d.Cancel() // No matter what, we can't leave the cancel channel open
// Atomically set the requested sync mode // Atomically set the requested sync mode
atomic.StoreUint32(&d.mode, uint32(mode)) d.mode.Store(uint32(mode))
// Retrieve the origin peer and initiate the downloading process // Retrieve the origin peer and initiate the downloading process
var p *peerConnection var p *peerConnection
@ -452,7 +452,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int,
} }
func (d *Downloader) getMode() SyncMode { func (d *Downloader) getMode() SyncMode {
return SyncMode(atomic.LoadUint32(&d.mode)) return SyncMode(d.mode.Load())
} }
// syncWithPeer starts a block synchronization based on the hash chain from the // syncWithPeer starts a block synchronization based on the hash chain from the
@ -562,9 +562,9 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
rawdb.WriteLastPivotNumber(d.stateDB, pivotNumber) rawdb.WriteLastPivotNumber(d.stateDB, pivotNumber)
} }
} }
d.committed = 1 d.committed.Store(true)
if mode == SnapSync && pivot.Number.Uint64() != 0 { if mode == SnapSync && pivot.Number.Uint64() != 0 {
d.committed = 0 d.committed.Store(false)
} }
if mode == SnapSync { if mode == SnapSync {
// Set the ancient data limitation. If we are running snap sync, all block // Set the ancient data limitation. If we are running snap sync, all block
@ -1128,7 +1128,7 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, head uint64) e
// If no more headers are inbound, notify the content fetchers and return // If no more headers are inbound, notify the content fetchers and return
if len(headers) == 0 { if len(headers) == 0 {
// Don't abort header fetches while the pivot is downloading // Don't abort header fetches while the pivot is downloading
if atomic.LoadInt32(&d.committed) == 0 && pivot <= from { if !d.committed.Load() && pivot <= from {
p.log.Debug("No headers, waiting for pivot commit") p.log.Debug("No headers, waiting for pivot commit")
select { select {
case <-time.After(fsHeaderContCheck): case <-time.After(fsHeaderContCheck):
@ -1669,7 +1669,7 @@ func (d *Downloader) processSnapSyncContent() error {
results = append(append([]*fetchResult{oldPivot}, oldTail...), results...) results = append(append([]*fetchResult{oldPivot}, oldTail...), results...)
} }
// Split around the pivot block and process the two sides via snap/full sync // Split around the pivot block and process the two sides via snap/full sync
if atomic.LoadInt32(&d.committed) == 0 { if !d.committed.Load() {
latest := results[len(results)-1].Header latest := results[len(results)-1].Header
// If the height is above the pivot block by 2 sets, it means the pivot // If the height is above the pivot block by 2 sets, it means the pivot
// become stale in the network and it was garbage collected, move to a // become stale in the network and it was garbage collected, move to a
@ -1794,7 +1794,7 @@ func (d *Downloader) commitPivotBlock(result *fetchResult) error {
if err := d.blockchain.SnapSyncCommitHead(block.Hash()); err != nil { if err := d.blockchain.SnapSyncCommitHead(block.Hash()); err != nil {
return err return err
} }
atomic.StoreInt32(&d.committed, 1) d.committed.Store(true)
return nil return nil
} }

View File

@ -476,9 +476,10 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) {
tester.newPeer("peer", protocol, testChainBase.blocks[1:]) tester.newPeer("peer", protocol, testChainBase.blocks[1:])
// Wrap the importer to allow stepping // Wrap the importer to allow stepping
blocked, proceed := uint32(0), make(chan struct{}) var blocked atomic.Uint32
proceed := make(chan struct{})
tester.downloader.chainInsertHook = func(results []*fetchResult) { tester.downloader.chainInsertHook = func(results []*fetchResult) {
atomic.StoreUint32(&blocked, uint32(len(results))) blocked.Store(uint32(len(results)))
<-proceed <-proceed
} }
// Start a synchronisation concurrently // Start a synchronisation concurrently
@ -505,7 +506,7 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) {
tester.downloader.queue.resultCache.lock.Lock() tester.downloader.queue.resultCache.lock.Lock()
{ {
cached = tester.downloader.queue.resultCache.countCompleted() cached = tester.downloader.queue.resultCache.countCompleted()
frozen = int(atomic.LoadUint32(&blocked)) frozen = int(blocked.Load())
retrieved = int(tester.chain.CurrentSnapBlock().Number.Uint64()) + 1 retrieved = int(tester.chain.CurrentSnapBlock().Number.Uint64()) + 1
} }
tester.downloader.queue.resultCache.lock.Unlock() tester.downloader.queue.resultCache.lock.Unlock()
@ -528,8 +529,8 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) {
t.Fatalf("block count mismatch: have %v, want %v (owned %v, blocked %v, target %v)", cached, blockCacheMaxItems, retrieved, frozen, targetBlocks+1) t.Fatalf("block count mismatch: have %v, want %v (owned %v, blocked %v, target %v)", cached, blockCacheMaxItems, retrieved, frozen, targetBlocks+1)
} }
// Permit the blocked blocks to import // Permit the blocked blocks to import
if atomic.LoadUint32(&blocked) > 0 { if blocked.Load() > 0 {
atomic.StoreUint32(&blocked, uint32(0)) blocked.Store(uint32(0))
proceed <- struct{}{} proceed <- struct{}{}
} }
} }
@ -786,12 +787,12 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) {
tester.newPeer("peer", protocol, chain.blocks[1:]) tester.newPeer("peer", protocol, chain.blocks[1:])
// Instrument the downloader to signal body requests // Instrument the downloader to signal body requests
bodiesHave, receiptsHave := int32(0), int32(0) var bodiesHave, receiptsHave atomic.Int32
tester.downloader.bodyFetchHook = func(headers []*types.Header) { tester.downloader.bodyFetchHook = func(headers []*types.Header) {
atomic.AddInt32(&bodiesHave, int32(len(headers))) bodiesHave.Add(int32(len(headers)))
} }
tester.downloader.receiptFetchHook = func(headers []*types.Header) { tester.downloader.receiptFetchHook = func(headers []*types.Header) {
atomic.AddInt32(&receiptsHave, int32(len(headers))) receiptsHave.Add(int32(len(headers)))
} }
// Synchronise with the peer and make sure all blocks were retrieved // Synchronise with the peer and make sure all blocks were retrieved
if err := tester.sync("peer", nil, mode); err != nil { if err := tester.sync("peer", nil, mode); err != nil {
@ -811,11 +812,11 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) {
receiptsNeeded++ receiptsNeeded++
} }
} }
if int(bodiesHave) != bodiesNeeded { if int(bodiesHave.Load()) != bodiesNeeded {
t.Errorf("body retrieval count mismatch: have %v, want %v", bodiesHave, bodiesNeeded) t.Errorf("body retrieval count mismatch: have %v, want %v", bodiesHave.Load(), bodiesNeeded)
} }
if int(receiptsHave) != receiptsNeeded { if int(receiptsHave.Load()) != receiptsNeeded {
t.Errorf("receipt retrieval count mismatch: have %v, want %v", receiptsHave, receiptsNeeded) t.Errorf("receipt retrieval count mismatch: have %v, want %v", receiptsHave.Load(), receiptsNeeded)
} }
} }

View File

@ -61,7 +61,7 @@ type fetchRequest struct {
// fetchResult is a struct collecting partial results from data fetchers until // fetchResult is a struct collecting partial results from data fetchers until
// all outstanding pieces complete and the result as a whole can be processed. // all outstanding pieces complete and the result as a whole can be processed.
type fetchResult struct { type fetchResult struct {
pending int32 // Flag telling what deliveries are outstanding pending atomic.Int32 // Flag telling what deliveries are outstanding
Header *types.Header Header *types.Header
Uncles []*types.Header Uncles []*types.Header
@ -75,38 +75,38 @@ func newFetchResult(header *types.Header, fastSync bool) *fetchResult {
Header: header, Header: header,
} }
if !header.EmptyBody() { if !header.EmptyBody() {
item.pending |= (1 << bodyType) item.pending.Store(item.pending.Load() | (1 << bodyType))
} else if header.WithdrawalsHash != nil { } else if header.WithdrawalsHash != nil {
item.Withdrawals = make(types.Withdrawals, 0) item.Withdrawals = make(types.Withdrawals, 0)
} }
if fastSync && !header.EmptyReceipts() { if fastSync && !header.EmptyReceipts() {
item.pending |= (1 << receiptType) item.pending.Store(item.pending.Load() | (1 << receiptType))
} }
return item return item
} }
// SetBodyDone flags the body as finished. // SetBodyDone flags the body as finished.
func (f *fetchResult) SetBodyDone() { func (f *fetchResult) SetBodyDone() {
if v := atomic.LoadInt32(&f.pending); (v & (1 << bodyType)) != 0 { if v := f.pending.Load(); (v & (1 << bodyType)) != 0 {
atomic.AddInt32(&f.pending, -1) f.pending.Add(-1)
} }
} }
// AllDone checks if item is done. // AllDone checks if item is done.
func (f *fetchResult) AllDone() bool { func (f *fetchResult) AllDone() bool {
return atomic.LoadInt32(&f.pending) == 0 return f.pending.Load() == 0
} }
// SetReceiptsDone flags the receipts as finished. // SetReceiptsDone flags the receipts as finished.
func (f *fetchResult) SetReceiptsDone() { func (f *fetchResult) SetReceiptsDone() {
if v := atomic.LoadInt32(&f.pending); (v & (1 << receiptType)) != 0 { if v := f.pending.Load(); (v & (1 << receiptType)) != 0 {
atomic.AddInt32(&f.pending, -2) f.pending.Add(-2)
} }
} }
// Done checks if the given type is done already // Done checks if the given type is done already
func (f *fetchResult) Done(kind uint) bool { func (f *fetchResult) Done(kind uint) bool {
v := atomic.LoadInt32(&f.pending) v := f.pending.Load()
return v&(1<<kind) == 0 return v&(1<<kind) == 0
} }

View File

@ -33,7 +33,7 @@ type resultStore struct {
// Internal index of first non-completed entry, updated atomically when needed. // Internal index of first non-completed entry, updated atomically when needed.
// If all items are complete, this will equal length(items), so // If all items are complete, this will equal length(items), so
// *important* : is not safe to use for indexing without checking against length // *important* : is not safe to use for indexing without checking against length
indexIncomplete int32 // atomic access indexIncomplete atomic.Int32
// throttleThreshold is the limit up to which we _want_ to fill the // throttleThreshold is the limit up to which we _want_ to fill the
// results. If blocks are large, we want to limit the results to less // results. If blocks are large, we want to limit the results to less
@ -146,7 +146,7 @@ func (r *resultStore) HasCompletedItems() bool {
func (r *resultStore) countCompleted() int { func (r *resultStore) countCompleted() int {
// We iterate from the already known complete point, and see // We iterate from the already known complete point, and see
// if any more has completed since last count // if any more has completed since last count
index := atomic.LoadInt32(&r.indexIncomplete) index := r.indexIncomplete.Load()
for ; ; index++ { for ; ; index++ {
if index >= int32(len(r.items)) { if index >= int32(len(r.items)) {
break break
@ -156,7 +156,7 @@ func (r *resultStore) countCompleted() int {
break break
} }
} }
atomic.StoreInt32(&r.indexIncomplete, index) r.indexIncomplete.Store(index)
return int(index) return int(index)
} }
@ -179,7 +179,7 @@ func (r *resultStore) GetCompleted(limit int) []*fetchResult {
} }
// Advance the expected block number of the first cache entry // Advance the expected block number of the first cache entry
r.resultOffset += uint64(limit) r.resultOffset += uint64(limit)
atomic.AddInt32(&r.indexIncomplete, int32(-limit)) r.indexIncomplete.Add(int32(-limit))
return results return results
} }

View File

@ -82,8 +82,8 @@ type skeletonTestPeer struct {
serve func(origin uint64) []*types.Header // Hook to allow custom responses serve func(origin uint64) []*types.Header // Hook to allow custom responses
served uint64 // Number of headers served by this peer served atomic.Uint64 // Number of headers served by this peer
dropped uint64 // Flag whether the peer was dropped (stop responding) dropped atomic.Uint64 // Flag whether the peer was dropped (stop responding)
} }
// newSkeletonTestPeer creates a new mock peer to test the skeleton sync with. // newSkeletonTestPeer creates a new mock peer to test the skeleton sync with.
@ -113,7 +113,7 @@ func (p *skeletonTestPeer) RequestHeadersByNumber(origin uint64, amount int, ski
// Since skeleton test peer are in-memory mocks, dropping the does not make // Since skeleton test peer are in-memory mocks, dropping the does not make
// them inaccessible. As such, check a local `dropped` field to see if the // them inaccessible. As such, check a local `dropped` field to see if the
// peer has been dropped and should not respond any more. // peer has been dropped and should not respond any more.
if atomic.LoadUint64(&p.dropped) != 0 { if p.dropped.Load() != 0 {
return nil, errors.New("peer already dropped") return nil, errors.New("peer already dropped")
} }
// Skeleton sync retrieves batches of headers going backward without gaps. // Skeleton sync retrieves batches of headers going backward without gaps.
@ -161,7 +161,7 @@ func (p *skeletonTestPeer) RequestHeadersByNumber(origin uint64, amount int, ski
} }
} }
} }
atomic.AddUint64(&p.served, uint64(len(headers))) p.served.Add(uint64(len(headers)))
hashes := make([]common.Hash, len(headers)) hashes := make([]common.Hash, len(headers))
for i, header := range headers { for i, header := range headers {
@ -182,7 +182,7 @@ func (p *skeletonTestPeer) RequestHeadersByNumber(origin uint64, amount int, ski
sink <- res sink <- res
if err := <-res.Done; err != nil { if err := <-res.Done; err != nil {
log.Warn("Skeleton test peer response rejected", "err", err) log.Warn("Skeleton test peer response rejected", "err", err)
atomic.AddUint64(&p.dropped, 1) p.dropped.Add(1)
} }
}() }()
return req, nil return req, nil
@ -817,7 +817,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
dropped := make(map[string]int) dropped := make(map[string]int)
drop := func(peer string) { drop := func(peer string) {
if p := peerset.Peer(peer); p != nil { if p := peerset.Peer(peer); p != nil {
atomic.AddUint64(&p.peer.(*skeletonTestPeer).dropped, 1) p.peer.(*skeletonTestPeer).dropped.Add(1)
} }
peerset.Unregister(peer) peerset.Unregister(peer)
dropped[peer]++ dropped[peer]++
@ -895,14 +895,14 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
if !tt.unpredictable { if !tt.unpredictable {
var served uint64 var served uint64
for _, peer := range tt.peers { for _, peer := range tt.peers {
served += atomic.LoadUint64(&peer.served) served += peer.served.Load()
} }
if served != tt.midserve { if served != tt.midserve {
t.Errorf("test %d, mid state: served headers mismatch: have %d, want %d", i, served, tt.midserve) t.Errorf("test %d, mid state: served headers mismatch: have %d, want %d", i, served, tt.midserve)
} }
var drops uint64 var drops uint64
for _, peer := range tt.peers { for _, peer := range tt.peers {
drops += atomic.LoadUint64(&peer.dropped) drops += peer.dropped.Load()
} }
if drops != tt.middrop { if drops != tt.middrop {
t.Errorf("test %d, mid state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) t.Errorf("test %d, mid state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop)
@ -950,20 +950,20 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
if !tt.unpredictable { if !tt.unpredictable {
served := uint64(0) served := uint64(0)
for _, peer := range tt.peers { for _, peer := range tt.peers {
served += atomic.LoadUint64(&peer.served) served += peer.served.Load()
} }
if tt.newPeer != nil { if tt.newPeer != nil {
served += atomic.LoadUint64(&tt.newPeer.served) served += tt.newPeer.served.Load()
} }
if served != tt.endserve { if served != tt.endserve {
t.Errorf("test %d, end state: served headers mismatch: have %d, want %d", i, served, tt.endserve) t.Errorf("test %d, end state: served headers mismatch: have %d, want %d", i, served, tt.endserve)
} }
drops := uint64(0) drops := uint64(0)
for _, peer := range tt.peers { for _, peer := range tt.peers {
drops += atomic.LoadUint64(&peer.dropped) drops += peer.dropped.Load()
} }
if tt.newPeer != nil { if tt.newPeer != nil {
drops += atomic.LoadUint64(&tt.newPeer.dropped) drops += tt.newPeer.dropped.Load()
} }
if drops != tt.enddrop { if drops != tt.enddrop {
t.Errorf("test %d, end state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) t.Errorf("test %d, end state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop)

View File

@ -212,12 +212,13 @@ type Config struct {
// CreateConsensusEngine creates a consensus engine for the given chain configuration. // CreateConsensusEngine creates a consensus engine for the given chain configuration.
func CreateConsensusEngine(stack *node.Node, ethashConfig *ethash.Config, cliqueConfig *params.CliqueConfig, notify []string, noverify bool, db ethdb.Database) consensus.Engine { func CreateConsensusEngine(stack *node.Node, ethashConfig *ethash.Config, cliqueConfig *params.CliqueConfig, notify []string, noverify bool, db ethdb.Database) consensus.Engine {
// If proof-of-authority is requested, set it up // If proof-of-authority is requested, set it up
//begin PluGeth code injection
if engine := pluginGetEngine(stack, notify, noverify, db); engine != nil { if engine := pluginGetEngine(stack, notify, noverify, db); engine != nil {
log.Error("returning plugin consensus engine") log.Debug("returning plugin consensus engine")
return engine return engine
} }
//end PluGeth code injection
var engine consensus.Engine var engine consensus.Engine
if cliqueConfig != nil { if cliqueConfig != nil {
engine = clique.New(cliqueConfig, db) engine = clique.New(cliqueConfig, db)
} else { } else {

View File

@ -142,7 +142,7 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
// also returned if requested and available. // also returned if requested and available.
// Note: an error is only returned if retrieving the head header has failed. If there are no // Note: an error is only returned if retrieving the head header has failed. If there are no
// retrievable blocks in the specified range then zero block count is returned with no error. // retrievable blocks in the specified range then zero block count is returned with no error.
func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNumber, blocks int) (*types.Block, []*types.Receipt, uint64, int, error) { func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNumber, blocks uint64) (*types.Block, []*types.Receipt, uint64, uint64, error) {
var ( var (
headBlock *types.Header headBlock *types.Header
pendingBlock *types.Block pendingBlock *types.Block
@ -200,8 +200,8 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNum
return nil, nil, 0, 0, nil return nil, nil, 0, 0, nil
} }
// Ensure not trying to retrieve before genesis. // Ensure not trying to retrieve before genesis.
if int(reqEnd+1) < blocks { if uint64(reqEnd+1) < blocks {
blocks = int(reqEnd + 1) blocks = uint64(reqEnd + 1)
} }
return pendingBlock, pendingReceipts, uint64(reqEnd), blocks, nil return pendingBlock, pendingReceipts, uint64(reqEnd), blocks, nil
} }
@ -220,7 +220,7 @@ func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNum
// //
// Note: baseFee includes the next block after the newest of the returned range, because this // Note: baseFee includes the next block after the newest of the returned range, because this
// value can be derived from the newest block. // value can be derived from the newest block.
func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) { func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedLastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) {
if blocks < 1 { if blocks < 1 {
return common.Big0, nil, nil, nil, nil // returning with no data and no error means there are no retrievable blocks return common.Big0, nil, nil, nil, nil // returning with no data and no error means there are no retrievable blocks
} }
@ -249,7 +249,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast
if err != nil || blocks == 0 { if err != nil || blocks == 0 {
return common.Big0, nil, nil, nil, err return common.Big0, nil, nil, nil, err
} }
oldestBlock := lastBlock + 1 - uint64(blocks) oldestBlock := lastBlock + 1 - blocks
var ( var (
next = oldestBlock next = oldestBlock
@ -259,7 +259,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast
for i, p := range rewardPercentiles { for i, p := range rewardPercentiles {
binary.LittleEndian.PutUint64(percentileKey[i*8:(i+1)*8], math.Float64bits(p)) binary.LittleEndian.PutUint64(percentileKey[i*8:(i+1)*8], math.Float64bits(p))
} }
for i := 0; i < maxBlockFetchers && i < blocks; i++ { for i := 0; i < maxBlockFetchers && i < int(blocks); i++ {
go func() { go func() {
for { for {
// Retrieve the next block number to fetch with this goroutine // Retrieve the next block number to fetch with this goroutine
@ -314,7 +314,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast
if fees.err != nil { if fees.err != nil {
return common.Big0, nil, nil, nil, fees.err return common.Big0, nil, nil, nil, fees.err
} }
i := int(fees.blockNumber - oldestBlock) i := fees.blockNumber - oldestBlock
if fees.results.baseFee != nil { if fees.results.baseFee != nil {
reward[i], baseFee[i], baseFee[i+1], gasUsedRatio[i] = fees.results.reward, fees.results.baseFee, fees.results.nextBaseFee, fees.results.gasUsedRatio reward[i], baseFee[i], baseFee[i+1], gasUsedRatio[i] = fees.results.reward, fees.results.baseFee, fees.results.nextBaseFee, fees.results.gasUsedRatio
} else { } else {

View File

@ -28,8 +28,8 @@ import (
func TestFeeHistory(t *testing.T) { func TestFeeHistory(t *testing.T) {
var cases = []struct { var cases = []struct {
pending bool pending bool
maxHeader, maxBlock int maxHeader, maxBlock uint64
count int count uint64
last rpc.BlockNumber last rpc.BlockNumber
percent []float64 percent []float64
expFirst uint64 expFirst uint64

View File

@ -42,8 +42,8 @@ var (
type Config struct { type Config struct {
Blocks int Blocks int
Percentile int Percentile int
MaxHeaderHistory int MaxHeaderHistory uint64
MaxBlockHistory int MaxBlockHistory uint64
Default *big.Int `toml:",omitempty"` Default *big.Int `toml:",omitempty"`
MaxPrice *big.Int `toml:",omitempty"` MaxPrice *big.Int `toml:",omitempty"`
IgnorePrice *big.Int `toml:",omitempty"` IgnorePrice *big.Int `toml:",omitempty"`
@ -71,7 +71,7 @@ type Oracle struct {
fetchLock sync.Mutex fetchLock sync.Mutex
checkBlocks, percentile int checkBlocks, percentile int
maxHeaderHistory, maxBlockHistory int maxHeaderHistory, maxBlockHistory uint64
historyCache *lru.Cache[cacheKey, processedFees] historyCache *lru.Cache[cacheKey, processedFees]
} }

View File

@ -418,7 +418,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP
if err != nil { if err != nil {
return nil, nil return nil, nil
} }
acc, err := accTrie.TryGetAccountByHash(account) acc, err := accTrie.GetAccountByHash(account)
if err != nil || acc == nil { if err != nil || acc == nil {
return nil, nil return nil, nil
} }
@ -510,7 +510,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s
case 1: case 1:
// If we're only retrieving an account trie node, fetch it directly // If we're only retrieving an account trie node, fetch it directly
blob, resolved, err := accTrie.TryGetNode(pathset[0]) blob, resolved, err := accTrie.GetNode(pathset[0])
loads += resolved // always account database reads, even for failures loads += resolved // always account database reads, even for failures
if err != nil { if err != nil {
break break
@ -524,7 +524,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s
if snap == nil { if snap == nil {
// We don't have the requested state snapshotted yet (or it is stale), // We don't have the requested state snapshotted yet (or it is stale),
// but can look up the account via the trie instead. // but can look up the account via the trie instead.
account, err := accTrie.TryGetAccountByHash(common.BytesToHash(pathset[0])) account, err := accTrie.GetAccountByHash(common.BytesToHash(pathset[0]))
loads += 8 // We don't know the exact cost of lookup, this is an estimate loads += 8 // We don't know the exact cost of lookup, this is an estimate
if err != nil || account == nil { if err != nil || account == nil {
break break
@ -545,7 +545,7 @@ func ServiceGetTrieNodesQuery(chain *core.BlockChain, req *GetTrieNodesPacket, s
break break
} }
for _, path := range pathset[1:] { for _, path := range pathset[1:] {
blob, resolved, err := stTrie.TryGetNode(path) blob, resolved, err := stTrie.GetNode(path)
loads += resolved // always account database reads, even for failures loads += resolved // always account database reads, even for failures
if err != nil { if err != nil {
break break

View File

@ -216,7 +216,7 @@ func defaultTrieRequestHandler(t *testPeer, requestId uint64, root common.Hash,
for _, pathset := range paths { for _, pathset := range paths {
switch len(pathset) { switch len(pathset) {
case 1: case 1:
blob, _, err := t.accountTrie.TryGetNode(pathset[0]) blob, _, err := t.accountTrie.GetNode(pathset[0])
if err != nil { if err != nil {
t.logger.Info("Error handling req", "error", err) t.logger.Info("Error handling req", "error", err)
break break
@ -225,7 +225,7 @@ func defaultTrieRequestHandler(t *testPeer, requestId uint64, root common.Hash,
default: default:
account := t.storageTries[(common.BytesToHash(pathset[0]))] account := t.storageTries[(common.BytesToHash(pathset[0]))]
for _, path := range pathset[1:] { for _, path := range pathset[1:] {
blob, _, err := account.TryGetNode(path) blob, _, err := account.GetNode(path)
if err != nil { if err != nil {
t.logger.Info("Error handling req", "error", err) t.logger.Info("Error handling req", "error", err)
break break
@ -1381,7 +1381,7 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) {
}) })
key := key32(i) key := key32(i)
elem := &kv{key, value} elem := &kv{key, value}
accTrie.Update(elem.k, elem.v) accTrie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem) entries = append(entries, elem)
} }
sort.Sort(entries) sort.Sort(entries)
@ -1431,7 +1431,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) {
CodeHash: getCodeHash(uint64(i)), CodeHash: getCodeHash(uint64(i)),
}) })
elem := &kv{boundaries[i].Bytes(), value} elem := &kv{boundaries[i].Bytes(), value}
accTrie.Update(elem.k, elem.v) accTrie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem) entries = append(entries, elem)
} }
// Fill other accounts if required // Fill other accounts if required
@ -1443,7 +1443,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) {
CodeHash: getCodeHash(i), CodeHash: getCodeHash(i),
}) })
elem := &kv{key32(i), value} elem := &kv{key32(i), value}
accTrie.Update(elem.k, elem.v) accTrie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem) entries = append(entries, elem)
} }
sort.Sort(entries) sort.Sort(entries)
@ -1487,7 +1487,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool)
CodeHash: codehash, CodeHash: codehash,
}) })
elem := &kv{key, value} elem := &kv{key, value}
accTrie.Update(elem.k, elem.v) accTrie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem) entries = append(entries, elem)
storageRoots[common.BytesToHash(key)] = stRoot storageRoots[common.BytesToHash(key)] = stRoot
@ -1551,7 +1551,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin
CodeHash: codehash, CodeHash: codehash,
}) })
elem := &kv{key, value} elem := &kv{key, value}
accTrie.Update(elem.k, elem.v) accTrie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem) entries = append(entries, elem)
// we reuse the same one for all accounts // we reuse the same one for all accounts
@ -1599,7 +1599,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas
key := crypto.Keccak256Hash(slotKey[:]) key := crypto.Keccak256Hash(slotKey[:])
elem := &kv{key[:], rlpSlotValue} elem := &kv{key[:], rlpSlotValue}
trie.Update(elem.k, elem.v) trie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem) entries = append(entries, elem)
} }
sort.Sort(entries) sort.Sort(entries)
@ -1638,7 +1638,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo
val := []byte{0xde, 0xad, 0xbe, 0xef} val := []byte{0xde, 0xad, 0xbe, 0xef}
elem := &kv{key[:], val} elem := &kv{key[:], val}
trie.Update(elem.k, elem.v) trie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem) entries = append(entries, elem)
} }
// Fill other slots if required // Fill other slots if required
@ -1650,7 +1650,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo
rlpSlotValue, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(slotValue[:])) rlpSlotValue, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(slotValue[:]))
elem := &kv{key[:], rlpSlotValue} elem := &kv{key[:], rlpSlotValue}
trie.Update(elem.k, elem.v) trie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem) entries = append(entries, elem)
} }
sort.Sort(entries) sort.Sort(entries)

View File

@ -805,7 +805,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
// Swap out the noop logger to the standard tracer // Swap out the noop logger to the standard tracer
writer = bufio.NewWriter(dump) writer = bufio.NewWriter(dump)
vmConf = vm.Config{ vmConf = vm.Config{
Debug: true,
Tracer: logger.NewJSONLogger(&logConfig, writer), Tracer: logger.NewJSONLogger(&logConfig, writer),
EnablePreimageRecording: true, EnablePreimageRecording: true,
} }
@ -975,7 +974,7 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte
} }
// end PluGeth injection // end PluGeth injection
} }
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true})
// Define a meaningful timeout of a single transaction trace // Define a meaningful timeout of a single transaction trace
if config.Timeout != nil { if config.Timeout != nil {

View File

@ -835,8 +835,8 @@ func TestTraceChain(t *testing.T) {
signer := types.HomesteadSigner{} signer := types.HomesteadSigner{}
var ( var (
ref uint32 // total refs has made ref atomic.Uint32 // total refs has made
rel uint32 // total rels has made rel atomic.Uint32 // total rels has made
nonce uint64 nonce uint64
) )
backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
@ -849,8 +849,8 @@ func TestTraceChain(t *testing.T) {
nonce += 1 nonce += 1
} }
}) })
backend.refHook = func() { atomic.AddUint32(&ref, 1) } backend.refHook = func() { ref.Add(1) }
backend.relHook = func() { atomic.AddUint32(&rel, 1) } backend.relHook = func() { rel.Add(1) }
api := NewAPI(backend) api := NewAPI(backend)
single := `{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}` single := `{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}`
@ -863,7 +863,8 @@ func TestTraceChain(t *testing.T) {
{10, 20, nil}, // the middle chain range, blocks [11, 20] {10, 20, nil}, // the middle chain range, blocks [11, 20]
} }
for _, c := range cases { for _, c := range cases {
ref, rel = 0, 0 // clean up the counters ref.Store(0)
rel.Store(0)
from, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.start)) from, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.start))
to, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.end)) to, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.end))
@ -888,8 +889,9 @@ func TestTraceChain(t *testing.T) {
if next != c.end+1 { if next != c.end+1 {
t.Error("Missing tracing block") t.Error("Missing tracing block")
} }
if ref != rel {
t.Errorf("Ref and deref actions are not equal, ref %d rel %d", ref, rel) if nref, nrel := ref.Load(), rel.Load(); nref != nrel {
t.Errorf("Ref and deref actions are not equal, ref %d rel %d", nref, nrel)
} }
} }
} }

View File

@ -31,7 +31,6 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
@ -144,7 +143,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to create call tracer: %v", err) t.Fatalf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
msg, err := core.TransactionToMessage(tx, signer, nil) msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
@ -247,7 +246,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
if err != nil { if err != nil {
b.Fatalf("failed to create call tracer: %v", err) b.Fatalf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
snap := statedb.Snapshot() snap := statedb.Snapshot()
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if _, err = st.TransitionDb(); err != nil { if _, err = st.TransitionDb(); err != nil {
@ -260,30 +259,15 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
} }
} }
// TestZeroValueToNotExitCall tests the calltracer(s) on the following: func TestInternals(t *testing.T) {
// Tx to A, A calls B with zero value. B does not already exist. var (
// Expected: that enter/exit is invoked and the inner call is shown in the result to = common.HexToAddress("0x00000000000000000000000000000000deadbeef")
func TestZeroValueToNotExitCall(t *testing.T) { origin = common.HexToAddress("0x00000000000000000000000000000000feed")
var to = common.HexToAddress("0x00000000000000000000000000000000deadbeef") txContext = vm.TxContext{
privkey, err := crypto.HexToECDSA("0000000000000000deadbeef00000000000000000000000000000000deadbeef")
if err != nil {
t.Fatalf("err %v", err)
}
signer := types.NewEIP155Signer(big.NewInt(1))
tx, err := types.SignNewTx(privkey, signer, &types.LegacyTx{
GasPrice: big.NewInt(0),
Gas: 50000,
To: &to,
})
if err != nil {
t.Fatalf("err %v", err)
}
origin, _ := signer.Sender(tx)
txContext := vm.TxContext{
Origin: origin, Origin: origin,
GasPrice: big.NewInt(1), GasPrice: big.NewInt(1),
} }
context := vm.BlockContext{ context = vm.BlockContext{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
Coinbase: common.Address{}, Coinbase: common.Address{},
@ -292,43 +276,104 @@ func TestZeroValueToNotExitCall(t *testing.T) {
Difficulty: big.NewInt(0x30000), Difficulty: big.NewInt(0x30000),
GasLimit: uint64(6000000), GasLimit: uint64(6000000),
} }
var code = []byte{ )
byte(vm.PUSH1), 0x0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), // in and outs zero mkTracer := func(name string, cfg json.RawMessage) tracers.Tracer {
byte(vm.DUP1), byte(vm.PUSH1), 0xff, byte(vm.GAS), // value=0,address=0xff, gas=GAS tr, err := tracers.DefaultDirectory.New(name, nil, cfg)
byte(vm.CALL),
}
var alloc = core.GenesisAlloc{
to: core.GenesisAccount{
Nonce: 1,
Code: code,
},
origin: core.GenesisAccount{
Nonce: 0,
Balance: big.NewInt(500000000000000),
},
}
_, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false)
// Create the tracer, the EVM environment and run it
tracer, err := tracers.DefaultDirectory.New("callTracer", nil, nil)
if err != nil { if err != nil {
t.Fatalf("failed to create call tracer: %v", err) t.Fatalf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) return tr
msg, err := core.TransactionToMessage(tx, signer, nil) }
for _, tc := range []struct {
name string
code []byte
tracer tracers.Tracer
want string
}{
{
// TestZeroValueToNotExitCall tests the calltracer(s) on the following:
// Tx to A, A calls B with zero value. B does not already exist.
// Expected: that enter/exit is invoked and the inner call is shown in the result
name: "ZeroValueToNotExitCall",
code: []byte{
byte(vm.PUSH1), 0x0, byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), // in and outs zero
byte(vm.DUP1), byte(vm.PUSH1), 0xff, byte(vm.GAS), // value=0,address=0xff, gas=GAS
byte(vm.CALL),
},
tracer: mkTracer("callTracer", nil),
want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`,
},
{
name: "Stack depletion in LOG0",
code: []byte{byte(vm.LOG3)},
tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)),
want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`,
},
{
name: "Mem expansion in LOG0",
code: []byte{
byte(vm.PUSH1), 0x1,
byte(vm.PUSH1), 0x0,
byte(vm.MSTORE),
byte(vm.PUSH1), 0xff,
byte(vm.PUSH1), 0x0,
byte(vm.LOG0),
},
tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)),
want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`,
},
{
// Leads to OOM on the prestate tracer
name: "Prestate-tracer - mem expansion in CREATE2",
code: []byte{
byte(vm.PUSH1), 0x1,
byte(vm.PUSH1), 0x0,
byte(vm.MSTORE),
byte(vm.PUSH1), 0x1,
byte(vm.PUSH5), 0xff, 0xff, 0xff, 0xff, 0xff,
byte(vm.PUSH1), 0x1,
byte(vm.PUSH1), 0x0,
byte(vm.CREATE2),
byte(vm.PUSH1), 0xff,
byte(vm.PUSH1), 0x0,
byte(vm.LOG0),
},
tracer: mkTracer("prestateTracer", json.RawMessage(`{ "withLog": true }`)),
want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52640350"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`,
},
} {
_, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(),
core.GenesisAlloc{
to: core.GenesisAccount{
Code: tc.code,
},
origin: core.GenesisAccount{
Balance: big.NewInt(500000000000000),
},
}, false)
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer})
msg := &core.Message{
To: &to,
From: origin,
Value: big.NewInt(0),
GasLimit: 50000,
GasPrice: big.NewInt(0),
GasFeeCap: big.NewInt(0),
GasTipCap: big.NewInt(0),
SkipAccountChecks: false,
}
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
if _, err := st.TransitionDb(); err != nil {
t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err)
}
// Retrieve the trace result and compare against the expected
res, err := tc.tracer.GetResult()
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("test %v: failed to retrieve trace result: %v", tc.name, err)
} }
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if string(res) != tc.want {
if _, err = st.TransitionDb(); err != nil { t.Fatalf("test %v: trace mismatch\n have: %v\n want: %v\n", tc.name, string(res), tc.want)
t.Fatalf("failed to execute transaction: %v", err)
} }
// Retrieve the trace result and compare against the etalon
res, err := tracer.GetResult()
if err != nil {
t.Fatalf("failed to retrieve trace result: %v", err)
}
wantStr := `{"from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","gas":"0x7148","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`
if string(res) != wantStr {
t.Fatalf("trace mismatch\n have: %v\n want: %v\n", string(res), wantStr)
} }
} }

View File

@ -107,7 +107,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
if err != nil { if err != nil {
return fmt.Errorf("failed to create call tracer: %v", err) return fmt.Errorf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
msg, err := core.TransactionToMessage(tx, signer, nil) msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil { if err != nil {
@ -124,8 +124,8 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve trace result: %v", err) return fmt.Errorf("failed to retrieve trace result: %v", err)
} }
ret := new([]flatCallTrace) ret := make([]flatCallTrace, 0)
if err := json.Unmarshal(res, ret); err != nil { if err := json.Unmarshal(res, &ret); err != nil {
return fmt.Errorf("failed to unmarshal trace result: %v", err) return fmt.Errorf("failed to unmarshal trace result: %v", err)
} }
if !jsonEqualFlat(ret, test.Result) { if !jsonEqualFlat(ret, test.Result) {

View File

@ -114,7 +114,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to create call tracer: %v", err) t.Fatalf("failed to create call tracer: %v", err)
} }
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
msg, err := core.TransactionToMessage(tx, signer, nil) msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)

View File

@ -47,7 +47,7 @@
"input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f", "input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f",
"result": { "result": {
"from": "0x13e4acefe6a6700604929946e70e6443e4e73447", "from": "0x13e4acefe6a6700604929946e70e6443e4e73447",
"gas": "0x5e106", "gas": "0x897be",
"gasUsed": "0x897be", "gasUsed": "0x897be",
"input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11", "input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11",
"output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029", "output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029",

View File

@ -399,7 +399,7 @@
} }
], ],
"from": "0x70c9217d814985faef62b124420f8dfbddd96433", "from": "0x70c9217d814985faef62b124420f8dfbddd96433",
"gas": "0x37b38", "gas": "0x3d090",
"gasUsed": "0x1810b", "gasUsed": "0x1810b",
"input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000", "input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000",
"to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b", "to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b",

View File

@ -87,7 +87,7 @@
} }
], ],
"from": "0xa529806c67cc6486d4d62024471772f47f6fd672", "from": "0xa529806c67cc6486d4d62024471772f47f6fd672",
"gas": "0x2d6e28", "gas": "0x2dc6c0",
"gasUsed": "0xbd55", "gasUsed": "0xbd55",
"input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e", "input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e",
"to": "0x269296dddce321a6bcbaa2f0181127593d732cba", "to": "0x269296dddce321a6bcbaa2f0181127593d732cba",

View File

@ -67,7 +67,7 @@
], ],
"error": "invalid jump destination", "error": "invalid jump destination",
"from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8", "from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8",
"gas": "0x435c8", "gas": "0x493e0",
"gasUsed": "0x493e0", "gasUsed": "0x493e0",
"input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8", "input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8",
"to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a", "to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a",

Some files were not shown because too many files have changed in this diff Show More