chore: rename geth to aiigo

This commit is contained in:
John Fucking Wick 2025-04-20 13:34:31 +08:00 committed by GitHub
commit ccd6234846
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
157 changed files with 6584 additions and 543 deletions

View file

@ -30,11 +30,11 @@ Please make sure your contributions adhere to our coding guidelines:
Before you submit a feature request, please check and make sure that it isn't Before you submit a feature request, please check and make sure that it isn't
possible through some other means. The JavaScript-enabled console is a powerful possible through some other means. The JavaScript-enabled console is a powerful
feature in the right hands. Please check our feature in the right hands. Please check our
[Geth documentation page](https://geth.ethereum.org/docs/) for more info [Aiigo documentation page](https://aiigo.ethereum.org/docs/) for more info
and help. and help.
## Configuration, dependencies, and tests ## Configuration, dependencies, and tests
Please see the [Developers' Guide](https://geth.ethereum.org/docs/developers/geth-developer/dev-guide) Please see the [Developers' Guide](https://aiigo.ethereum.org/docs/developers/aiigo-developer/dev-guide)
for more details on configuring your environment, managing project dependencies for more details on configuring your environment, managing project dependencies
and testing procedures. and testing procedures.

View file

@ -8,7 +8,7 @@ assignees: ''
#### System information #### System information
Geth version: `geth version` Aiigo version: `aiigo version`
CL client & version: e.g. lighthouse/nimbus/prysm@v1.0.0 CL client & version: e.g. lighthouse/nimbus/prysm@v1.0.0
OS & Version: Windows/Linux/OSX OS & Version: Windows/Linux/OSX
Commit hash : (if `develop`) Commit hash : (if `develop`)

14
.gitignore vendored
View file

@ -21,14 +21,14 @@
/build/_workspace/ /build/_workspace/
/build/cache/ /build/cache/
/build/bin/ /build/bin/
/geth*.zip /aiigo*.zip
# used by the build/ci.go archive + upload tool # used by the build/ci.go archive + upload tool
/geth*.tar.gz /aiigo*.tar.gz
/geth*.tar.gz.sig /aiigo*.tar.gz.sig
/geth*.tar.gz.asc /aiigo*.tar.gz.asc
/geth*.zip.sig /aiigo*.zip.sig
/geth*.zip.asc /aiigo*.zip.asc
# travis # travis
@ -53,6 +53,6 @@ cmd/devp2p/devp2p
cmd/era/era cmd/era/era
cmd/ethkey/ethkey cmd/ethkey/ethkey
cmd/evm/evm cmd/evm/evm
cmd/geth/geth cmd/aiigo/aiigo
cmd/rlpdump/rlpdump cmd/rlpdump/rlpdump
cmd/workload/workload cmd/workload/workload

View file

@ -35,26 +35,26 @@ jobs:
script: script:
# build amd64 # build amd64
- go run build/ci.go install -dlgo - go run build/ci.go install -dlgo
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload aiigostore/builds
# build 386 # build 386
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
- git status --porcelain - git status --porcelain
- go run build/ci.go install -dlgo -arch 386 - go run build/ci.go install -dlgo -arch 386
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload aiigostore/builds
# Switch over GCC to cross compilation (breaks 386, hence why do it here only) # Switch over GCC to cross compilation (breaks 386, hence why do it here only)
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross - sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross
- sudo ln -s /usr/include/asm-generic /usr/include/asm - sudo ln -s /usr/include/asm-generic /usr/include/asm
- GOARM=5 go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabi-gcc - GOARM=5 go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabi-gcc
- GOARM=5 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - GOARM=5 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload aiigostore/builds
- GOARM=6 go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabi-gcc - GOARM=6 go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabi-gcc
- GOARM=6 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - GOARM=6 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload aiigostore/builds
- GOARM=7 go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabihf-gcc - GOARM=7 go run build/ci.go install -dlgo -arch arm -cc arm-linux-gnueabihf-gcc
- GOARM=7 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - GOARM=7 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload aiigostore/builds
- go run build/ci.go install -dlgo -arch arm64 -cc aarch64-linux-gnu-gcc - go run build/ci.go install -dlgo -arch arm64 -cc aarch64-linux-gnu-gcc
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload aiigostore/builds
# These builders run the tests # These builders run the tests
- stage: build - stage: build
@ -88,7 +88,7 @@ jobs:
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install devscripts debhelper dput fakeroot - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install devscripts debhelper dput fakeroot
script: script:
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts - echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" - go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user aiigo-ci -signer "Go Ethereum Linux Builder <aiigo-ci@ethereum.org>"
# This builder does the Azure archive purges to avoid accumulating junk # This builder does the Azure archive purges to avoid accumulating junk
- stage: build - stage: build
@ -101,7 +101,7 @@ jobs:
git: git:
submodules: false # avoid cloning ethereum/tests submodules: false # avoid cloning ethereum/tests
script: script:
- go run build/ci.go purge -store gethstore/builds -days 14 - go run build/ci.go purge -store aiigostore/builds -days 14
# This builder executes race tests # This builder executes race tests
- stage: build - stage: build

View file

@ -3,7 +3,7 @@ ARG COMMIT=""
ARG VERSION="" ARG VERSION=""
ARG BUILDNUM="" ARG BUILDNUM=""
# Build Geth in a stock Go builder container # Build Aiigo in a stock Go builder container
FROM golang:1.24-alpine AS builder FROM golang:1.24-alpine AS builder
RUN apk add --no-cache gcc musl-dev linux-headers git RUN apk add --no-cache gcc musl-dev linux-headers git
@ -14,16 +14,16 @@ COPY go.sum /go-ethereum/
RUN cd /go-ethereum && go mod download RUN cd /go-ethereum && go mod download
ADD . /go-ethereum ADD . /go-ethereum
RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/aiigo
# Pull Geth into a second stage deploy alpine container # Pull Aiigo into a second stage deploy alpine container
FROM alpine:latest FROM alpine:latest
RUN apk add --no-cache ca-certificates RUN apk add --no-cache ca-certificates
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/ COPY --from=builder /go-ethereum/build/bin/aiigo /usr/local/bin/
EXPOSE 8545 8546 30303 30303/udp EXPOSE 8545 8546 30303 30303/udp
ENTRYPOINT ["geth"] ENTRYPOINT ["aiigo"]
# Add some metadata labels to help programmatic image consumption # Add some metadata labels to help programmatic image consumption
ARG COMMIT="" ARG COMMIT=""

View file

@ -3,7 +3,7 @@ ARG COMMIT=""
ARG VERSION="" ARG VERSION=""
ARG BUILDNUM="" ARG BUILDNUM=""
# Build Geth in a stock Go builder container # Build Aiigo in a stock Go builder container
FROM golang:1.24-alpine AS builder FROM golang:1.24-alpine AS builder
RUN apk add --no-cache gcc musl-dev linux-headers git RUN apk add --no-cache gcc musl-dev linux-headers git
@ -19,7 +19,7 @@ ADD . /go-ethereum
# makes it so that under certain circumstances, the docker layer can be cached, # makes it so that under certain circumstances, the docker layer can be cached,
# and the builder can jump to the next (build all) command, with the go cache fully loaded. # and the builder can jump to the next (build all) command, with the go cache fully loaded.
# #
RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/geth RUN cd /go-ethereum && go run build/ci.go install -static ./cmd/aiigo
RUN cd /go-ethereum && go run build/ci.go install -static RUN cd /go-ethereum && go run build/ci.go install -static

View file

@ -2,17 +2,17 @@
# with Go source code. If you know what GOPATH is then you probably # with Go source code. If you know what GOPATH is then you probably
# don't need to bother with make. # don't need to bother with make.
.PHONY: geth all test lint fmt clean devtools help .PHONY: aiigo all test lint fmt clean devtools help
GOBIN = ./build/bin GOBIN = ./build/bin
GO ?= latest GO ?= latest
GORUN = go run GORUN = go run
#? geth: Build geth. #? aiigo: Build aiigo.
geth: aiigo:
$(GORUN) build/ci.go install ./cmd/geth $(GORUN) build/ci.go install ./cmd/aiigo
@echo "Done building." @echo "Done building."
@echo "Run \"$(GOBIN)/geth\" to launch geth." @echo "Run \"$(GOBIN)/aiigo\" to launch aiigo."
#? all: Build all packages and executables. #? all: Build all packages and executables.
all: all:

View file

@ -10,17 +10,17 @@ https://pkg.go.dev/badge/github.com/ethereum/go-ethereum
[![Discord](https://img.shields.io/badge/discord-join%20chat-blue.svg)](https://discord.gg/nthXNEv) [![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 Automated builds are available for stable releases and the unstable master branch. Binary
archives are published at https://geth.ethereum.org/downloads/. archives are published at https://aiigo.ethereum.org/downloads/.
## Building the source ## Building the source
For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth). For prerequisites and detailed build instructions please read the [Installation Instructions](https://aiigo.ethereum.org/docs/getting-started/installing-aiigo).
Building `geth` requires both a Go (version 1.23 or later) and a C compiler. You can install Building `aiigo` requires both a Go (version 1.23 or later) and a C compiler. You can install
them using your favourite package manager. Once the dependencies are installed, run them using your favourite package manager. Once the dependencies are installed, run
```shell ```shell
make geth make aiigo
``` ```
or, to build the full suite of utilities: or, to build the full suite of utilities:
@ -36,19 +36,19 @@ directory.
| Command | Description | | Command | Description |
| :--------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | :--------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`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. | | **`aiigo`** | 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. `aiigo --help` and the [CLI page](https://aiigo.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`. | | `clef` | Stand-alone signing tool, which can be used as a backend signer for `aiigo`. |
| `devp2p` | Utilities to interact with nodes on the networking layer, without running a full blockchain. | | `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. | | `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://aiigo.ethereum.org/docs/developers/dapp-developer/native-bindings) page for details. |
| `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`). | | `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`). | | `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` ## Running `aiigo`
Going through all the possible command line flags is out of scope here (please consult our Going through all the possible command line flags is out of scope here (please consult our
[CLI Wiki page](https://geth.ethereum.org/docs/fundamentals/command-line-options)), [CLI Wiki page](https://aiigo.ethereum.org/docs/fundamentals/command-line-options)),
but we've enumerated a few common parameter combos to get you up to speed quickly but we've enumerated a few common parameter combos to get you up to speed quickly
on how you can run your own `geth` instance. on how you can run your own `aiigo` instance.
### Hardware Requirements ### Hardware Requirements
@ -74,19 +74,19 @@ particular use case, the user doesn't care about years-old historical data, so w
sync quickly to the current state of the network. To do so: sync quickly to the current state of the network. To do so:
```shell ```shell
$ geth console $ aiigo console
``` ```
This command will: This command will:
* Start `geth` in snap sync mode (default, can be changed with the `--syncmode` flag), * Start `aiigo` 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 causing it to download more data in exchange for avoiding processing the entire history
of the Ethereum network, which is very CPU intensive. 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), * Start the built-in interactive [JavaScript console](https://aiigo.ethereum.org/docs/interacting-with-aiigo/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) (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), (note: the `web3` version bundled within `aiigo` 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). as well as `aiigo`'s own [management APIs](https://aiigo.ethereum.org/docs/interacting-with-aiigo/rpc).
This tool is optional and if you leave it out you can always attach it to an already running This tool is optional and if you leave it out you can always attach it to an already running
`geth` instance with `geth attach`. `aiigo` instance with `aiigo attach`.
### A Full node on the Holesky test network ### A Full node on the Holesky test network
@ -97,45 +97,45 @@ network, you want to join the **test** network with your node, which is fully eq
the main network, but with play-Ether only. the main network, but with play-Ether only.
```shell ```shell
$ geth --holesky console $ aiigo --holesky console
``` ```
The `console` subcommand has the same meaning as above and is equally The `console` subcommand has the same meaning as above and is equally
useful on the testnet too. useful on the testnet too.
Specifying the `--holesky` flag, however, will reconfigure your `geth` instance a bit: Specifying the `--holesky` flag, however, will reconfigure your `aiigo` instance a bit:
* Instead of connecting to the main Ethereum network, the client will connect to the Holesky * Instead of connecting to the main Ethereum network, the client will connect to the Holesky
test network, which uses different P2P bootnodes, different network IDs and genesis test network, which uses different P2P bootnodes, different network IDs and genesis
states. states.
* Instead of using the default data directory (`~/.ethereum` on Linux for example), `geth` * Instead of using the default data directory (`~/.ethereum` on Linux for example), `aiigo`
will nest itself one level deeper into a `holesky` subfolder (`~/.ethereum/holesky` on will nest itself one level deeper into a `holesky` subfolder (`~/.ethereum/holesky` on
Linux). Note, on OSX and Linux this also means that attaching to a running testnet node 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 requires the use of a custom endpoint since `aiigo attach` will try to attach to a
production node endpoint by default, e.g., production node endpoint by default, e.g.,
`geth attach <datadir>/holesky/geth.ipc`. Windows users are not affected by `aiigo attach <datadir>/holesky/aiigo.ipc`. Windows users are not affected by
this. this.
*Note: Although some internal protective measures prevent transactions from *Note: Although some internal protective measures prevent transactions from
crossing over between the main network and test network, you should always crossing over between the main network and test network, you should always
use separate accounts for play and real money. Unless you manually move 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, `aiigo` will by default correctly separate the two networks and will not make any
accounts available between them.* accounts available between them.*
### Configuration ### Configuration
As an alternative to passing the numerous flags to the `geth` binary, you can also pass a As an alternative to passing the numerous flags to the `aiigo` binary, you can also pass a
configuration file via: configuration file via:
```shell ```shell
$ geth --config /path/to/your_config.toml $ aiigo --config /path/to/your_config.toml
``` ```
To get an idea of how the file should look like you can use the `dumpconfig` subcommand to To get an idea of how the file should look like you can use the `dumpconfig` subcommand to
export your existing configuration: export your existing configuration:
```shell ```shell
$ geth --your-favourite-flags dumpconfig $ aiigo --your-favourite-flags dumpconfig
``` ```
#### Docker quick start #### Docker quick start
@ -149,25 +149,25 @@ docker run -d --name ethereum-node -v /Users/alice/ethereum:/root \
ethereum/client-go ethereum/client-go
``` ```
This will start `geth` in snap-sync mode with a DB memory allowance of 1GB, as the This will start `aiigo` 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 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 saving your blockchain as well as map the default ports. There is also an `alpine` tag
available for a slim version of the image. 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 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 and/or hosts. By default, `aiigo` binds to the local interface and RPC endpoints are not
accessible from the outside. accessible from the outside.
### Programmatically interfacing `geth` nodes ### Programmatically interfacing `aiigo` nodes
As a developer, sooner rather than later you'll want to start interacting with `geth` and the As a developer, sooner rather than later you'll want to start interacting with `aiigo` and the
Ethereum network via your own programs and not manually through the console. To aid 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/) this, `aiigo` 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)). and [`aiigo` specific APIs](https://aiigo.ethereum.org/docs/interacting-with-aiigo/rpc)).
These can be exposed via HTTP, WebSockets and IPC (UNIX sockets on UNIX based These can be exposed via HTTP, WebSockets and IPC (UNIX sockets on UNIX based
platforms, and named pipes on Windows). platforms, and named pipes on Windows).
The IPC interface is enabled by default and exposes all the APIs supported by `geth`, The IPC interface is enabled by default and exposes all the APIs supported by `aiigo`,
whereas the HTTP and WS interfaces need to manually be enabled and only expose a 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 subset of APIs due to security reasons. These can be turned on/off and configured as
you'd expect. you'd expect.
@ -188,7 +188,7 @@ HTTP based JSON-RPC API options:
* `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it) * `--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 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 connect via HTTP, WS or IPC to a `aiigo` node configured with the above flags and you'll
need to speak [JSON-RPC](https://www.jsonrpc.org/specification) on all transports. You need to speak [JSON-RPC](https://www.jsonrpc.org/specification) on all transports. You
can reuse the same connection for multiple requests! can reuse the same connection for multiple requests!
@ -204,13 +204,13 @@ Maintaining your own private network is more involved as a lot of configurations
granted in the official networks need to be manually set up. granted in the official networks need to be manually set up.
Unfortunately since [the Merge](https://ethereum.org/en/roadmap/merge/) it is no longer possible Unfortunately since [the Merge](https://ethereum.org/en/roadmap/merge/) it is no longer possible
to easily set up a network of geth nodes without also setting up a corresponding beacon chain. to easily set up a network of aiigo nodes without also setting up a corresponding beacon chain.
There are three different solutions depending on your use case: There are three different solutions depending on your use case:
* If you are looking for a simple way to test smart contracts from go in your CI, you can use the [Simulated Backend](https://geth.ethereum.org/docs/developers/dapp-developer/native-bindings#blockchain-simulator). * If you are looking for a simple way to test smart contracts from go in your CI, you can use the [Simulated Backend](https://aiigo.ethereum.org/docs/developers/dapp-developer/native-bindings#blockchain-simulator).
* If you want a convenient single node environment for testing, you can use our [Dev Mode](https://geth.ethereum.org/docs/developers/dapp-developer/dev-mode). * If you want a convenient single node environment for testing, you can use our [Dev Mode](https://aiigo.ethereum.org/docs/developers/dapp-developer/dev-mode).
* If you are looking for a multiple node test network, you can set one up quite easily with [Kurtosis](https://geth.ethereum.org/docs/fundamentals/kurtosis). * If you are looking for a multiple node test network, you can set one up quite easily with [Kurtosis](https://aiigo.ethereum.org/docs/fundamentals/kurtosis).
## Contribution ## Contribution
@ -234,15 +234,15 @@ Please make sure your contributions adhere to our coding guidelines:
* Commit messages should be prefixed with the package(s) they modify. * Commit messages should be prefixed with the package(s) they modify.
* E.g. "eth, rpc: make trace configs optional" * E.g. "eth, rpc: make trace configs optional"
Please see the [Developers' Guide](https://geth.ethereum.org/docs/developers/geth-developer/dev-guide) Please see the [Developers' Guide](https://aiigo.ethereum.org/docs/developers/aiigo-developer/dev-guide)
for more details on configuring your environment, managing project dependencies, and for more details on configuring your environment, managing project dependencies, and
testing procedures. testing procedures.
### Contributing to geth.ethereum.org ### Contributing to aiigo.ethereum.org
For contributions to the [go-ethereum website](https://geth.ethereum.org), please checkout and raise pull requests against the `website` branch. For contributions to the [go-ethereum website](https://aiigo.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 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. [contributing](https://aiigo.ethereum.org/docs/developers/aiigo-developer/contributing) page of the website.
## License ## License

View file

@ -10,7 +10,7 @@ Audit reports are published in the `docs` folder: https://github.com/ethereum/go
| Scope | Date | Report Link | | Scope | Date | Report Link |
| ------- | ------- | ----------- | | ------- | ------- | ----------- |
| `geth` | 20170425 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2017-04-25_Geth-audit_Truesec.pdf) | | `aiigo` | 20170425 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2017-04-25_Aiigo-audit_Truesec.pdf) |
| `clef` | 20180914 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2018-09-14_Clef-audit_NCC.pdf) | | `clef` | 20180914 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2018-09-14_Clef-audit_NCC.pdf) |
| `Discv5` | 20191015 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2019-10-15_Discv5_audit_LeastAuthority.pdf) | | `Discv5` | 20191015 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2019-10-15_Discv5_audit_LeastAuthority.pdf) |
| `Discv5` | 20200124 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2020-01-24_DiscV5_audit_Cure53.pdf) | | `Discv5` | 20200124 | [pdf](https://github.com/ethereum/go-ethereum/blob/master/docs/audits/2020-01-24_DiscV5_audit_Cure53.pdf) |
@ -21,7 +21,7 @@ Audit reports are published in the `docs` folder: https://github.com/ethereum/go
To find out how to disclose a vulnerability in Ethereum visit [https://bounty.ethereum.org](https://bounty.ethereum.org) or email bounty@ethereum.org. Please read the [disclosure page](https://github.com/ethereum/go-ethereum/security/advisories?state=published) for more information about publicly disclosed security vulnerabilities. To find out how to disclose a vulnerability in Ethereum visit [https://bounty.ethereum.org](https://bounty.ethereum.org) or email bounty@ethereum.org. Please read the [disclosure page](https://github.com/ethereum/go-ethereum/security/advisories?state=published) for more information about publicly disclosed security vulnerabilities.
Use the built-in `geth version-check` feature to check whether the software is affected by any known vulnerability. This command will fetch the latest [`vulnerabilities.json`](https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json) file which contains known security vulnerabilities concerning `geth`, and cross-check the data against its own version number. Use the built-in `aiigo version-check` feature to check whether the software is affected by any known vulnerability. This command will fetch the latest [`vulnerabilities.json`](https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities.json) file which contains known security vulnerabilities concerning `aiigo`, and cross-check the data against its own version number.
The following key may be used to communicate sensitive information to developers. The following key may be used to communicate sensitive information to developers.

View file

@ -17,7 +17,7 @@
// Package abigen generates Ethereum contract Go bindings. // Package abigen generates Ethereum contract Go bindings.
// //
// Detailed usage document and tutorial available on the go-ethereum Wiki page: // Detailed usage document and tutorial available on the go-ethereum Wiki page:
// https://geth.ethereum.org/docs/developers/dapp-developer/native-bindings // https://aiigo.ethereum.org/docs/developers/dapp-developer/native-bindings
package abigen package abigen
import ( import (

View file

@ -102,7 +102,7 @@ func (am *Manager) Close() error {
} }
// AddBackend starts the tracking of an additional backend for wallet updates. // AddBackend starts the tracking of an additional backend for wallet updates.
// cmd/geth assumes once this func returns the backends have been already integrated. // cmd/aiigo assumes once this func returns the backends have been already integrated.
func (am *Manager) AddBackend(backend Backend) { func (am *Manager) AddBackend(backend Backend) {
done := make(chan struct{}) done := make(chan struct{})
am.newBackends <- newBackendEvent{backend, done} am.newBackends <- newBackendEvent{backend, done}

View file

@ -22,13 +22,13 @@
At the end of this process, you will be provided with a PIN, a PUK and a pairing password. Write them down, you'll need them shortly. At the end of this process, you will be provided with a PIN, a PUK and a pairing password. Write them down, you'll need them shortly.
Start `geth` with the `console` command. You will notice the following warning: Start `aiigo` with the `console` command. You will notice the following warning:
``` ```
WARN [04-09|16:58:38.898] Failed to open wallet url=keycard://044def09 err="smartcard: pairing password needed" WARN [04-09|16:58:38.898] Failed to open wallet url=keycard://044def09 err="smartcard: pairing password needed"
``` ```
Write down the URL (`keycard://044def09` in this example). Then ask `geth` to open the wallet: Write down the URL (`keycard://044def09` in this example). Then ask `aiigo` to open the wallet:
``` ```
> personal.openWallet("keycard://044def09", "pairing password") > personal.openWallet("keycard://044def09", "pairing password")
@ -82,7 +82,7 @@
## Usage ## Usage
1. Start `geth` with the `console` command 1. Start `aiigo` with the `console` command
2. Check the card's URL by checking `personal.listWallets`: 2. Check the card's URL by checking `personal.listWallets`:
``` ```
@ -102,5 +102,5 @@ personal.openWallet("keycard://a4d73015")
## Known issues ## Known issues
* Starting geth with a valid card seems to make firefox crash. * Starting aiigo with a valid card seems to make firefox crash.
* PCSC version 4.4 should work, but is currently untested * PCSC version 4.4 should work, but is currently untested

View file

@ -53,7 +53,7 @@ for:
- go run build/ci.go install -dlgo -arch %GETH_ARCH% -cc %GETH_CC% - go run build/ci.go install -dlgo -arch %GETH_ARCH% -cc %GETH_CC%
after_build: after_build:
# Upload builds. Note that ci.go makes this a no-op PR builds. # Upload builds. Note that ci.go makes this a no-op PR builds.
- go run build/ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds - go run build/ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload aiigostore/builds
- go run build/ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload gethstore/builds - go run build/ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload aiigostore/builds
test_script: test_script:
- go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% -short - go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% -short

View file

@ -22,7 +22,7 @@ import (
) )
// EngineAPIError is a standardized error message between consensus and execution // EngineAPIError is a standardized error message between consensus and execution
// clients, also containing any custom error message Geth might include. // clients, also containing any custom error message Aiigo might include.
type EngineAPIError struct { type EngineAPIError struct {
code int code int
msg string msg string

View file

@ -8,7 +8,7 @@ xcodebuild -version
# -- Build for macOS and upload to Azure # -- Build for macOS and upload to Azure
go run build/ci.go install -dlgo go run build/ci.go install -dlgo
go run build/ci.go archive -type tar # -signer OSX_SIGNING_KEY -upload gethstore/builds go run build/ci.go archive -type tar # -signer OSX_SIGNING_KEY -upload aiigostore/builds
# # -- CocoaPods # # -- CocoaPods
# gem uninstall cocoapods -a -x # gem uninstall cocoapods -a -x
@ -19,4 +19,4 @@ go run build/ci.go archive -type tar # -signer OSX_SIGNING_KEY -upload gethstore
# pod setup --verbose # pod setup --verbose
# # -- Build for iOS and upload to Azure # # -- Build for iOS and upload to Azure
# go run build/ci.go xcode -signer IOS_SIGNING_KEY -upload gethstore/builds # go run build/ci.go xcode -signer IOS_SIGNING_KEY -upload aiigostore/builds

View file

@ -14,4 +14,4 @@ mkdir -p ~/.ssh
echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
# Build the source package and upload. # Build the source package and upload.
go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>" go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user aiigo-ci -signer "Go Ethereum Linux Builder <aiigo-ci@ethereum.org>"

View file

@ -47,4 +47,4 @@ Then go into the source package directory for your running distribution and buil
Built packages are placed in the dist/ directory. Built packages are placed in the dist/ directory.
$ cd .. $ cd ..
$ dpkg-deb -c geth-unstable_1.9.6+bionic_amd64.deb $ dpkg-deb -c aiigo-unstable_1.9.6+bionic_amd64.deb

View file

@ -63,18 +63,18 @@ import (
) )
var ( var (
// Files that end up in the geth*.zip archive. // Files that end up in the aiigo*.zip archive.
gethArchiveFiles = []string{ aiigoArchiveFiles = []string{
"COPYING", "COPYING",
executablePath("geth"), executablePath("aiigo"),
} }
// Files that end up in the geth-alltools*.zip archive. // Files that end up in the aiigo-alltools*.zip archive.
allToolsArchiveFiles = []string{ allToolsArchiveFiles = []string{
"COPYING", "COPYING",
executablePath("abigen"), executablePath("abigen"),
executablePath("evm"), executablePath("evm"),
executablePath("geth"), executablePath("aiigo"),
executablePath("rlpdump"), executablePath("rlpdump"),
executablePath("clef"), executablePath("clef"),
} }
@ -90,7 +90,7 @@ var (
Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.", Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.",
}, },
{ {
BinaryName: "geth", BinaryName: "aiigo",
Description: "Ethereum CLI client.", Description: "Ethereum CLI client.",
}, },
{ {
@ -567,7 +567,7 @@ func doArchive(cmdline []string) {
atype = flag.String("type", "zip", "Type of archive to write (zip|tar)") atype = flag.String("type", "zip", "Type of archive to write (zip|tar)")
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. LINUX_SIGNING_KEY)`) signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. LINUX_SIGNING_KEY)`)
signify = flag.String("signify", "", `Environment variable holding the signify key (e.g. LINUX_SIGNIFY_KEY)`) signify = flag.String("signify", "", `Environment variable holding the signify key (e.g. LINUX_SIGNIFY_KEY)`)
upload = flag.String("upload", "", `Destination to upload the archives (usually "gethstore/builds")`) upload = flag.String("upload", "", `Destination to upload the archives (usually "aiigostore/builds")`)
ext string ext string
) )
flag.CommandLine.Parse(cmdline) flag.CommandLine.Parse(cmdline)
@ -582,18 +582,18 @@ func doArchive(cmdline []string) {
var ( var (
env = build.Env() env = build.Env()
basegeth = archiveBasename(*arch, version.Archive(env.Commit)) baseaiigo = archiveBasename(*arch, version.Archive(env.Commit))
geth = "geth-" + basegeth + ext aiigo = "aiigo-" + baseaiigo + ext
alltools = "geth-alltools-" + basegeth + ext alltools = "aiigo-alltools-" + baseaiigo + ext
) )
maybeSkipArchive(env) maybeSkipArchive(env)
if err := build.WriteArchive(geth, gethArchiveFiles); err != nil { if err := build.WriteArchive(aiigo, aiigoArchiveFiles); err != nil {
log.Fatal(err) log.Fatal(err)
} }
if err := build.WriteArchive(alltools, allToolsArchiveFiles); err != nil { if err := build.WriteArchive(alltools, allToolsArchiveFiles); err != nil {
log.Fatal(err) log.Fatal(err)
} }
for _, archive := range []string{geth, alltools} { for _, archive := range []string{aiigo, alltools} {
if err := archiveUpload(archive, *upload, *signer, *signify); err != nil { if err := archiveUpload(archive, *upload, *signer, *signify); err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -624,7 +624,7 @@ func archiveUpload(archive string, blobstore string, signer string, signifyVar s
} }
if signifyVar != "" { if signifyVar != "" {
key := os.Getenv(signifyVar) key := os.Getenv(signifyVar)
untrustedComment := "verify with geth-release.pub" untrustedComment := "verify with aiigo-release.pub"
trustedComment := fmt.Sprintf("%s (%s)", archive, time.Now().UTC().Format(time.RFC1123)) trustedComment := fmt.Sprintf("%s (%s)", archive, time.Now().UTC().Format(time.RFC1123))
if err := signify.SignFile(archive, archive+".sig", key, untrustedComment, trustedComment); err != nil { if err := signify.SignFile(archive, archive+".sig", key, untrustedComment, trustedComment); err != nil {
return err return err
@ -689,14 +689,14 @@ func doDockerBuildx(cmdline []string) {
build.MustRun(auther) build.MustRun(auther)
} }
// Retrieve the version infos to build and push to the following paths: // Retrieve the version infos to build and push to the following paths:
// - ethereum/client-go:latest - Pushes to the master branch, Geth only // - ethereum/client-go:latest - Pushes to the master branch, Aiigo only
// - ethereum/client-go:stable - Version tag publish on GitHub, Geth only // - ethereum/client-go:stable - Version tag publish on GitHub, Aiigo only
// - ethereum/client-go:alltools-latest - Pushes to the master branch, Geth & tools // - ethereum/client-go:alltools-latest - Pushes to the master branch, Aiigo & tools
// - ethereum/client-go:alltools-stable - Version tag publish on GitHub, Geth & tools // - ethereum/client-go:alltools-stable - Version tag publish on GitHub, Aiigo & tools
// - ethereum/client-go:release-<major>.<minor> - Version tag publish on GitHub, Geth only // - ethereum/client-go:release-<major>.<minor> - Version tag publish on GitHub, Aiigo only
// - ethereum/client-go:alltools-release-<major>.<minor> - Version tag publish on GitHub, Geth & tools // - ethereum/client-go:alltools-release-<major>.<minor> - Version tag publish on GitHub, Aiigo & tools
// - ethereum/client-go:v<major>.<minor>.<patch> - Version tag publish on GitHub, Geth only // - ethereum/client-go:v<major>.<minor>.<patch> - Version tag publish on GitHub, Aiigo only
// - ethereum/client-go:alltools-v<major>.<minor>.<patch> - Version tag publish on GitHub, Geth & tools // - ethereum/client-go:alltools-v<major>.<minor>.<patch> - Version tag publish on GitHub, Aiigo & tools
var tags []string var tags []string
switch { switch {
@ -719,12 +719,12 @@ func doDockerBuildx(cmdline []string) {
{file: "Dockerfile.alltools", base: fmt.Sprintf("%s:alltools-", *hubImage)}, {file: "Dockerfile.alltools", base: fmt.Sprintf("%s:alltools-", *hubImage)},
} { } {
for _, tag := range tags { // latest, stable etc for _, tag := range tags { // latest, stable etc
gethImage := fmt.Sprintf("%s%s", spec.base, tag) aiigoImage := fmt.Sprintf("%s%s", spec.base, tag)
cmd := exec.Command("docker", "buildx", "build", cmd := exec.Command("docker", "buildx", "build",
"--build-arg", "COMMIT="+env.Commit, "--build-arg", "COMMIT="+env.Commit,
"--build-arg", "VERSION="+version.WithMeta, "--build-arg", "VERSION="+version.WithMeta,
"--build-arg", "BUILDNUM="+env.Buildnum, "--build-arg", "BUILDNUM="+env.Buildnum,
"--tag", gethImage, "--tag", aiigoImage,
"--platform", *platform, "--platform", *platform,
"--file", spec.file, "--file", spec.file,
) )
@ -743,7 +743,7 @@ func doDebianSource(cmdline []string) {
cachedir = flag.String("cachedir", "./build/cache", `Filesystem path to cache the downloaded Go bundles at`) cachedir = flag.String("cachedir", "./build/cache", `Filesystem path to cache the downloaded Go bundles at`)
signer = flag.String("signer", "", `Signing key name, also used as package author`) signer = flag.String("signer", "", `Signing key name, also used as package author`)
upload = flag.String("upload", "", `Where to upload the source package (usually "ethereum/ethereum")`) upload = flag.String("upload", "", `Where to upload the source package (usually "ethereum/ethereum")`)
sshUser = flag.String("sftp-user", "", `Username for SFTP upload (usually "geth-ci")`) sshUser = flag.String("sftp-user", "", `Username for SFTP upload (usually "aiigo-ci")`)
workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`) workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`)
now = time.Now() now = time.Now()
) )
@ -904,7 +904,7 @@ func makeWorkdir(wdflag string) string {
if wdflag != "" { if wdflag != "" {
err = os.MkdirAll(wdflag, 0744) err = os.MkdirAll(wdflag, 0744)
} else { } else {
wdflag, err = os.MkdirTemp("", "geth-build-") wdflag, err = os.MkdirTemp("", "aiigo-build-")
} }
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -1058,7 +1058,7 @@ func doWindowsInstaller(cmdline []string) {
arch = flag.String("arch", runtime.GOARCH, "Architecture for cross build packaging") arch = flag.String("arch", runtime.GOARCH, "Architecture for cross build packaging")
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. WINDOWS_SIGNING_KEY)`) signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. WINDOWS_SIGNING_KEY)`)
signify = flag.String("signify key", "", `Environment variable holding the signify signing key (e.g. WINDOWS_SIGNIFY_KEY)`) signify = flag.String("signify key", "", `Environment variable holding the signify signing key (e.g. WINDOWS_SIGNIFY_KEY)`)
upload = flag.String("upload", "", `Destination to upload the archives (usually "gethstore/builds")`) upload = flag.String("upload", "", `Destination to upload the archives (usually "aiigostore/builds")`)
workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`) workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`)
) )
flag.CommandLine.Parse(cmdline) flag.CommandLine.Parse(cmdline)
@ -1070,28 +1070,28 @@ func doWindowsInstaller(cmdline []string) {
var ( var (
devTools []string devTools []string
allTools []string allTools []string
gethTool string aiigoTool string
) )
for _, file := range allToolsArchiveFiles { for _, file := range allToolsArchiveFiles {
if file == "COPYING" { // license, copied later if file == "COPYING" { // license, copied later
continue continue
} }
allTools = append(allTools, filepath.Base(file)) allTools = append(allTools, filepath.Base(file))
if filepath.Base(file) == "geth.exe" { if filepath.Base(file) == "aiigo.exe" {
gethTool = file aiigoTool = file
} else { } else {
devTools = append(devTools, file) devTools = append(devTools, file)
} }
} }
// Render NSIS scripts: Installer NSIS contains two installer sections, // Render NSIS scripts: Installer NSIS contains two installer sections,
// first section contains the geth binary, second section holds the dev tools. // first section contains the aiigo binary, second section holds the dev tools.
templateData := map[string]interface{}{ templateData := map[string]interface{}{
"License": "COPYING", "License": "COPYING",
"Geth": gethTool, "Aiigo": aiigoTool,
"DevTools": devTools, "DevTools": devTools,
} }
build.Render("build/nsis.geth.nsi", filepath.Join(*workdir, "geth.nsi"), 0644, nil) build.Render("build/nsis.aiigo.nsi", filepath.Join(*workdir, "aiigo.nsi"), 0644, nil)
build.Render("build/nsis.install.nsh", filepath.Join(*workdir, "install.nsh"), 0644, templateData) build.Render("build/nsis.install.nsh", filepath.Join(*workdir, "install.nsh"), 0644, templateData)
build.Render("build/nsis.uninstall.nsh", filepath.Join(*workdir, "uninstall.nsh"), 0644, allTools) build.Render("build/nsis.uninstall.nsh", filepath.Join(*workdir, "uninstall.nsh"), 0644, allTools)
build.Render("build/nsis.pathupdate.nsh", filepath.Join(*workdir, "PathUpdate.nsh"), 0644, nil) build.Render("build/nsis.pathupdate.nsh", filepath.Join(*workdir, "PathUpdate.nsh"), 0644, nil)
@ -1109,7 +1109,7 @@ func doWindowsInstaller(cmdline []string) {
if env.Commit != "" { if env.Commit != "" {
ver[2] += "-" + env.Commit[:8] ver[2] += "-" + env.Commit[:8]
} }
installer, err := filepath.Abs("geth-" + archiveBasename(*arch, version.Archive(env.Commit)) + ".exe") installer, err := filepath.Abs("aiigo-" + archiveBasename(*arch, version.Archive(env.Commit)) + ".exe")
if err != nil { if err != nil {
log.Fatalf("Failed to convert installer file path: %v", err) log.Fatalf("Failed to convert installer file path: %v", err)
} }
@ -1119,7 +1119,7 @@ func doWindowsInstaller(cmdline []string) {
"/DMINORVERSION="+ver[1], "/DMINORVERSION="+ver[1],
"/DBUILDVERSION="+ver[2], "/DBUILDVERSION="+ver[2],
"/DARCH="+*arch, "/DARCH="+*arch,
filepath.Join(*workdir, "geth.nsi"), filepath.Join(*workdir, "aiigo.nsi"),
) )
// Sign and publish installer. // Sign and publish installer.
if err := archiveUpload(installer, *upload, *signer, *signify); err != nil { if err := archiveUpload(installer, *upload, *signer, *signify); err != nil {
@ -1131,7 +1131,7 @@ func doWindowsInstaller(cmdline []string) {
func doPurge(cmdline []string) { func doPurge(cmdline []string) {
var ( var (
store = flag.String("store", "", `Destination from where to purge archives (usually "gethstore/builds")`) store = flag.String("store", "", `Destination from where to purge archives (usually "aiigostore/builds")`)
limit = flag.Int("days", 30, `Age threshold above which to delete unstable archives`) limit = flag.Int("days", 30, `Age threshold above which to delete unstable archives`)
) )
flag.CommandLine.Parse(cmdline) flag.CommandLine.Parse(cmdline)

View file

@ -1,4 +1,4 @@
_geth_bash_autocomplete() { _aiigo_bash_autocomplete() {
if [[ "${COMP_WORDS[0]}" != "source" ]]; then if [[ "${COMP_WORDS[0]}" != "source" ]]; then
local cur opts base local cur opts base
COMPREPLY=() COMPREPLY=()
@ -13,4 +13,4 @@ _geth_bash_autocomplete() {
fi fi
} }
complete -o bashdefault -o default -o nospace -F _geth_bash_autocomplete geth complete -o bashdefault -o default -o nospace -F _aiigo_bash_autocomplete aiigo

View file

@ -1,4 +1,4 @@
_geth_zsh_autocomplete() { _aiigo_zsh_autocomplete() {
local -a opts local -a opts
local cur local cur
cur=${words[-1]} cur=${words[-1]}
@ -15,4 +15,4 @@ _geth_zsh_autocomplete() {
fi fi
} }
compdef _geth_zsh_autocomplete geth compdef _aiigo_zsh_autocomplete aiigo

View file

@ -11,8 +11,8 @@ Vcs-Browser: https://github.com/ethereum/go-ethereum
Package: {{.Name}} Package: {{.Name}}
Architecture: any Architecture: any
Depends: ${misc:Depends}, {{.ExeList}} Depends: ${misc:Depends}, {{.ExeList}}
Description: Meta-package to install geth and other tools Description: Meta-package to install aiigo and other tools
Meta-package to install geth and other tools Meta-package to install aiigo and other tools
{{range .Executables}} {{range .Executables}}
Package: {{$.ExeName .}} Package: {{$.ExeName .}}

View file

@ -1,5 +1,5 @@
build/bin/{{.BinaryName}} usr/bin build/bin/{{.BinaryName}} usr/bin
{{- if eq .BinaryName "geth" }} {{- if eq .BinaryName "aiigo" }}
build/deb/ethereum/completions/bash/geth etc/bash_completion.d build/deb/ethereum/completions/bash/aiigo etc/bash_completion.d
build/deb/ethereum/completions/zsh/_geth usr/share/zsh/vendor-completions build/deb/ethereum/completions/zsh/_aiigo usr/share/zsh/vendor-completions
{{end -}} {{end -}}

View file

@ -6,11 +6,11 @@
# - BUILDVERSION, build id version # - BUILDVERSION, build id version
# #
# The created installer executes the following steps: # The created installer executes the following steps:
# 1. install geth for all users # 1. install aiigo for all users
# 2. install optional development tools such as abigen # 2. install optional development tools such as abigen
# 3. create an uninstaller # 3. create an uninstaller
# 4. configures the Windows firewall for geth # 4. configures the Windows firewall for aiigo
# 5. create geth, attach and uninstall start menu entries # 5. create aiigo, attach and uninstall start menu entries
# 6. configures the registry that allows Windows to manage the package through its platform tools # 6. configures the registry that allows Windows to manage the package through its platform tools
# 7. adds the environment system wide variable ETHEREUM_SOCKET # 7. adds the environment system wide variable ETHEREUM_SOCKET
# 8. adds the install directory to %PATH% # 8. adds the install directory to %PATH%
@ -30,7 +30,7 @@
CRCCheck on CRCCheck on
!define GROUPNAME "Ethereum" !define GROUPNAME "Ethereum"
!define APPNAME "Geth" !define APPNAME "Aiigo"
!define DESCRIPTION "Official Go implementation of the Ethereum protocol" !define DESCRIPTION "Official Go implementation of the Ethereum protocol"
!addplugindir .\ !addplugindir .\
@ -55,7 +55,7 @@ ${EndIf}
!macroend !macroend
function .onInit function .onInit
# make vars are global for all users since geth is installed global # make vars are global for all users since aiigo is installed global
setShellVarContext all setShellVarContext all
!insertmacro VerifyUserIsAdmin !insertmacro VerifyUserIsAdmin

View file

@ -1,4 +1,4 @@
Name "geth ${MAJORVERSION}.${MINORVERSION}.${BUILDVERSION}" # VERSION variables set through command line arguments Name "aiigo ${MAJORVERSION}.${MINORVERSION}.${BUILDVERSION}" # VERSION variables set through command line arguments
InstallDir "$InstDir" InstallDir "$InstDir"
OutFile "${OUTPUTFILE}" # set through command line arguments OutFile "${OUTPUTFILE}" # set through command line arguments
@ -12,30 +12,30 @@ PageEx license
LicenseData {{.License}} LicenseData {{.License}}
PageExEnd PageExEnd
# Install geth binary # Install aiigo binary
Section "Geth" GETH_IDX Section "Aiigo" GETH_IDX
SetOutPath $INSTDIR SetOutPath $INSTDIR
file {{.Geth}} file {{.Aiigo}}
# Create start menu launcher # Create start menu launcher
createDirectory "$SMPROGRAMS\${APPNAME}" createDirectory "$SMPROGRAMS\${APPNAME}"
createShortCut "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" "$INSTDIR\geth.exe" createShortCut "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" "$INSTDIR\aiigo.exe"
createShortCut "$SMPROGRAMS\${APPNAME}\Attach.lnk" "$INSTDIR\geth.exe" "attach" createShortCut "$SMPROGRAMS\${APPNAME}\Attach.lnk" "$INSTDIR\aiigo.exe" "attach"
createShortCut "$SMPROGRAMS\${APPNAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe" createShortCut "$SMPROGRAMS\${APPNAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe"
# Firewall - remove rules (if exists) # Firewall - remove rules (if exists)
SimpleFC::AdvRemoveRule "Geth incoming peers (TCP:30303)" SimpleFC::AdvRemoveRule "Aiigo incoming peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth outgoing peers (TCP:30303)" SimpleFC::AdvRemoveRule "Aiigo outgoing peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)" SimpleFC::AdvRemoveRule "Aiigo UDP discovery (UDP:30303)"
# Firewall - add rules # Firewall - add rules
SimpleFC::AdvAddRule "Geth incoming peers (TCP:30303)" "" 6 1 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" 30303 "" "" "" SimpleFC::AdvAddRule "Aiigo incoming peers (TCP:30303)" "" 6 1 1 2147483647 1 "$INSTDIR\aiigo.exe" "" "" "Ethereum" 30303 "" "" ""
SimpleFC::AdvAddRule "Geth outgoing peers (TCP:30303)" "" 6 2 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" "" 30303 "" "" SimpleFC::AdvAddRule "Aiigo outgoing peers (TCP:30303)" "" 6 2 1 2147483647 1 "$INSTDIR\aiigo.exe" "" "" "Ethereum" "" 30303 "" ""
SimpleFC::AdvAddRule "Geth UDP discovery (UDP:30303)" "" 17 2 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" "" 30303 "" "" SimpleFC::AdvAddRule "Aiigo UDP discovery (UDP:30303)" "" 17 2 1 2147483647 1 "$INSTDIR\aiigo.exe" "" "" "Ethereum" "" 30303 "" ""
# Set default IPC endpoint (https://github.com/ethereum/EIPs/issues/147) # Set default IPC endpoint (https://github.com/ethereum/EIPs/issues/147)
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc" ${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\aiigo.ipc"
${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\geth.ipc" ${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\aiigo.ipc"
# Add instdir to PATH # Add instdir to PATH
Push "$INSTDIR" Push "$INSTDIR"

View file

@ -17,12 +17,12 @@ Section "Uninstall"
rmDir "$SMPROGRAMS\${APPNAME}" rmDir "$SMPROGRAMS\${APPNAME}"
# Firewall - remove rules if exists # Firewall - remove rules if exists
SimpleFC::AdvRemoveRule "Geth incoming peers (TCP:30303)" SimpleFC::AdvRemoveRule "Aiigo incoming peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth outgoing peers (TCP:30303)" SimpleFC::AdvRemoveRule "Aiigo outgoing peers (TCP:30303)"
SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)" SimpleFC::AdvRemoveRule "Aiigo UDP discovery (UDP:30303)"
# Remove IPC endpoint (https://github.com/ethereum/EIPs/issues/147) # Remove IPC endpoint (https://github.com/ethereum/EIPs/issues/147)
${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc" ${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\aiigo.ipc"
# Remove install directory from PATH # Remove install directory from PATH
Push "$INSTDIR" Push "$INSTDIR"

View file

@ -23,10 +23,10 @@ dependencies:
test: test:
override: override:
# Build Geth and move into a known folder # Build Aiigo and move into a known folder
- make geth - make aiigo
- cp ./build/bin/geth $HOME/geth - cp ./build/bin/aiigo $HOME/aiigo
# Run hive and move all generated logs into the public artifacts folder # Run hive and move all generated logs into the public artifacts folder
- (cd ~/.go_workspace/src/github.com/karalabe/hive && hive --docker-noshell --client=go-ethereum:local --override=$HOME/geth --test=. --sim=.) - (cd ~/.go_workspace/src/github.com/karalabe/hive && hive --docker-noshell --client=go-ethereum:local --override=$HOME/aiigo --test=. --sim=.)
- cp -r ~/.go_workspace/src/github.com/karalabe/hive/workspace/logs/* $CIRCLE_ARTIFACTS - cp -r ~/.go_workspace/src/github.com/karalabe/hive/workspace/logs/* $CIRCLE_ARTIFACTS

367
cmd/aiigo/accountcmd.go Normal file
View file

@ -0,0 +1,367 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"errors"
"fmt"
"os"
"strings"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/urfave/cli/v2"
)
var (
walletCommand = &cli.Command{
Name: "wallet",
Usage: "Manage Ethereum presale wallets",
ArgsUsage: "",
Description: `
aiigo wallet import /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a
passwordfile as argument containing the wallet password in plaintext.`,
Subcommands: []*cli.Command{
{
Name: "import",
Usage: "Import Ethereum presale wallet",
ArgsUsage: "<keyFile>",
Action: importWallet,
Flags: []cli.Flag{
utils.DataDirFlag,
utils.KeyStoreDirFlag,
utils.PasswordFileFlag,
utils.LightKDFFlag,
},
Description: `
aiigo wallet [options] /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a
passwordfile as argument containing the wallet password in plaintext.`,
},
},
}
accountCommand = &cli.Command{
Name: "account",
Usage: "Manage accounts",
Description: `
Manage accounts, list all existing accounts, import a private key into a new
account, create a new account or update an existing account.
It supports interactive mode, when you are prompted for password as well as
non-interactive mode where passwords are supplied via a given password file.
Non-interactive mode is only meant for scripted use on test networks or known
safe environments.
Make sure you remember the password you gave when creating a new account (with
either new or import). Without it you are not able to unlock your account.
Note that exporting your key in unencrypted format is NOT supported.
Keys are stored under <DATADIR>/keystore.
It is safe to transfer the entire directory or the individual keys therein
between ethereum nodes by simply copying.
Make sure you backup your keys regularly.`,
Subcommands: []*cli.Command{
{
Name: "list",
Usage: "Print summary of existing accounts",
Action: accountList,
Flags: []cli.Flag{
utils.DataDirFlag,
utils.KeyStoreDirFlag,
},
Description: `
Print a short summary of all accounts`,
},
{
Name: "new",
Usage: "Create a new account",
Action: accountCreate,
Flags: []cli.Flag{
utils.DataDirFlag,
utils.KeyStoreDirFlag,
utils.PasswordFileFlag,
utils.LightKDFFlag,
},
Description: `
aiigo account new
Creates a new account and prints the address.
The account is saved in encrypted format, you are prompted for a password.
You must remember this password to unlock your account in the future.
For non-interactive use the password can be specified with the --password flag:
Note, this is meant to be used for testing only, it is a bad idea to save your
password to file or expose in any other way.
`,
},
{
Name: "update",
Usage: "Update an existing account",
Action: accountUpdate,
ArgsUsage: "<address>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.KeyStoreDirFlag,
utils.LightKDFFlag,
},
Description: `
aiigo account update <address>
Update an existing account.
The account is saved in the newest version in encrypted format, you are prompted
for a password to unlock the account and another to save the updated file.
This same command can therefore be used to migrate an account of a deprecated
format to the newest format or change the password for an account.
For non-interactive use the password can be specified with the --password flag:
aiigo account update [options] <address>
Since only one password can be given, only format update can be performed,
changing your password is only possible interactively.
`,
},
{
Name: "import",
Usage: "Import a private key into a new account",
Action: accountImport,
Flags: []cli.Flag{
utils.DataDirFlag,
utils.KeyStoreDirFlag,
utils.PasswordFileFlag,
utils.LightKDFFlag,
},
ArgsUsage: "<keyFile>",
Description: `
aiigo account import <keyfile>
Imports an unencrypted private key from <keyfile> and creates a new account.
Prints the address.
The keyfile is assumed to contain an unencrypted private key in hexadecimal format.
The account is saved in encrypted format, you are prompted for a password.
You must remember this password to unlock your account in the future.
For non-interactive use the password can be specified with the -password flag:
aiigo account import [options] <keyfile>
Note:
As you can directly copy your encrypted accounts to another ethereum instance,
this import mechanism is not needed when you transfer an account between
nodes.
`,
},
},
}
)
// makeAccountManager creates an account manager with backends
func makeAccountManager(ctx *cli.Context) *accounts.Manager {
cfg := loadBaseConfig(ctx)
am := accounts.NewManager(nil)
keydir, isEphemeral, err := cfg.Node.GetKeyStoreDir()
if err != nil {
utils.Fatalf("Failed to get the keystore directory: %v", err)
}
if isEphemeral {
utils.Fatalf("Can't use ephemeral directory as keystore path")
}
if err := setAccountManagerBackends(&cfg.Node, am, keydir); err != nil {
utils.Fatalf("Failed to set account manager backends: %v", err)
}
return am
}
func accountList(ctx *cli.Context) error {
am := makeAccountManager(ctx)
var index int
for _, wallet := range am.Wallets() {
for _, account := range wallet.Accounts() {
fmt.Printf("Account #%d: {%x} %s\n", index, account.Address, &account.URL)
index++
}
}
return nil
}
// readPasswordFromFile reads the first line of the given file, trims line endings,
// and returns the password and whether the reading was successful.
func readPasswordFromFile(path string) (string, bool) {
if path == "" {
return "", false
}
text, err := os.ReadFile(path)
if err != nil {
utils.Fatalf("Failed to read password file: %v", err)
}
lines := strings.Split(string(text), "\n")
if len(lines) == 0 {
return "", false
}
// Sanitise DOS line endings.
return strings.TrimRight(lines[0], "\r"), true
}
// accountCreate creates a new account into the keystore defined by the CLI flags.
func accountCreate(ctx *cli.Context) error {
cfg := loadBaseConfig(ctx)
keydir, isEphemeral, err := cfg.Node.GetKeyStoreDir()
if err != nil {
utils.Fatalf("Failed to get the keystore directory: %v", err)
}
if isEphemeral {
utils.Fatalf("Can't use ephemeral directory as keystore path")
}
scryptN := keystore.StandardScryptN
scryptP := keystore.StandardScryptP
if cfg.Node.UseLightweightKDF {
scryptN = keystore.LightScryptN
scryptP = keystore.LightScryptP
}
password, ok := readPasswordFromFile(ctx.Path(utils.PasswordFileFlag.Name))
if !ok {
password = utils.GetPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true)
}
account, err := keystore.StoreKey(keydir, password, scryptN, scryptP)
if err != nil {
utils.Fatalf("Failed to create account: %v", err)
}
fmt.Printf("\nYour new key was generated\n\n")
fmt.Printf("Public address of the key: %s\n", account.Address.Hex())
fmt.Printf("Path of the secret key file: %s\n\n", account.URL.Path)
fmt.Printf("- You can share your public address with anyone. Others need it to interact with you.\n")
fmt.Printf("- You must NEVER share the secret key with anyone! The key controls access to your funds!\n")
fmt.Printf("- You must BACKUP your key file! Without the key, it's impossible to access account funds!\n")
fmt.Printf("- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!\n\n")
return nil
}
// accountUpdate transitions an account from a previous format to the current
// one, also providing the possibility to change the pass-phrase.
func accountUpdate(ctx *cli.Context) error {
if ctx.Args().Len() == 0 {
utils.Fatalf("No accounts specified to update")
}
am := makeAccountManager(ctx)
backends := am.Backends(keystore.KeyStoreType)
if len(backends) == 0 {
utils.Fatalf("Keystore is not available")
}
ks := backends[0].(*keystore.KeyStore)
for _, addr := range ctx.Args().Slice() {
if !common.IsHexAddress(addr) {
return errors.New("address must be specified in hexadecimal form")
}
account := accounts.Account{Address: common.HexToAddress(addr)}
newPassword := utils.GetPassPhrase("Please give a NEW password. Do not forget this password.", true)
updateFn := func(attempt int) error {
prompt := fmt.Sprintf("Please provide the OLD password for account %s | Attempt %d/%d", addr, attempt+1, 3)
password := utils.GetPassPhrase(prompt, false)
return ks.Update(account, password, newPassword)
}
// let user attempt unlock thrice.
err := updateFn(0)
for attempts := 1; attempts < 3 && errors.Is(err, keystore.ErrDecrypt); attempts++ {
err = updateFn(attempts)
}
if err != nil {
return fmt.Errorf("could not update account: %w", err)
}
}
return nil
}
func importWallet(ctx *cli.Context) error {
if ctx.Args().Len() != 1 {
utils.Fatalf("keyfile must be given as the only argument")
}
keyfile := ctx.Args().First()
keyJSON, err := os.ReadFile(keyfile)
if err != nil {
utils.Fatalf("Could not read wallet file: %v", err)
}
am := makeAccountManager(ctx)
backends := am.Backends(keystore.KeyStoreType)
if len(backends) == 0 {
utils.Fatalf("Keystore is not available")
}
password, ok := readPasswordFromFile(ctx.Path(utils.PasswordFileFlag.Name))
if !ok {
password = utils.GetPassPhrase("", false)
}
ks := backends[0].(*keystore.KeyStore)
acct, err := ks.ImportPreSaleKey(keyJSON, password)
if err != nil {
utils.Fatalf("%v", err)
}
fmt.Printf("Address: {%x}\n", acct.Address)
return nil
}
func accountImport(ctx *cli.Context) error {
if ctx.Args().Len() != 1 {
utils.Fatalf("keyfile must be given as the only argument")
}
keyfile := ctx.Args().First()
key, err := crypto.LoadECDSA(keyfile)
if err != nil {
utils.Fatalf("Failed to load the private key: %v", err)
}
am := makeAccountManager(ctx)
backends := am.Backends(keystore.KeyStoreType)
if len(backends) == 0 {
utils.Fatalf("Keystore is not available")
}
ks := backends[0].(*keystore.KeyStore)
password, ok := readPasswordFromFile(ctx.Path(utils.PasswordFileFlag.Name))
if !ok {
password = utils.GetPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true)
}
acct, err := ks.ImportECDSA(key, password)
if err != nil {
utils.Fatalf("Could not create the account: %v", err)
}
fmt.Printf("Address: {%x}\n", acct.Address)
return nil
}

View file

@ -0,0 +1,207 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"os"
"path/filepath"
"runtime"
"testing"
"github.com/cespare/cp"
)
// These tests are 'smoke tests' for the account related
// subcommands and flags.
//
// For most tests, the test files from package accounts
// are copied into a temporary keystore directory.
func tmpDatadirWithKeystore(t *testing.T) string {
datadir := t.TempDir()
keystore := filepath.Join(datadir, "keystore")
source := filepath.Join("..", "..", "accounts", "keystore", "testdata", "keystore")
if err := cp.CopyAll(keystore, source); err != nil {
t.Fatal(err)
}
return datadir
}
func TestAccountListEmpty(t *testing.T) {
t.Parallel()
aiigo := runaiigo(t, "account", "list")
aiigo.ExpectExit()
}
func TestAccountList(t *testing.T) {
t.Parallel()
datadir := tmpDatadirWithKeystore(t)
var want = `
Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa
Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz
`
if runtime.GOOS == "windows" {
want = `
Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}\keystore\UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}\keystore\aaa
Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\keystore\zzz
`
}
{
aiigo := runaiigo(t, "account", "list", "--datadir", datadir)
aiigo.Expect(want)
aiigo.ExpectExit()
}
{
aiigo := runaiigo(t, "--datadir", datadir, "account", "list")
aiigo.Expect(want)
aiigo.ExpectExit()
}
}
func TestAccountNew(t *testing.T) {
t.Parallel()
aiigo := runaiigo(t, "account", "new", "--lightkdf")
defer aiigo.ExpectExit()
aiigo.Expect(`
Your new account is locked with a password. Please give a password. Do not forget this password.
!! Unsupported terminal, password will be echoed.
Password: {{.InputLine "foobar"}}
Repeat password: {{.InputLine "foobar"}}
Your new key was generated
`)
aiigo.ExpectRegexp(`
Public address of the key: 0x[0-9a-fA-F]{40}
Path of the secret key file: .*UTC--.+--[0-9a-f]{40}
- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!
`)
}
func TestAccountImport(t *testing.T) {
t.Parallel()
tests := []struct{ name, key, output string }{
{
name: "correct account",
key: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
output: "Address: {fcad0b19bb29d4674531d6f115237e16afce377c}\n",
},
{
name: "invalid character",
key: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef1",
output: "Fatal: Failed to load the private key: invalid character '1' at end of key file\n",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
importAccountWithExpect(t, test.key, test.output)
})
}
}
func TestAccountHelp(t *testing.T) {
t.Parallel()
aiigo := runaiigo(t, "account", "-h")
aiigo.WaitExit()
if have, want := aiigo.ExitStatus(), 0; have != want {
t.Errorf("exit error, have %d want %d", have, want)
}
aiigo = runaiigo(t, "account", "import", "-h")
aiigo.WaitExit()
if have, want := aiigo.ExitStatus(), 0; have != want {
t.Errorf("exit error, have %d want %d", have, want)
}
}
func importAccountWithExpect(t *testing.T, key string, expected string) {
dir := t.TempDir()
keyfile := filepath.Join(dir, "key.prv")
if err := os.WriteFile(keyfile, []byte(key), 0600); err != nil {
t.Error(err)
}
passwordFile := filepath.Join(dir, "password.txt")
if err := os.WriteFile(passwordFile, []byte("foobar"), 0600); err != nil {
t.Error(err)
}
aiigo := runaiigo(t, "--lightkdf", "account", "import", "-password", passwordFile, keyfile)
defer aiigo.ExpectExit()
aiigo.Expect(expected)
}
func TestAccountNewBadRepeat(t *testing.T) {
t.Parallel()
aiigo := runaiigo(t, "account", "new", "--lightkdf")
defer aiigo.ExpectExit()
aiigo.Expect(`
Your new account is locked with a password. Please give a password. Do not forget this password.
!! Unsupported terminal, password will be echoed.
Password: {{.InputLine "something"}}
Repeat password: {{.InputLine "something else"}}
Fatal: Passwords do not match
`)
}
func TestAccountUpdate(t *testing.T) {
t.Parallel()
datadir := tmpDatadirWithKeystore(t)
aiigo := runaiigo(t, "account", "update",
"--datadir", datadir, "--lightkdf",
"f466859ead1932d743d622cb74fc058882e8648a")
defer aiigo.ExpectExit()
aiigo.Expect(`
Please give a NEW password. Do not forget this password.
!! Unsupported terminal, password will be echoed.
Password: {{.InputLine "foobar2"}}
Repeat password: {{.InputLine "foobar2"}}
Please provide the OLD password for account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
Password: {{.InputLine "foobar"}}
`)
}
func TestWalletImport(t *testing.T) {
t.Parallel()
aiigo := runaiigo(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer aiigo.ExpectExit()
aiigo.Expect(`
!! Unsupported terminal, password will be echoed.
Password: {{.InputLine "foo"}}
Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f}
`)
files, err := os.ReadDir(filepath.Join(aiigo.Datadir, "keystore"))
if len(files) != 1 {
t.Errorf("expected one key file in keystore directory, found %d files (error: %v)", len(files), err)
}
}
func TestWalletImportBadPassword(t *testing.T) {
t.Parallel()
aiigo := runaiigo(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer aiigo.ExpectExit()
aiigo.Expect(`
!! Unsupported terminal, password will be echoed.
Password: {{.InputLine "wrong"}}
Fatal: could not decrypt key with given password
`)
}

83
cmd/aiigo/attach_test.go Normal file
View file

@ -0,0 +1,83 @@
// Copyright 2022 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"fmt"
"net"
"net/http"
"sync/atomic"
"testing"
)
type testHandler struct {
body func(http.ResponseWriter, *http.Request)
}
func (t *testHandler) ServeHTTP(out http.ResponseWriter, in *http.Request) {
t.body(out, in)
}
// TestAttachWithHeaders tests that 'aiigo attach' with custom headers works, i.e
// that custom headers are forwarded to the target.
func TestAttachWithHeaders(t *testing.T) {
t.Parallel()
ln, err := net.Listen("tcp", "localhost:0")
if err != nil {
t.Fatal(err)
}
port := ln.Addr().(*net.TCPAddr).Port
testReceiveHeaders(t, ln, "attach", "-H", "first: one", "-H", "second: two", fmt.Sprintf("http://localhost:%d", port))
// This way to do it fails due to flag ordering:
//
// testReceiveHeaders(t, ln, "-H", "first: one", "-H", "second: two", "attach", fmt.Sprintf("http://localhost:%d", port))
// This is fixed in a follow-up PR.
}
// TestRemoteDbWithHeaders tests that 'aiigo db --remotedb' with custom headers works, i.e
// that custom headers are forwarded to the target.
func TestRemoteDbWithHeaders(t *testing.T) {
t.Parallel()
ln, err := net.Listen("tcp", "localhost:0")
if err != nil {
t.Fatal(err)
}
port := ln.Addr().(*net.TCPAddr).Port
testReceiveHeaders(t, ln, "db", "metadata", "--remotedb", fmt.Sprintf("http://localhost:%d", port), "-H", "first: one", "-H", "second: two")
}
func testReceiveHeaders(t *testing.T, ln net.Listener, aiigoArgs ...string) {
var ok atomic.Uint32
server := &http.Server{
Addr: "localhost:0",
Handler: &testHandler{func(w http.ResponseWriter, r *http.Request) {
// We expect two headers
if have, want := r.Header.Get("first"), "one"; have != want {
t.Fatalf("missing header, have %v want %v", have, want)
}
if have, want := r.Header.Get("second"), "two"; have != want {
t.Fatalf("missing header, have %v want %v", have, want)
}
ok.Store(1)
}}}
go server.Serve(ln)
defer server.Close()
runaiigo(t, aiigoArgs...).WaitExit()
if ok.Load() != 1 {
t.Fatal("Test fail, expected invocation to succeed")
}
}

660
cmd/aiigo/chaincmd.go Normal file
View file

@ -0,0 +1,660 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"encoding/json"
"errors"
"fmt"
"os"
"runtime"
"slices"
"strconv"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/internal/era"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/urfave/cli/v2"
)
var (
initCommand = &cli.Command{
Action: initGenesis,
Name: "init",
Usage: "Bootstrap and initialize a new genesis block",
ArgsUsage: "<genesisPath>",
Flags: slices.Concat([]cli.Flag{
utils.CachePreimagesFlag,
utils.OverridePrague,
utils.OverrideVerkle,
}, utils.DatabaseFlags),
Description: `
The init command initializes a new genesis block and definition for the network.
This is a destructive action and changes the network in which you will be
participating.
It expects the genesis file as argument.`,
}
dumpGenesisCommand = &cli.Command{
Action: dumpGenesis,
Name: "dumpgenesis",
Usage: "Dumps genesis block JSON configuration to stdout",
ArgsUsage: "",
Flags: slices.Concat([]cli.Flag{utils.DataDirFlag}, utils.NetworkFlags),
Description: `
The dumpgenesis command prints the genesis configuration of the network preset
if one is set. Otherwise it prints the genesis from the datadir.`,
}
importCommand = &cli.Command{
Action: importChain,
Name: "import",
Usage: "Import a blockchain file",
ArgsUsage: "<filename> (<filename 2> ... <filename N>) ",
Flags: slices.Concat([]cli.Flag{
utils.CacheFlag,
utils.GCModeFlag,
utils.SnapshotFlag,
utils.CacheDatabaseFlag,
utils.CacheGCFlag,
utils.NoCompactionFlag,
utils.MetricsEnabledFlag,
utils.MetricsEnabledExpensiveFlag,
utils.MetricsHTTPFlag,
utils.MetricsPortFlag,
utils.MetricsEnableInfluxDBFlag,
utils.MetricsEnableInfluxDBV2Flag,
utils.MetricsInfluxDBEndpointFlag,
utils.MetricsInfluxDBDatabaseFlag,
utils.MetricsInfluxDBUsernameFlag,
utils.MetricsInfluxDBPasswordFlag,
utils.MetricsInfluxDBTagsFlag,
utils.MetricsInfluxDBTokenFlag,
utils.MetricsInfluxDBBucketFlag,
utils.MetricsInfluxDBOrganizationFlag,
utils.TxLookupLimitFlag,
utils.VMTraceFlag,
utils.VMTraceJsonConfigFlag,
utils.TransactionHistoryFlag,
utils.LogHistoryFlag,
utils.LogNoHistoryFlag,
utils.LogExportCheckpointsFlag,
utils.StateHistoryFlag,
}, utils.DatabaseFlags, debug.Flags),
Before: func(ctx *cli.Context) error {
flags.MigrateGlobalFlags(ctx)
return debug.Setup(ctx)
},
Description: `
The import command allows the import of blocks from an RLP-encoded format. This format can be a single file
containing multiple RLP-encoded blocks, or multiple files can be given.
If only one file is used, an import error will result in the entire import process failing. If
multiple files are processed, the import process will continue even if an individual RLP file fails
to import successfully.`,
}
exportCommand = &cli.Command{
Action: exportChain,
Name: "export",
Usage: "Export blockchain into file",
ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]",
Flags: slices.Concat([]cli.Flag{utils.CacheFlag}, utils.DatabaseFlags),
Description: `
Requires a first argument of the file to write to.
Optional second and third arguments control the first and
last block to write. In this mode, the file will be appended
if already existing. If the file ends with .gz, the output will
be gzipped.`,
}
importHistoryCommand = &cli.Command{
Action: importHistory,
Name: "import-history",
Usage: "Import an Era archive",
ArgsUsage: "<dir>",
Flags: slices.Concat([]cli.Flag{utils.TxLookupLimitFlag, utils.TransactionHistoryFlag}, utils.DatabaseFlags, utils.NetworkFlags),
Description: `
The import-history command will import blocks and their corresponding receipts
from Era archives.
`,
}
exportHistoryCommand = &cli.Command{
Action: exportHistory,
Name: "export-history",
Usage: "Export blockchain history to Era archives",
ArgsUsage: "<dir> <first> <last>",
Flags: utils.DatabaseFlags,
Description: `
The export-history command will export blocks and their corresponding receipts
into Era archives. Eras are typically packaged in steps of 8192 blocks.
`,
}
importPreimagesCommand = &cli.Command{
Action: importPreimages,
Name: "import-preimages",
Usage: "Import the preimage database from an RLP stream",
ArgsUsage: "<datafile>",
Flags: slices.Concat([]cli.Flag{utils.CacheFlag}, utils.DatabaseFlags),
Description: `
The import-preimages command imports hash preimages from an RLP encoded stream.
It's deprecated, please use "aiigo db import" instead.
`,
}
dumpCommand = &cli.Command{
Action: dump,
Name: "dump",
Usage: "Dump a specific block from storage",
ArgsUsage: "[? <blockHash> | <blockNum>]",
Flags: slices.Concat([]cli.Flag{
utils.CacheFlag,
utils.IterativeOutputFlag,
utils.ExcludeCodeFlag,
utils.ExcludeStorageFlag,
utils.IncludeIncompletesFlag,
utils.StartKeyFlag,
utils.DumpLimitFlag,
}, utils.DatabaseFlags),
Description: `
This command dumps out the state for a given block (or latest, if none provided).
`,
}
pruneCommand = &cli.Command{
Action: pruneHistory,
Name: "prune-history",
Usage: "Prune blockchain history (block bodies and receipts) up to the merge block",
ArgsUsage: "",
Flags: utils.DatabaseFlags,
Description: `
The prune-history command removes historical block bodies and receipts from the
blockchain database up to the merge block, while preserving block headers. This
helps reduce storage requirements for nodes that don't need full historical data.`,
}
)
// initGenesis will initialise the given JSON format genesis file and writes it as
// the zero'd block (i.e. genesis) or will fail hard if it can't succeed.
func initGenesis(ctx *cli.Context) error {
if ctx.Args().Len() != 1 {
utils.Fatalf("need genesis.json file as the only argument")
}
genesisPath := ctx.Args().First()
if len(genesisPath) == 0 {
utils.Fatalf("invalid path to genesis file")
}
file, err := os.Open(genesisPath)
if err != nil {
utils.Fatalf("Failed to read genesis file: %v", err)
}
defer file.Close()
genesis := new(core.Genesis)
if err := json.NewDecoder(file).Decode(genesis); err != nil {
utils.Fatalf("invalid genesis file: %v", err)
}
// Open and initialise both full and light databases
stack, _ := makeConfigNode(ctx)
defer stack.Close()
var overrides core.ChainOverrides
if ctx.IsSet(utils.OverridePrague.Name) {
v := ctx.Uint64(utils.OverridePrague.Name)
overrides.OverridePrague = &v
}
if ctx.IsSet(utils.OverrideVerkle.Name) {
v := ctx.Uint64(utils.OverrideVerkle.Name)
overrides.OverrideVerkle = &v
}
chaindb, err := stack.OpenDatabaseWithFreezer("chaindata", 0, 0, ctx.String(utils.AncientFlag.Name), "", false)
if err != nil {
utils.Fatalf("Failed to open database: %v", err)
}
defer chaindb.Close()
triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle())
defer triedb.Close()
_, hash, _, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides)
if err != nil {
utils.Fatalf("Failed to write genesis block: %v", err)
}
log.Info("Successfully wrote genesis state", "database", "chaindata", "hash", hash)
return nil
}
func dumpGenesis(ctx *cli.Context) error {
// check if there is a testnet preset enabled
var genesis *core.Genesis
if utils.IsNetworkPreset(ctx) {
genesis = utils.MakeGenesis(ctx)
} else if ctx.IsSet(utils.DeveloperFlag.Name) && !ctx.IsSet(utils.DataDirFlag.Name) {
genesis = core.DeveloperGenesisBlock(11_500_000, nil)
}
if genesis != nil {
if err := json.NewEncoder(os.Stdout).Encode(genesis); err != nil {
utils.Fatalf("could not encode genesis: %s", err)
}
return nil
}
// dump whatever already exists in the datadir
stack, _ := makeConfigNode(ctx)
db, err := stack.OpenDatabase("chaindata", 0, 0, "", true)
if err != nil {
return err
}
defer db.Close()
genesis, err = core.ReadGenesis(db)
if err != nil {
utils.Fatalf("failed to read genesis: %s", err)
}
if err := json.NewEncoder(os.Stdout).Encode(*genesis); err != nil {
utils.Fatalf("could not encode stored genesis: %s", err)
}
return nil
}
func importChain(ctx *cli.Context) error {
if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.")
}
stack, cfg := makeConfigNode(ctx)
defer stack.Close()
// Start metrics export if enabled
utils.SetupMetrics(&cfg.Metrics)
chain, db := utils.MakeChain(ctx, stack, false)
defer db.Close()
// Start periodically gathering memory profiles
var peakMemAlloc, peakMemSys atomic.Uint64
go func() {
stats := new(runtime.MemStats)
for {
runtime.ReadMemStats(stats)
if peakMemAlloc.Load() < stats.Alloc {
peakMemAlloc.Store(stats.Alloc)
}
if peakMemSys.Load() < stats.Sys {
peakMemSys.Store(stats.Sys)
}
time.Sleep(5 * time.Second)
}
}()
// Import the chain
start := time.Now()
var importErr error
if ctx.Args().Len() == 1 {
if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
importErr = err
log.Error("Import error", "err", err)
}
} else {
for _, arg := range ctx.Args().Slice() {
if err := utils.ImportChain(chain, arg); err != nil {
importErr = err
log.Error("Import error", "file", arg, "err", err)
if err == utils.ErrImportInterrupted {
break
}
}
}
}
chain.Stop()
fmt.Printf("Import done in %v.\n\n", time.Since(start))
// Output pre-compaction stats mostly to see the import trashing
showDBStats(db)
// Print the memory statistics used by the importing
mem := new(runtime.MemStats)
runtime.ReadMemStats(mem)
fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(peakMemAlloc.Load())/1024/1024)
fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(peakMemSys.Load())/1024/1024)
fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000)
fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
if ctx.Bool(utils.NoCompactionFlag.Name) {
return nil
}
// Compact the entire database to more accurately measure disk io and print the stats
start = time.Now()
fmt.Println("Compacting entire database...")
if err := db.Compact(nil, nil); err != nil {
utils.Fatalf("Compaction failed: %v", err)
}
fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
showDBStats(db)
return importErr
}
func exportChain(ctx *cli.Context) error {
if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.")
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chain, db := utils.MakeChain(ctx, stack, true)
defer db.Close()
start := time.Now()
var err error
fp := ctx.Args().First()
if ctx.Args().Len() < 3 {
err = utils.ExportChain(chain, fp)
} else {
// This can be improved to allow for numbers larger than 9223372036854775807
first, ferr := strconv.ParseInt(ctx.Args().Get(1), 10, 64)
last, lerr := strconv.ParseInt(ctx.Args().Get(2), 10, 64)
if ferr != nil || lerr != nil {
utils.Fatalf("Export error in parsing parameters: block number not an integer\n")
}
if first < 0 || last < 0 {
utils.Fatalf("Export error: block number must be greater than 0\n")
}
if head := chain.CurrentSnapBlock(); uint64(last) > head.Number.Uint64() {
utils.Fatalf("Export error: block number %d larger than head block %d\n", uint64(last), head.Number.Uint64())
}
err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last))
}
if err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v\n", time.Since(start))
return nil
}
func importHistory(ctx *cli.Context) error {
if ctx.Args().Len() != 1 {
utils.Fatalf("usage: %s", ctx.Command.ArgsUsage)
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chain, db := utils.MakeChain(ctx, stack, false)
defer db.Close()
var (
start = time.Now()
dir = ctx.Args().Get(0)
network string
)
// Determine network.
if utils.IsNetworkPreset(ctx) {
switch {
case ctx.Bool(utils.MainnetFlag.Name):
network = "mainnet"
case ctx.Bool(utils.SepoliaFlag.Name):
network = "sepolia"
case ctx.Bool(utils.HoleskyFlag.Name):
network = "holesky"
case ctx.Bool(utils.HoodiFlag.Name):
network = "hoodi"
}
} else {
// No network flag set, try to determine network based on files
// present in directory.
var networks []string
for _, n := range params.NetworkNames {
entries, err := era.ReadDir(dir, n)
if err != nil {
return fmt.Errorf("error reading %s: %w", dir, err)
}
if len(entries) > 0 {
networks = append(networks, n)
}
}
if len(networks) == 0 {
return fmt.Errorf("no era1 files found in %s", dir)
}
if len(networks) > 1 {
return errors.New("multiple networks found, use a network flag to specify desired network")
}
network = networks[0]
}
if err := utils.ImportHistory(chain, db, dir, network); err != nil {
return err
}
fmt.Printf("Import done in %v\n", time.Since(start))
return nil
}
// exportHistory exports chain history in Era archives at a specified
// directory.
func exportHistory(ctx *cli.Context) error {
if ctx.Args().Len() != 3 {
utils.Fatalf("usage: %s", ctx.Command.ArgsUsage)
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chain, _ := utils.MakeChain(ctx, stack, true)
start := time.Now()
var (
dir = ctx.Args().Get(0)
first, ferr = strconv.ParseInt(ctx.Args().Get(1), 10, 64)
last, lerr = strconv.ParseInt(ctx.Args().Get(2), 10, 64)
)
if ferr != nil || lerr != nil {
utils.Fatalf("Export error in parsing parameters: block number not an integer\n")
}
if first < 0 || last < 0 {
utils.Fatalf("Export error: block number must be greater than 0\n")
}
if head := chain.CurrentSnapBlock(); uint64(last) > head.Number.Uint64() {
utils.Fatalf("Export error: block number %d larger than head block %d\n", uint64(last), head.Number.Uint64())
}
err := utils.ExportHistory(chain, dir, uint64(first), uint64(last), uint64(era.MaxEra1Size))
if err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v\n", time.Since(start))
return nil
}
// importPreimages imports preimage data from the specified file.
// it is deprecated, and the export function has been removed, but
// the import function is kept around for the time being so that
// older file formats can still be imported.
func importPreimages(ctx *cli.Context) error {
if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.")
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, false)
defer db.Close()
start := time.Now()
if err := utils.ImportPreimages(db, ctx.Args().First()); err != nil {
utils.Fatalf("Import error: %v\n", err)
}
fmt.Printf("Import done in %v\n", time.Since(start))
return nil
}
func parseDumpConfig(ctx *cli.Context, db ethdb.Database) (*state.DumpConfig, common.Hash, error) {
var header *types.Header
if ctx.NArg() > 1 {
return nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg())
}
if ctx.NArg() == 1 {
arg := ctx.Args().First()
if hashish(arg) {
hash := common.HexToHash(arg)
if number := rawdb.ReadHeaderNumber(db, hash); number != nil {
header = rawdb.ReadHeader(db, hash, *number)
} else {
return nil, common.Hash{}, fmt.Errorf("block %x not found", hash)
}
} else {
number, err := strconv.ParseUint(arg, 10, 64)
if err != nil {
return nil, common.Hash{}, err
}
if hash := rawdb.ReadCanonicalHash(db, number); hash != (common.Hash{}) {
header = rawdb.ReadHeader(db, hash, number)
} else {
return nil, common.Hash{}, fmt.Errorf("header for block %d not found", number)
}
}
} else {
// Use latest
header = rawdb.ReadHeadHeader(db)
}
if header == nil {
return nil, common.Hash{}, errors.New("no head block found")
}
startArg := common.FromHex(ctx.String(utils.StartKeyFlag.Name))
var start common.Hash
switch len(startArg) {
case 0: // common.Hash
case 32:
start = common.BytesToHash(startArg)
case 20:
start = crypto.Keccak256Hash(startArg)
log.Info("Converting start-address to hash", "address", common.BytesToAddress(startArg), "hash", start.Hex())
default:
return nil, common.Hash{}, fmt.Errorf("invalid start argument: %x. 20 or 32 hex-encoded bytes required", startArg)
}
conf := &state.DumpConfig{
SkipCode: ctx.Bool(utils.ExcludeCodeFlag.Name),
SkipStorage: ctx.Bool(utils.ExcludeStorageFlag.Name),
OnlyWithAddresses: !ctx.Bool(utils.IncludeIncompletesFlag.Name),
Start: start.Bytes(),
Max: ctx.Uint64(utils.DumpLimitFlag.Name),
}
log.Info("State dump configured", "block", header.Number, "hash", header.Hash().Hex(),
"skipcode", conf.SkipCode, "skipstorage", conf.SkipStorage,
"start", hexutil.Encode(conf.Start), "limit", conf.Max)
return conf, header.Root, nil
}
func dump(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
conf, root, err := parseDumpConfig(ctx, db)
if err != nil {
return err
}
triedb := utils.MakeTrieDatabase(ctx, db, true, true, false) // always enable preimage lookup
defer triedb.Close()
state, err := state.New(root, state.NewDatabase(triedb, nil))
if err != nil {
return err
}
if ctx.Bool(utils.IterativeOutputFlag.Name) {
state.IterativeDump(conf, json.NewEncoder(os.Stdout))
} else {
fmt.Println(string(state.Dump(conf)))
}
return nil
}
// hashish returns true for strings that look like hashes.
func hashish(x string) bool {
_, err := strconv.Atoi(x)
return err != nil
}
func pruneHistory(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
// Open the chain database
chain, chaindb := utils.MakeChain(ctx, stack, false)
defer chaindb.Close()
defer chain.Stop()
// Determine the prune point. This will be the first PoS block.
prunePoint, ok := ethconfig.HistoryPrunePoints[chain.Genesis().Hash()]
if !ok || prunePoint == nil {
return errors.New("prune point not found")
}
var (
mergeBlock = prunePoint.BlockNumber
mergeBlockHash = prunePoint.BlockHash.Hex()
)
// Check we're far enough past merge to ensure all data is in freezer
currentHeader := chain.CurrentHeader()
if currentHeader == nil {
return errors.New("current header not found")
}
if currentHeader.Number.Uint64() < mergeBlock+params.FullImmutabilityThreshold {
return fmt.Errorf("chain not far enough past merge block, need %d more blocks",
mergeBlock+params.FullImmutabilityThreshold-currentHeader.Number.Uint64())
}
// Double-check the prune block in db has the expected hash.
hash := rawdb.ReadCanonicalHash(chaindb, mergeBlock)
if hash != common.HexToHash(mergeBlockHash) {
return fmt.Errorf("merge block hash mismatch: got %s, want %s", hash.Hex(), mergeBlockHash)
}
log.Info("Starting history pruning", "head", currentHeader.Number, "tail", mergeBlock, "tailHash", mergeBlockHash)
start := time.Now()
rawdb.PruneTransactionIndex(chaindb, mergeBlock)
if _, err := chaindb.TruncateTail(mergeBlock); err != nil {
return fmt.Errorf("failed to truncate ancient data: %v", err)
}
log.Info("History pruning completed", "tail", mergeBlock, "elapsed", common.PrettyDuration(time.Since(start)))
// TODO(s1na): what if there is a crash between the two prune operations?
return nil
}

408
cmd/aiigo/config.go Normal file
View file

@ -0,0 +1,408 @@
// Copyright 2017 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"bufio"
"errors"
"fmt"
"os"
"reflect"
"runtime"
"slices"
"strings"
"unicode"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/external"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/accounts/usbwallet"
"github.com/ethereum/go-ethereum/beacon/blsync"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/eth/catalyst"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/internal/version"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/naoina/toml"
"github.com/urfave/cli/v2"
)
var (
dumpConfigCommand = &cli.Command{
Action: dumpConfig,
Name: "dumpconfig",
Usage: "Export configuration values in a TOML format",
ArgsUsage: "<dumpfile (optional)>",
Flags: slices.Concat(nodeFlags, rpcFlags),
Description: `Export configuration values in TOML format (to stdout by default).`,
}
configFileFlag = &cli.StringFlag{
Name: "config",
Usage: "TOML configuration file",
Category: flags.EthCategory,
}
)
// These settings ensure that TOML keys use the same names as Go struct fields.
var tomlSettings = toml.Config{
NormFieldName: func(rt reflect.Type, key string) string {
return key
},
FieldToKey: func(rt reflect.Type, field string) string {
return field
},
MissingField: func(rt reflect.Type, field string) error {
id := fmt.Sprintf("%s.%s", rt.String(), field)
if deprecatedConfigFields[id] {
log.Warn(fmt.Sprintf("Config field '%s' is deprecated and won't have any effect.", id))
return nil
}
var link string
if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" {
link = fmt.Sprintf(", see https://godoc.org/%s#%s for available fields", rt.PkgPath(), rt.Name())
}
return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link)
},
}
var deprecatedConfigFields = map[string]bool{
"ethconfig.Config.EVMInterpreter": true,
"ethconfig.Config.EWASMInterpreter": true,
"ethconfig.Config.TrieCleanCacheJournal": true,
"ethconfig.Config.TrieCleanCacheRejournal": true,
"ethconfig.Config.LightServ": true,
"ethconfig.Config.LightIngress": true,
"ethconfig.Config.LightEgress": true,
"ethconfig.Config.LightPeers": true,
"ethconfig.Config.LightNoPrune": true,
"ethconfig.Config.LightNoSyncServe": true,
}
type ethstatsConfig struct {
URL string `toml:",omitempty"`
}
type aiigoConfig struct {
Eth ethconfig.Config
Node node.Config
Ethstats ethstatsConfig
Metrics metrics.Config
}
func loadConfig(file string, cfg *aiigoConfig) error {
f, err := os.Open(file)
if err != nil {
return err
}
defer f.Close()
err = tomlSettings.NewDecoder(bufio.NewReader(f)).Decode(cfg)
// Add file name to errors that have a line number.
if _, ok := err.(*toml.LineError); ok {
err = errors.New(file + ", " + err.Error())
}
return err
}
func defaultNodeConfig() node.Config {
git, _ := version.VCS()
cfg := node.DefaultConfig
cfg.Name = clientIdentifier
cfg.Version = version.WithCommit(git.Commit, git.Date)
cfg.HTTPModules = append(cfg.HTTPModules, "eth")
cfg.WSModules = append(cfg.WSModules, "eth")
cfg.IPCPath = clientIdentifier + ".ipc"
return cfg
}
// loadBaseConfig loads the aiigoConfig based on the given command line
// parameters and config file.
func loadBaseConfig(ctx *cli.Context) aiigoConfig {
// Load defaults.
cfg := aiigoConfig{
Eth: ethconfig.Defaults,
Node: defaultNodeConfig(),
Metrics: metrics.DefaultConfig,
}
// Load config file.
if file := ctx.String(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err)
}
}
// Apply flags.
utils.SetNodeConfig(ctx, &cfg.Node)
return cfg
}
// makeConfigNode loads aiigo configuration and creates a blank node instance.
func makeConfigNode(ctx *cli.Context) (*node.Node, aiigoConfig) {
cfg := loadBaseConfig(ctx)
stack, err := node.New(&cfg.Node)
if err != nil {
utils.Fatalf("Failed to create the protocol stack: %v", err)
}
// Node doesn't by default populate account manager backends
if err := setAccountManagerBackends(stack.Config(), stack.AccountManager(), stack.KeyStoreDir()); err != nil {
utils.Fatalf("Failed to set account manager backends: %v", err)
}
utils.SetEthConfig(ctx, stack, &cfg.Eth)
if ctx.IsSet(utils.EthStatsURLFlag.Name) {
cfg.Ethstats.URL = ctx.String(utils.EthStatsURLFlag.Name)
}
applyMetricConfig(ctx, &cfg)
return stack, cfg
}
// makeFullNode loads aiigo configuration and creates the Ethereum backend.
func makeFullNode(ctx *cli.Context) *node.Node {
stack, cfg := makeConfigNode(ctx)
if ctx.IsSet(utils.OverridePrague.Name) {
v := ctx.Uint64(utils.OverridePrague.Name)
cfg.Eth.OverridePrague = &v
}
if ctx.IsSet(utils.OverrideVerkle.Name) {
v := ctx.Uint64(utils.OverrideVerkle.Name)
cfg.Eth.OverrideVerkle = &v
}
// Start metrics export if enabled
utils.SetupMetrics(&cfg.Metrics)
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
// Create gauge with aiigo system and build information
if eth != nil { // The 'eth' backend may be nil in light mode
var protos []string
for _, p := range eth.Protocols() {
protos = append(protos, fmt.Sprintf("%v/%d", p.Name, p.Version))
}
metrics.NewRegisteredGaugeInfo("aiigo/info", nil).Update(metrics.GaugeInfoValue{
"arch": runtime.GOARCH,
"os": runtime.GOOS,
"version": cfg.Node.Version,
"protocols": strings.Join(protos, ","),
})
}
// Configure log filter RPC API.
filterSystem := utils.RegisterFilterAPI(stack, backend, &cfg.Eth)
// Configure GraphQL if requested.
if ctx.IsSet(utils.GraphQLEnabledFlag.Name) {
utils.RegisterGraphQLService(stack, backend, filterSystem, &cfg.Node)
}
// Add the Ethereum Stats daemon if requested.
if cfg.Ethstats.URL != "" {
utils.RegisterEthStatsService(stack, backend, cfg.Ethstats.URL)
}
// Configure full-sync tester service if requested
if ctx.IsSet(utils.SyncTargetFlag.Name) {
hex := hexutil.MustDecode(ctx.String(utils.SyncTargetFlag.Name))
if len(hex) != common.HashLength {
utils.Fatalf("invalid sync target length: have %d, want %d", len(hex), common.HashLength)
}
utils.RegisterFullSyncTester(stack, eth, common.BytesToHash(hex))
}
if ctx.IsSet(utils.DeveloperFlag.Name) {
// Start dev mode.
simBeacon, err := catalyst.NewSimulatedBeacon(ctx.Uint64(utils.DeveloperPeriodFlag.Name), cfg.Eth.Miner.PendingFeeRecipient, eth)
if err != nil {
utils.Fatalf("failed to register dev mode catalyst service: %v", err)
}
catalyst.RegisterSimulatedBeaconAPIs(stack, simBeacon)
stack.RegisterLifecycle(simBeacon)
} else if ctx.IsSet(utils.BeaconApiFlag.Name) {
// Start blsync mode.
srv := rpc.NewServer()
srv.RegisterName("engine", catalyst.NewConsensusAPI(eth))
blsyncer := blsync.NewClient(utils.MakeBeaconLightConfig(ctx))
blsyncer.SetEngineRPC(rpc.DialInProc(srv))
stack.RegisterLifecycle(blsyncer)
} else {
// Launch the engine API for interacting with external consensus client.
err := catalyst.Register(stack, eth)
if err != nil {
utils.Fatalf("failed to register catalyst service: %v", err)
}
}
return stack
}
// dumpConfig is the dumpconfig command.
func dumpConfig(ctx *cli.Context) error {
_, cfg := makeConfigNode(ctx)
comment := ""
if cfg.Eth.Genesis != nil {
cfg.Eth.Genesis = nil
comment += "# Note: this config doesn't contain the genesis block.\n\n"
}
out, err := tomlSettings.Marshal(&cfg)
if err != nil {
return err
}
dump := os.Stdout
if ctx.NArg() > 0 {
dump, err = os.OpenFile(ctx.Args().Get(0), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer dump.Close()
}
dump.WriteString(comment)
dump.Write(out)
return nil
}
func applyMetricConfig(ctx *cli.Context, cfg *aiigoConfig) {
if ctx.IsSet(utils.MetricsEnabledFlag.Name) {
cfg.Metrics.Enabled = ctx.Bool(utils.MetricsEnabledFlag.Name)
}
if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) {
log.Warn("Expensive metrics are collected by default, please remove this flag", "flag", utils.MetricsEnabledExpensiveFlag.Name)
}
if ctx.IsSet(utils.MetricsHTTPFlag.Name) {
cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name)
}
if ctx.IsSet(utils.MetricsPortFlag.Name) {
cfg.Metrics.Port = ctx.Int(utils.MetricsPortFlag.Name)
}
if ctx.IsSet(utils.MetricsEnableInfluxDBFlag.Name) {
cfg.Metrics.EnableInfluxDB = ctx.Bool(utils.MetricsEnableInfluxDBFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBEndpointFlag.Name) {
cfg.Metrics.InfluxDBEndpoint = ctx.String(utils.MetricsInfluxDBEndpointFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBDatabaseFlag.Name) {
cfg.Metrics.InfluxDBDatabase = ctx.String(utils.MetricsInfluxDBDatabaseFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBUsernameFlag.Name) {
cfg.Metrics.InfluxDBUsername = ctx.String(utils.MetricsInfluxDBUsernameFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBPasswordFlag.Name) {
cfg.Metrics.InfluxDBPassword = ctx.String(utils.MetricsInfluxDBPasswordFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBTagsFlag.Name) {
cfg.Metrics.InfluxDBTags = ctx.String(utils.MetricsInfluxDBTagsFlag.Name)
}
if ctx.IsSet(utils.MetricsEnableInfluxDBV2Flag.Name) {
cfg.Metrics.EnableInfluxDBV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBTokenFlag.Name) {
cfg.Metrics.InfluxDBToken = ctx.String(utils.MetricsInfluxDBTokenFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name) {
cfg.Metrics.InfluxDBBucket = ctx.String(utils.MetricsInfluxDBBucketFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) {
cfg.Metrics.InfluxDBOrganization = ctx.String(utils.MetricsInfluxDBOrganizationFlag.Name)
}
// Sanity-check the commandline flags. It is fine if some unused fields is part
// of the toml-config, but we expect the commandline to only contain relevant
// arguments, otherwise it indicates an error.
var (
enableExport = ctx.Bool(utils.MetricsEnableInfluxDBFlag.Name)
enableExportV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name)
)
if enableExport || enableExportV2 {
v1FlagIsSet := ctx.IsSet(utils.MetricsInfluxDBUsernameFlag.Name) ||
ctx.IsSet(utils.MetricsInfluxDBPasswordFlag.Name)
v2FlagIsSet := ctx.IsSet(utils.MetricsInfluxDBTokenFlag.Name) ||
ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) ||
ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name)
if enableExport && v2FlagIsSet {
utils.Fatalf("Flags --influxdb.metrics.organization, --influxdb.metrics.token, --influxdb.metrics.bucket are only available for influxdb-v2")
} else if enableExportV2 && v1FlagIsSet {
utils.Fatalf("Flags --influxdb.metrics.username, --influxdb.metrics.password are only available for influxdb-v1")
}
}
}
func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error {
scryptN := keystore.StandardScryptN
scryptP := keystore.StandardScryptP
if conf.UseLightweightKDF {
scryptN = keystore.LightScryptN
scryptP = keystore.LightScryptP
}
// Assemble the supported backends
if len(conf.ExternalSigner) > 0 {
log.Info("Using external signer", "url", conf.ExternalSigner)
if extBackend, err := external.NewExternalBackend(conf.ExternalSigner); err == nil {
am.AddBackend(extBackend)
return nil
} else {
return fmt.Errorf("error connecting to external signer: %v", err)
}
}
// For now, we're using EITHER external signer OR local signers.
// If/when we implement some form of lockfile for USB and keystore wallets,
// we can have both, but it's very confusing for the user to see the same
// accounts in both externally and locally, plus very racey.
am.AddBackend(keystore.NewKeyStore(keydir, scryptN, scryptP))
if conf.USB {
// Start a USB hub for Ledger hardware wallets
if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil {
log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err))
} else {
am.AddBackend(ledgerhub)
}
// Start a USB hub for Trezor hardware wallets (HID version)
if trezorhub, err := usbwallet.NewTrezorHubWithHID(); err != nil {
log.Warn(fmt.Sprintf("Failed to start HID Trezor hub, disabling: %v", err))
} else {
am.AddBackend(trezorhub)
}
// Start a USB hub for Trezor hardware wallets (WebUSB version)
if trezorhub, err := usbwallet.NewTrezorHubWithWebUSB(); err != nil {
log.Warn(fmt.Sprintf("Failed to start WebUSB Trezor hub, disabling: %v", err))
} else {
am.AddBackend(trezorhub)
}
}
if len(conf.SmartCardDaemonPath) > 0 {
// Start a smart card hub
if schub, err := scwallet.NewHub(conf.SmartCardDaemonPath, scwallet.Scheme, keydir); err != nil {
log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err))
} else {
am.AddBackend(schub)
}
}
return nil
}

160
cmd/aiigo/consolecmd.go Normal file
View file

@ -0,0 +1,160 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"fmt"
"slices"
"strings"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/console"
"github.com/urfave/cli/v2"
)
var (
consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag}
consoleCommand = &cli.Command{
Action: localConsole,
Name: "console",
Usage: "Start an interactive JavaScript environment",
Flags: slices.Concat(nodeFlags, rpcFlags, consoleFlags),
Description: `
The aiigo console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://aiigo.ethereum.org/docs/interacting-with-aiigo/javascript-console.`,
}
attachCommand = &cli.Command{
Action: remoteConsole,
Name: "attach",
Usage: "Start an interactive JavaScript environment (connect to node)",
ArgsUsage: "[endpoint]",
Flags: slices.Concat([]cli.Flag{utils.DataDirFlag, utils.HttpHeaderFlag}, consoleFlags),
Description: `
The aiigo console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://aiigo.ethereum.org/docs/interacting-with-aiigo/javascript-console.
This command allows to open a console on a running aiigo node.`,
}
javascriptCommand = &cli.Command{
Action: ephemeralConsole,
Name: "js",
Usage: "(DEPRECATED) Execute the specified JavaScript files",
ArgsUsage: "<jsfile> [jsfile...]",
Flags: slices.Concat(nodeFlags, consoleFlags),
Description: `
The JavaScript VM exposes a node admin interface as well as the Ðapp
JavaScript API. See https://aiigo.ethereum.org/docs/interacting-with-aiigo/javascript-console`,
}
)
// localConsole starts a new aiigo node, attaching a JavaScript console to it at the
// same time.
func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
prepare(ctx)
stack := makeFullNode(ctx)
startNode(ctx, stack, true)
defer stack.Close()
// Attach to the newly started node and create the JavaScript console.
client := stack.Attach()
config := console.Config{
DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.String(utils.JSpathFlag.Name),
Client: client,
Preload: utils.MakeConsolePreloads(ctx),
}
console, err := console.New(config)
if err != nil {
return fmt.Errorf("failed to start the JavaScript console: %v", err)
}
defer console.Stop(false)
// If only a short execution was requested, evaluate and return.
if script := ctx.String(utils.ExecFlag.Name); script != "" {
console.Evaluate(script)
return nil
}
// Track node shutdown and stop the console when it goes down.
// This happens when SIGTERM is sent to the process.
go func() {
stack.Wait()
console.StopInteractive()
}()
// Print the welcome screen and enter interactive mode.
console.Welcome()
console.Interactive()
return nil
}
// remoteConsole will connect to a remote aiigo instance, attaching a JavaScript
// console to it.
func remoteConsole(ctx *cli.Context) error {
if ctx.Args().Len() > 1 {
utils.Fatalf("invalid command-line: too many arguments")
}
endpoint := ctx.Args().First()
if endpoint == "" {
cfg := defaultNodeConfig()
utils.SetDataDir(ctx, &cfg)
endpoint = cfg.IPCEndpoint()
}
client, err := utils.DialRPCWithHeaders(endpoint, ctx.StringSlice(utils.HttpHeaderFlag.Name))
if err != nil {
utils.Fatalf("Unable to attach to remote aiigo: %v", err)
}
config := console.Config{
DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.String(utils.JSpathFlag.Name),
Client: client,
Preload: utils.MakeConsolePreloads(ctx),
}
console, err := console.New(config)
if err != nil {
utils.Fatalf("Failed to start the JavaScript console: %v", err)
}
defer console.Stop(false)
if script := ctx.String(utils.ExecFlag.Name); script != "" {
console.Evaluate(script)
return nil
}
// Otherwise print the welcome screen and enter interactive mode
console.Welcome()
console.Interactive()
return nil
}
// ephemeralConsole starts a new aiigo node, attaches an ephemeral JavaScript
// console to it, executes each of the files specified as arguments and tears
// everything down.
func ephemeralConsole(ctx *cli.Context) error {
var b strings.Builder
for _, file := range ctx.Args().Slice() {
b.WriteString(fmt.Sprintf("loadScript('%s');", file))
}
utils.Fatalf(`The "js" command is deprecated. Please use the following instead:
aiigo --exec "%s" console`, b.String())
return nil
}

View file

@ -0,0 +1,160 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"crypto/rand"
"math/big"
"path/filepath"
"runtime"
"strconv"
"strings"
"testing"
"time"
"github.com/ethereum/go-ethereum/internal/version"
)
const (
ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0"
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
)
// spawns aiigo with the given command line args, using a set of flags to minimise
// memory and disk IO. If the args don't set --datadir, the
// child g gets a temporary data directory.
func runMinimalaiigo(t *testing.T, args ...string) *testaiigo {
// --holesky to make the 'writing genesis to disk' faster (no accounts)
// --networkid=1337 to avoid cache bump
// --syncmode=full to avoid allocating fast sync bloom
allArgs := []string{"--holesky", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
"--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64",
"--datadir.minfreedisk", "0"}
return runaiigo(t, append(allArgs, args...)...)
}
// Tests that a node embedded within a console can be started up properly and
// then terminated by closing the input stream.
func TestConsoleWelcome(t *testing.T) {
t.Parallel()
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
// Start a aiigo console, make sure it's cleaned up and terminate the console
aiigo := runMinimalaiigo(t, "--miner.etherbase", coinbase, "console")
// Gather all the infos the welcome message needs to contain
aiigo.SetTemplateFunc("goos", func() string { return runtime.GOOS })
aiigo.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
aiigo.SetTemplateFunc("gover", runtime.Version)
aiigo.SetTemplateFunc("aiigover", func() string { return version.WithCommit("", "") })
aiigo.SetTemplateFunc("niltime", func() string {
return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
})
aiigo.SetTemplateFunc("apis", func() string { return ipcAPIs })
// Verify the actual welcome message to the required template
aiigo.Expect(`
Welcome to the aiigo JavaScript console!
instance: aiigo/v{{aiigover}}/{{goos}}-{{goarch}}/{{gover}}
at block: 0 ({{niltime}})
datadir: {{.Datadir}}
modules: {{apis}}
To exit, press ctrl-d or type exit
> {{.InputLine "exit"}}
`)
aiigo.ExpectExit()
}
// Tests that a console can be attached to a running node via various means.
func TestAttachWelcome(t *testing.T) {
var (
ipc string
httpPort string
wsPort string
)
// Configure the instance for IPC attachment
if runtime.GOOS == "windows" {
ipc = `\\.\pipe\aiigo` + strconv.Itoa(trulyRandInt(100000, 999999))
} else {
ipc = filepath.Join(t.TempDir(), "aiigo.ipc")
}
// And HTTP + WS attachment
p := trulyRandInt(1024, 65533) // Yeah, sometimes this will fail, sorry :P
httpPort = strconv.Itoa(p)
wsPort = strconv.Itoa(p + 1)
aiigo := runMinimalaiigo(t, "--miner.etherbase", "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182",
"--ipcpath", ipc,
"--http", "--http.port", httpPort,
"--ws", "--ws.port", wsPort)
t.Run("ipc", func(t *testing.T) {
waitForEndpoint(t, ipc, 4*time.Second)
testAttachWelcome(t, aiigo, "ipc:"+ipc, ipcAPIs)
})
t.Run("http", func(t *testing.T) {
endpoint := "http://127.0.0.1:" + httpPort
waitForEndpoint(t, endpoint, 4*time.Second)
testAttachWelcome(t, aiigo, endpoint, httpAPIs)
})
t.Run("ws", func(t *testing.T) {
endpoint := "ws://127.0.0.1:" + wsPort
waitForEndpoint(t, endpoint, 4*time.Second)
testAttachWelcome(t, aiigo, endpoint, httpAPIs)
})
aiigo.Kill()
}
func testAttachWelcome(t *testing.T, aiigo *testaiigo, endpoint, apis string) {
// Attach to a running aiigo node and terminate immediately
attach := runaiigo(t, "attach", endpoint)
defer attach.ExpectExit()
attach.CloseStdin()
// Gather all the infos the welcome message needs to contain
attach.SetTemplateFunc("goos", func() string { return runtime.GOOS })
attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
attach.SetTemplateFunc("gover", runtime.Version)
attach.SetTemplateFunc("aiigover", func() string { return version.WithCommit("", "") })
attach.SetTemplateFunc("niltime", func() string {
return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
})
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
attach.SetTemplateFunc("datadir", func() string { return aiigo.Datadir })
attach.SetTemplateFunc("apis", func() string { return apis })
// Verify the actual welcome message to the required template
attach.Expect(`
Welcome to the aiigo JavaScript console!
instance: aiigo/v{{aiigover}}/{{goos}}-{{goarch}}/{{gover}}
at block: 0 ({{niltime}}){{if ipc}}
datadir: {{datadir}}{{end}}
modules: {{apis}}
To exit, press ctrl-d or type exit
> {{.InputLine "exit" }}
`)
attach.ExpectExit()
}
// trulyRandInt generates a crypto random integer used by the console tests to
// not clash network ports with other tests running concurrently.
func trulyRandInt(lo, hi int) int {
num, _ := rand.Int(rand.Reader, big.NewInt(int64(hi-lo)))
return int(num.Int64()) + lo
}

909
cmd/aiigo/dbcmd.go Normal file
View file

@ -0,0 +1,909 @@
// Copyright 2021 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"bytes"
"fmt"
"os"
"os/signal"
"path/filepath"
"slices"
"strconv"
"strings"
"syscall"
"time"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/console/prompt"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
"github.com/olekukonko/tablewriter"
"github.com/urfave/cli/v2"
)
var (
removeStateDataFlag = &cli.BoolFlag{
Name: "remove.state",
Usage: "If set, selects the state data for removal",
}
removeChainDataFlag = &cli.BoolFlag{
Name: "remove.chain",
Usage: "If set, selects the state data for removal",
}
removedbCommand = &cli.Command{
Action: removeDB,
Name: "removedb",
Usage: "Remove blockchain and state databases",
ArgsUsage: "",
Flags: slices.Concat(utils.DatabaseFlags,
[]cli.Flag{removeStateDataFlag, removeChainDataFlag}),
Description: `
Remove blockchain and state databases`,
}
dbCommand = &cli.Command{
Name: "db",
Usage: "Low level database operations",
ArgsUsage: "",
Subcommands: []*cli.Command{
dbInspectCmd,
dbStatCmd,
dbCompactCmd,
dbGetCmd,
dbDeleteCmd,
dbPutCmd,
dbGetSlotsCmd,
dbDumpFreezerIndex,
dbImportCmd,
dbExportCmd,
dbMetadataCmd,
dbCheckStateContentCmd,
dbInspectHistoryCmd,
},
}
dbInspectCmd = &cli.Command{
Action: inspect,
Name: "inspect",
ArgsUsage: "<prefix> <start>",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Usage: "Inspect the storage size for each type of data in the database",
Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`,
}
dbCheckStateContentCmd = &cli.Command{
Action: checkStateContent,
Name: "check-state-content",
ArgsUsage: "<start (optional)>",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Usage: "Verify that state data is cryptographically correct",
Description: `This command iterates the entire database for 32-byte keys, looking for rlp-encoded trie nodes.
For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates
a data corruption.`,
}
dbStatCmd = &cli.Command{
Action: dbStats,
Name: "stats",
Usage: "Print leveldb statistics",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
}
dbCompactCmd = &cli.Command{
Action: dbCompact,
Name: "compact",
Usage: "Compact leveldb database. WARNING: May take a very long time",
Flags: slices.Concat([]cli.Flag{
utils.CacheFlag,
utils.CacheDatabaseFlag,
}, utils.NetworkFlags, utils.DatabaseFlags),
Description: `This command performs a database compaction.
WARNING: This operation may take a very long time to finish, and may cause database
corruption if it is aborted during execution'!`,
}
dbGetCmd = &cli.Command{
Action: dbGet,
Name: "get",
Usage: "Show the value of a database key",
ArgsUsage: "<hex-encoded key>",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: "This command looks up the specified database key from the database.",
}
dbDeleteCmd = &cli.Command{
Action: dbDelete,
Name: "delete",
Usage: "Delete a database key (WARNING: may corrupt your database)",
ArgsUsage: "<hex-encoded key>",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: `This command deletes the specified database key from the database.
WARNING: This is a low-level operation which may cause database corruption!`,
}
dbPutCmd = &cli.Command{
Action: dbPut,
Name: "put",
Usage: "Set the value of a database key (WARNING: may corrupt your database)",
ArgsUsage: "<hex-encoded key> <hex-encoded value>",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: `This command sets a given database key to the given value.
WARNING: This is a low-level operation which may cause database corruption!`,
}
dbGetSlotsCmd = &cli.Command{
Action: dbDumpTrie,
Name: "dumptrie",
Usage: "Show the storage key/values of a given storage trie",
ArgsUsage: "<hex-encoded state root> <hex-encoded account hash> <hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: "This command looks up the specified database key from the database.",
}
dbDumpFreezerIndex = &cli.Command{
Action: freezerInspect,
Name: "freezer-index",
Usage: "Dump out the index of a specific freezer table",
ArgsUsage: "<freezer-type> <table-type> <start (int)> <end (int)>",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: "This command displays information about the freezer index.",
}
dbImportCmd = &cli.Command{
Action: importLDBdata,
Name: "import",
Usage: "Imports leveldb-data from an exported RLP dump.",
ArgsUsage: "<dumpfile> <start (optional)",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: "The import command imports the specific chain data from an RLP encoded stream.",
}
dbExportCmd = &cli.Command{
Action: exportChaindata,
Name: "export",
Usage: "Exports the chain data into an RLP dump. If the <dumpfile> has .gz suffix, gzip compression will be used.",
ArgsUsage: "<type> <dumpfile>",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.",
}
dbMetadataCmd = &cli.Command{
Action: showMetaData,
Name: "metadata",
Usage: "Shows metadata about the chain status.",
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: "Shows metadata about the chain status.",
}
dbInspectHistoryCmd = &cli.Command{
Action: inspectHistory,
Name: "inspect-history",
Usage: "Inspect the state history within block range",
ArgsUsage: "<address> [OPTIONAL <storage-slot>]",
Flags: slices.Concat([]cli.Flag{
&cli.Uint64Flag{
Name: "start",
Usage: "block number of the range start, zero means earliest history",
},
&cli.Uint64Flag{
Name: "end",
Usage: "block number of the range end(included), zero means latest history",
},
&cli.BoolFlag{
Name: "raw",
Usage: "display the decoded raw state value (otherwise shows rlp-encoded value)",
},
}, utils.NetworkFlags, utils.DatabaseFlags),
Description: "This command queries the history of the account or storage slot within the specified block range",
}
)
func removeDB(ctx *cli.Context) error {
stack, config := makeConfigNode(ctx)
// Resolve folder paths.
var (
rootDir = stack.ResolvePath("chaindata")
ancientDir = config.Eth.DatabaseFreezer
)
switch {
case ancientDir == "":
ancientDir = filepath.Join(stack.ResolvePath("chaindata"), "ancient")
case !filepath.IsAbs(ancientDir):
ancientDir = config.Node.ResolvePath(ancientDir)
}
// Delete state data
statePaths := []string{
rootDir,
filepath.Join(ancientDir, rawdb.MerkleStateFreezerName),
filepath.Join(ancientDir, rawdb.VerkleStateFreezerName),
}
confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name)
// Delete ancient chain
chainPaths := []string{filepath.Join(
ancientDir,
rawdb.ChainFreezerName,
)}
confirmAndRemoveDB(chainPaths, "ancient chain", ctx, removeChainDataFlag.Name)
return nil
}
// removeFolder deletes all files (not folders) inside the directory 'dir' (but
// not files in subfolders).
func removeFolder(dir string) {
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
// If we're at the top level folder, recurse into
if path == dir {
return nil
}
// Delete all the files, but not subfolders
if !info.IsDir() {
os.Remove(path)
return nil
}
return filepath.SkipDir
})
}
// confirmAndRemoveDB prompts the user for a last confirmation and removes the
// list of folders if accepted.
func confirmAndRemoveDB(paths []string, kind string, ctx *cli.Context, removeFlagName string) {
var (
confirm bool
err error
)
msg := fmt.Sprintf("Location(s) of '%s': \n", kind)
for _, path := range paths {
msg += fmt.Sprintf("\t- %s\n", path)
}
fmt.Println(msg)
if ctx.IsSet(removeFlagName) {
confirm = ctx.Bool(removeFlagName)
if confirm {
fmt.Printf("Remove '%s'? [y/n] y\n", kind)
} else {
fmt.Printf("Remove '%s'? [y/n] n\n", kind)
}
} else {
confirm, err = prompt.Stdin.PromptConfirm(fmt.Sprintf("Remove '%s'?", kind))
}
switch {
case err != nil:
utils.Fatalf("%v", err)
case !confirm:
log.Info("Database deletion skipped", "kind", kind, "paths", paths)
default:
var (
deleted []string
start = time.Now()
)
for _, path := range paths {
if common.FileExist(path) {
removeFolder(path)
deleted = append(deleted, path)
} else {
log.Info("Folder is not existent", "path", path)
}
}
log.Info("Database successfully deleted", "kind", kind, "paths", deleted, "elapsed", common.PrettyDuration(time.Since(start)))
}
}
func inspect(ctx *cli.Context) error {
var (
prefix []byte
start []byte
)
if ctx.NArg() > 2 {
return fmt.Errorf("max 2 arguments: %v", ctx.Command.ArgsUsage)
}
if ctx.NArg() >= 1 {
if d, err := hexutil.Decode(ctx.Args().Get(0)); err != nil {
return fmt.Errorf("failed to hex-decode 'prefix': %v", err)
} else {
prefix = d
}
}
if ctx.NArg() >= 2 {
if d, err := hexutil.Decode(ctx.Args().Get(1)); err != nil {
return fmt.Errorf("failed to hex-decode 'start': %v", err)
} else {
start = d
}
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
return rawdb.InspectDatabase(db, prefix, start)
}
func checkStateContent(ctx *cli.Context) error {
var (
prefix []byte
start []byte
)
if ctx.NArg() > 1 {
return fmt.Errorf("max 1 argument: %v", ctx.Command.ArgsUsage)
}
if ctx.NArg() > 0 {
if d, err := hexutil.Decode(ctx.Args().First()); err != nil {
return fmt.Errorf("failed to hex-decode 'start': %v", err)
} else {
start = d
}
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
var (
it = rawdb.NewKeyLengthIterator(db.NewIterator(prefix, start), 32)
hasher = crypto.NewKeccakState()
got = make([]byte, 32)
errs int
count int
startTime = time.Now()
lastLog = time.Now()
)
for it.Next() {
count++
k := it.Key()
v := it.Value()
hasher.Reset()
hasher.Write(v)
hasher.Read(got)
if !bytes.Equal(k, got) {
errs++
fmt.Printf("Error at %#x\n", k)
fmt.Printf(" Hash: %#x\n", got)
fmt.Printf(" Data: %#x\n", v)
}
if time.Since(lastLog) > 8*time.Second {
log.Info("Iterating the database", "at", fmt.Sprintf("%#x", k), "elapsed", common.PrettyDuration(time.Since(startTime)))
lastLog = time.Now()
}
}
if err := it.Error(); err != nil {
return err
}
log.Info("Iterated the state content", "errors", errs, "items", count)
return nil
}
func showDBStats(db ethdb.KeyValueStater) {
stats, err := db.Stat()
if err != nil {
log.Warn("Failed to read database stats", "error", err)
return
}
fmt.Println(stats)
}
func dbStats(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
showDBStats(db)
return nil
}
func dbCompact(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, false)
defer db.Close()
log.Info("Stats before compaction")
showDBStats(db)
log.Info("Triggering compaction")
if err := db.Compact(nil, nil); err != nil {
log.Info("Compact err", "error", err)
return err
}
log.Info("Stats after compaction")
showDBStats(db)
return nil
}
// dbGet shows the value of a given database key
func dbGet(ctx *cli.Context) error {
if ctx.NArg() != 1 {
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
key, err := common.ParseHexOrString(ctx.Args().Get(0))
if err != nil {
log.Info("Could not decode the key", "error", err)
return err
}
data, err := db.Get(key)
if err != nil {
log.Info("Get operation failed", "key", fmt.Sprintf("%#x", key), "error", err)
return err
}
fmt.Printf("key %#x: %#x\n", key, data)
return nil
}
// dbDelete deletes a key from the database
func dbDelete(ctx *cli.Context) error {
if ctx.NArg() != 1 {
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, false)
defer db.Close()
key, err := common.ParseHexOrString(ctx.Args().Get(0))
if err != nil {
log.Info("Could not decode the key", "error", err)
return err
}
data, err := db.Get(key)
if err == nil {
fmt.Printf("Previous value: %#x\n", data)
}
if err = db.Delete(key); err != nil {
log.Info("Delete operation returned an error", "key", fmt.Sprintf("%#x", key), "error", err)
return err
}
return nil
}
// dbPut overwrite a value in the database
func dbPut(ctx *cli.Context) error {
if ctx.NArg() != 2 {
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, false)
defer db.Close()
var (
key []byte
value []byte
data []byte
err error
)
key, err = common.ParseHexOrString(ctx.Args().Get(0))
if err != nil {
log.Info("Could not decode the key", "error", err)
return err
}
value, err = hexutil.Decode(ctx.Args().Get(1))
if err != nil {
log.Info("Could not decode the value", "error", err)
return err
}
data, err = db.Get(key)
if err == nil {
fmt.Printf("Previous value: %#x\n", data)
}
return db.Put(key, value)
}
// dbDumpTrie shows the key-value slots of a given storage trie
func dbDumpTrie(ctx *cli.Context) error {
if ctx.NArg() < 3 {
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
triedb := utils.MakeTrieDatabase(ctx, db, false, true, false)
defer triedb.Close()
var (
state []byte
storage []byte
account []byte
start []byte
max = int64(-1)
err error
)
if state, err = hexutil.Decode(ctx.Args().Get(0)); err != nil {
log.Info("Could not decode the state root", "error", err)
return err
}
if account, err = hexutil.Decode(ctx.Args().Get(1)); err != nil {
log.Info("Could not decode the account hash", "error", err)
return err
}
if storage, err = hexutil.Decode(ctx.Args().Get(2)); err != nil {
log.Info("Could not decode the storage trie root", "error", err)
return err
}
if ctx.NArg() > 3 {
if start, err = hexutil.Decode(ctx.Args().Get(3)); err != nil {
log.Info("Could not decode the seek position", "error", err)
return err
}
}
if ctx.NArg() > 4 {
if max, err = strconv.ParseInt(ctx.Args().Get(4), 10, 64); err != nil {
log.Info("Could not decode the max count", "error", err)
return err
}
}
id := trie.StorageTrieID(common.BytesToHash(state), common.BytesToHash(account), common.BytesToHash(storage))
theTrie, err := trie.New(id, triedb)
if err != nil {
return err
}
trieIt, err := theTrie.NodeIterator(start)
if err != nil {
return err
}
var count int64
it := trie.NewIterator(trieIt)
for it.Next() {
if max > 0 && count == max {
fmt.Printf("Exiting after %d values\n", count)
break
}
fmt.Printf(" %d. key %#x: %#x\n", count, it.Key, it.Value)
count++
}
return it.Err
}
func freezerInspect(ctx *cli.Context) error {
if ctx.NArg() < 4 {
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
}
var (
freezer = ctx.Args().Get(0)
table = ctx.Args().Get(1)
)
start, err := strconv.ParseInt(ctx.Args().Get(2), 10, 64)
if err != nil {
log.Info("Could not read start-param", "err", err)
return err
}
end, err := strconv.ParseInt(ctx.Args().Get(3), 10, 64)
if err != nil {
log.Info("Could not read count param", "err", err)
return err
}
stack, _ := makeConfigNode(ctx)
ancient := stack.ResolveAncient("chaindata", ctx.String(utils.AncientFlag.Name))
stack.Close()
return rawdb.InspectFreezerTable(ancient, freezer, table, start, end)
}
func importLDBdata(ctx *cli.Context) error {
start := 0
switch ctx.NArg() {
case 1:
break
case 2:
s, err := strconv.Atoi(ctx.Args().Get(1))
if err != nil {
return fmt.Errorf("second arg must be an integer: %v", err)
}
start = s
default:
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
}
var (
fName = ctx.Args().Get(0)
stack, _ = makeConfigNode(ctx)
interrupt = make(chan os.Signal, 1)
stop = make(chan struct{})
)
defer stack.Close()
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(interrupt)
defer close(interrupt)
go func() {
if _, ok := <-interrupt; ok {
log.Info("Interrupted during ldb import, stopping at next batch")
}
close(stop)
}()
db := utils.MakeChainDatabase(ctx, stack, false)
defer db.Close()
return utils.ImportLDBData(db, fName, int64(start), stop)
}
type preimageIterator struct {
iter ethdb.Iterator
}
func (iter *preimageIterator) Next() (byte, []byte, []byte, bool) {
for iter.iter.Next() {
key := iter.iter.Key()
if bytes.HasPrefix(key, rawdb.PreimagePrefix) && len(key) == (len(rawdb.PreimagePrefix)+common.HashLength) {
return utils.OpBatchAdd, key, iter.iter.Value(), true
}
}
return 0, nil, nil, false
}
func (iter *preimageIterator) Release() {
iter.iter.Release()
}
type snapshotIterator struct {
init bool
account ethdb.Iterator
storage ethdb.Iterator
}
func (iter *snapshotIterator) Next() (byte, []byte, []byte, bool) {
if !iter.init {
iter.init = true
return utils.OpBatchDel, rawdb.SnapshotRootKey, nil, true
}
for iter.account.Next() {
key := iter.account.Key()
if bytes.HasPrefix(key, rawdb.SnapshotAccountPrefix) && len(key) == (len(rawdb.SnapshotAccountPrefix)+common.HashLength) {
return utils.OpBatchAdd, key, iter.account.Value(), true
}
}
for iter.storage.Next() {
key := iter.storage.Key()
if bytes.HasPrefix(key, rawdb.SnapshotStoragePrefix) && len(key) == (len(rawdb.SnapshotStoragePrefix)+2*common.HashLength) {
return utils.OpBatchAdd, key, iter.storage.Value(), true
}
}
return 0, nil, nil, false
}
func (iter *snapshotIterator) Release() {
iter.account.Release()
iter.storage.Release()
}
// chainExporters defines the export scheme for all exportable chain data.
var chainExporters = map[string]func(db ethdb.Database) utils.ChainDataIterator{
"preimage": func(db ethdb.Database) utils.ChainDataIterator {
iter := db.NewIterator(rawdb.PreimagePrefix, nil)
return &preimageIterator{iter: iter}
},
"snapshot": func(db ethdb.Database) utils.ChainDataIterator {
account := db.NewIterator(rawdb.SnapshotAccountPrefix, nil)
storage := db.NewIterator(rawdb.SnapshotStoragePrefix, nil)
return &snapshotIterator{account: account, storage: storage}
},
}
func exportChaindata(ctx *cli.Context) error {
if ctx.NArg() < 2 {
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
}
// Parse the required chain data type, make sure it's supported.
kind := ctx.Args().Get(0)
kind = strings.ToLower(strings.Trim(kind, " "))
exporter, ok := chainExporters[kind]
if !ok {
var kinds []string
for kind := range chainExporters {
kinds = append(kinds, kind)
}
return fmt.Errorf("invalid data type %s, supported types: %s", kind, strings.Join(kinds, ", "))
}
var (
stack, _ = makeConfigNode(ctx)
interrupt = make(chan os.Signal, 1)
stop = make(chan struct{})
)
defer stack.Close()
signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(interrupt)
defer close(interrupt)
go func() {
if _, ok := <-interrupt; ok {
log.Info("Interrupted during db export, stopping at next batch")
}
close(stop)
}()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
return utils.ExportChaindata(ctx.Args().Get(1), kind, exporter(db), stop)
}
func showMetaData(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
ancients, err := db.Ancients()
if err != nil {
fmt.Fprintf(os.Stderr, "Error accessing ancients: %v", err)
}
data := rawdb.ReadChainMetadata(db)
data = append(data, []string{"frozen", fmt.Sprintf("%d items", ancients)})
data = append(data, []string{"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))})
if b := rawdb.ReadHeadBlock(db); b != nil {
data = append(data, []string{"headBlock.Hash", fmt.Sprintf("%v", b.Hash())})
data = append(data, []string{"headBlock.Root", fmt.Sprintf("%v", b.Root())})
data = append(data, []string{"headBlock.Number", fmt.Sprintf("%d (%#x)", b.Number(), b.Number())})
}
if h := rawdb.ReadHeadHeader(db); h != nil {
data = append(data, []string{"headHeader.Hash", fmt.Sprintf("%v", h.Hash())})
data = append(data, []string{"headHeader.Root", fmt.Sprintf("%v", h.Root)})
data = append(data, []string{"headHeader.Number", fmt.Sprintf("%d (%#x)", h.Number, h.Number)})
}
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Field", "Value"})
table.AppendBulk(data)
table.Render()
return nil
}
func inspectAccount(db *triedb.Database, start uint64, end uint64, address common.Address, raw bool) error {
stats, err := db.AccountHistory(address, start, end)
if err != nil {
return err
}
fmt.Printf("Account history:\n\taddress: %s\n\tblockrange: [#%d-#%d]\n", address.Hex(), stats.Start, stats.End)
from := stats.Start
for i := 0; i < len(stats.Blocks); i++ {
var content string
if len(stats.Origins[i]) == 0 {
content = "<empty>"
} else {
if !raw {
content = fmt.Sprintf("%#x", stats.Origins[i])
} else {
account := new(types.SlimAccount)
if err := rlp.DecodeBytes(stats.Origins[i], account); err != nil {
panic(err)
}
code := "<nil>"
if len(account.CodeHash) > 0 {
code = fmt.Sprintf("%#x", account.CodeHash)
}
root := "<nil>"
if len(account.Root) > 0 {
root = fmt.Sprintf("%#x", account.Root)
}
content = fmt.Sprintf("nonce: %d, balance: %d, codeHash: %s, root: %s", account.Nonce, account.Balance, code, root)
}
}
fmt.Printf("#%d - #%d: %s\n", from, stats.Blocks[i], content)
from = stats.Blocks[i]
}
return nil
}
func inspectStorage(db *triedb.Database, start uint64, end uint64, address common.Address, slot common.Hash, raw bool) error {
// The hash of storage slot key is utilized in the history
// rather than the raw slot key, make the conversion.
stats, err := db.StorageHistory(address, slot, start, end)
if err != nil {
return err
}
fmt.Printf("Storage history:\n\taddress: %s\n\tslot: %s\n\tblockrange: [#%d-#%d]\n", address.Hex(), slot.Hex(), stats.Start, stats.End)
from := stats.Start
for i := 0; i < len(stats.Blocks); i++ {
var content string
if len(stats.Origins[i]) == 0 {
content = "<empty>"
} else {
if !raw {
content = fmt.Sprintf("%#x", stats.Origins[i])
} else {
_, data, _, err := rlp.Split(stats.Origins[i])
if err != nil {
fmt.Printf("Failed to decode storage slot, %v", err)
return err
}
content = fmt.Sprintf("%#x", data)
}
}
fmt.Printf("#%d - #%d: %s\n", from, stats.Blocks[i], content)
from = stats.Blocks[i]
}
return nil
}
func inspectHistory(ctx *cli.Context) error {
if ctx.NArg() == 0 || ctx.NArg() > 2 {
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
}
var (
address common.Address
slot common.Hash
)
if err := address.UnmarshalText([]byte(ctx.Args().Get(0))); err != nil {
return err
}
if ctx.NArg() > 1 {
if err := slot.UnmarshalText([]byte(ctx.Args().Get(1))); err != nil {
return err
}
}
// Load the databases.
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
triedb := utils.MakeTrieDatabase(ctx, db, false, false, false)
defer triedb.Close()
var (
err error
start uint64 // the id of first history object to query
end uint64 // the id (included) of last history object to query
)
// State histories are identified by state ID rather than block number.
// To address this, load the corresponding block header and perform the
// conversion by this function.
blockToID := func(blockNumber uint64) (uint64, error) {
header := rawdb.ReadHeader(db, rawdb.ReadCanonicalHash(db, blockNumber), blockNumber)
if header == nil {
return 0, fmt.Errorf("block #%d is not existent", blockNumber)
}
id := rawdb.ReadStateID(db, header.Root)
if id == nil {
first, last, err := triedb.HistoryRange()
if err == nil {
return 0, fmt.Errorf("history of block #%d is not existent, available history range: [#%d-#%d]", blockNumber, first, last)
}
return 0, fmt.Errorf("history of block #%d is not existent", blockNumber)
}
return *id, nil
}
// Parse the starting block number for inspection.
startNumber := ctx.Uint64("start")
if startNumber != 0 {
start, err = blockToID(startNumber)
if err != nil {
return err
}
}
// Parse the ending block number for inspection.
endBlock := ctx.Uint64("end")
if endBlock != 0 {
end, err = blockToID(endBlock)
if err != nil {
return err
}
}
// Inspect the state history.
if slot == (common.Hash{}) {
return inspectAccount(triedb, start, end, address, ctx.Bool("raw"))
}
return inspectStorage(triedb, start, end, address, slot, ctx.Bool("raw"))
}

View file

@ -0,0 +1,45 @@
// Copyright 2022 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"bytes"
"fmt"
"os"
"testing"
"github.com/ethereum/go-ethereum/common"
)
// TestExport does a basic test of "aiigo export", exporting the test-genesis.
func TestExport(t *testing.T) {
t.Parallel()
outfile := fmt.Sprintf("%v/testExport.out", t.TempDir())
aiigo := runaiigo(t, "--datadir", initaiigo(t), "export", outfile)
aiigo.WaitExit()
if have, want := aiigo.ExitStatus(), 0; have != want {
t.Errorf("exit error, have %d want %d", have, want)
}
have, err := os.ReadFile(outfile)
if err != nil {
t.Fatal(err)
}
want := common.FromHex("0xf9026bf90266a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a08758259b018f7bce3d2be2ddb62f325eaeea0a0c188cf96623eab468a4413e03a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180837a12008080b875000000000000000000000000000000000000000000000000000000000000000002f0d131f1f97aef08aec6e3291b957d9efe71050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0")
if !bytes.Equal(have, want) {
t.Fatalf("wrong content exported")
}
}

198
cmd/aiigo/genesis_test.go Normal file
View file

@ -0,0 +1,198 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"fmt"
"os"
"path/filepath"
"strconv"
"testing"
)
var customGenesisTests = []struct {
genesis string
query string
result string
}{
// Genesis file with a mostly-empty chain configuration (ensure missing fields work)
{
genesis: `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000001338",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"config": {
"terminalTotalDifficulty": 0
}
}`,
query: "eth.getBlock(0).nonce",
result: "0x0000000000001338",
},
// Genesis file with specific chain configurations
{
genesis: `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000001339",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"config" : {
"homesteadBlock" : 42,
"daoForkBlock" : 141,
"daoForkSupport" : true,
"terminalTotalDifficulty": 0
}
}`,
query: "eth.getBlock(0).nonce",
result: "0x0000000000001339",
},
}
// Tests that initializing aiigo with a custom genesis block and chain definitions
// work properly.
func TestCustomGenesis(t *testing.T) {
t.Parallel()
for i, tt := range customGenesisTests {
// Create a temporary data directory to use and inspect later
datadir := t.TempDir()
// Initialize the data directory with the custom genesis block
json := filepath.Join(datadir, "genesis.json")
if err := os.WriteFile(json, []byte(tt.genesis), 0600); err != nil {
t.Fatalf("test %d: failed to write genesis file: %v", i, err)
}
runaiigo(t, "--datadir", datadir, "init", json).WaitExit()
// Query the custom genesis block
aiigo := runaiigo(t, "--networkid", "1337", "--syncmode=full", "--cache", "16",
"--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0",
"--nodiscover", "--nat", "none", "--ipcdisable",
"--exec", tt.query, "console")
aiigo.ExpectRegexp(tt.result)
aiigo.ExpectExit()
}
}
// TestCustomBackend that the backend selection and detection (leveldb vs pebble) works properly.
func TestCustomBackend(t *testing.T) {
t.Parallel()
// Test pebble, but only on 64-bit platforms
if strconv.IntSize != 64 {
t.Skip("Custom backends are only available on 64-bit platform")
}
genesis := `{
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000001338",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"config": {
"terminalTotalDifficulty": 0
}
}`
type backendTest struct {
initArgs []string
initExpect string
execArgs []string
execExpect string
}
testfunc := func(t *testing.T, tt backendTest) error {
// Create a temporary data directory to use and inspect later
datadir := t.TempDir()
// Initialize the data directory with the custom genesis block
json := filepath.Join(datadir, "genesis.json")
if err := os.WriteFile(json, []byte(genesis), 0600); err != nil {
return fmt.Errorf("failed to write genesis file: %v", err)
}
{ // Init
args := append(tt.initArgs, "--datadir", datadir, "init", json)
aiigo := runaiigo(t, args...)
aiigo.ExpectRegexp(tt.initExpect)
aiigo.ExpectExit()
}
{ // Exec + query
args := append(tt.execArgs, "--networkid", "1337", "--syncmode=full", "--cache", "16",
"--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0",
"--nodiscover", "--nat", "none", "--ipcdisable",
"--exec", "eth.getBlock(0).nonce", "console")
aiigo := runaiigo(t, args...)
aiigo.ExpectRegexp(tt.execExpect)
aiigo.ExpectExit()
}
return nil
}
for i, tt := range []backendTest{
{ // When not specified, it should default to pebble
execArgs: []string{"--db.engine", "pebble"},
execExpect: "0x0000000000001338",
},
{ // Explicit leveldb
initArgs: []string{"--db.engine", "leveldb"},
execArgs: []string{"--db.engine", "leveldb"},
execExpect: "0x0000000000001338",
},
{ // Explicit leveldb first, then autodiscover
initArgs: []string{"--db.engine", "leveldb"},
execExpect: "0x0000000000001338",
},
{ // Explicit pebble
initArgs: []string{"--db.engine", "pebble"},
execArgs: []string{"--db.engine", "pebble"},
execExpect: "0x0000000000001338",
},
{ // Explicit pebble, then auto-discover
initArgs: []string{"--db.engine", "pebble"},
execExpect: "0x0000000000001338",
},
{ // Can't start pebble on top of leveldb
initArgs: []string{"--db.engine", "leveldb"},
execArgs: []string{"--db.engine", "pebble"},
execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was pebble but found pre-existing leveldb database in specified data directory`,
},
{ // Can't start leveldb on top of pebble
initArgs: []string{"--db.engine", "pebble"},
execArgs: []string{"--db.engine", "leveldb"},
execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was leveldb but found pre-existing pebble database in specified data directory`,
},
{ // Reject invalid backend choice
initArgs: []string{"--db.engine", "mssql"},
initExpect: `Fatal: Invalid choice for db.engine 'mssql', allowed 'leveldb' or 'pebble'`,
// Since the init fails, this will return the (default) mainnet genesis
// block nonce
execExpect: `0x0000000000000042`,
},
} {
if err := testfunc(t, tt); err != nil {
t.Fatalf("test %d-leveldb: %v", i, err)
}
}
}

237
cmd/aiigo/logging_test.go Normal file
View file

@ -0,0 +1,237 @@
// Copyright 2023 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
//go:build integrationtests
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io"
"math/rand"
"os"
"os/exec"
"strings"
"testing"
"github.com/ethereum/go-ethereum/internal/reexec"
)
func runSelf(args ...string) ([]byte, error) {
cmd := &exec.Cmd{
Path: reexec.Self(),
Args: append([]string{"aiigo-test"}, args...),
}
return cmd.CombinedOutput()
}
func split(input io.Reader) []string {
var output []string
scanner := bufio.NewScanner(input)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
output = append(output, strings.TrimSpace(scanner.Text()))
}
return output
}
func censor(input string, start, end int) string {
if len(input) < end {
return input
}
return input[:start] + strings.Repeat("X", end-start) + input[end:]
}
func TestLogging(t *testing.T) {
t.Parallel()
testConsoleLogging(t, "terminal", 6, 24)
testConsoleLogging(t, "logfmt", 2, 26)
}
func testConsoleLogging(t *testing.T, format string, tStart, tEnd int) {
haveB, err := runSelf("--log.format", format, "logtest")
if err != nil {
t.Fatal(err)
}
readFile, err := os.Open(fmt.Sprintf("testdata/logging/logtest-%v.txt", format))
if err != nil {
t.Fatal(err)
}
defer readFile.Close()
wantLines := split(readFile)
haveLines := split(bytes.NewBuffer(haveB))
for i, want := range wantLines {
if i > len(haveLines)-1 {
t.Fatalf("format %v, line %d missing, want:%v", format, i, want)
}
have := haveLines[i]
for strings.Contains(have, "Unknown config environment variable") {
// This can happen on CI runs. Drop it.
haveLines = append(haveLines[:i], haveLines[i+1:]...)
have = haveLines[i]
}
// Black out the timestamp
have = censor(have, tStart, tEnd)
want = censor(want, tStart, tEnd)
if have != want {
t.Logf(nicediff([]byte(have), []byte(want)))
t.Fatalf("format %v, line %d\nhave %v\nwant %v", format, i, have, want)
}
}
if len(haveLines) != len(wantLines) {
t.Errorf("format %v, want %d lines, have %d", format, len(haveLines), len(wantLines))
}
}
func TestJsonLogging(t *testing.T) {
t.Parallel()
haveB, err := runSelf("--log.format", "json", "logtest")
if err != nil {
t.Fatal(err)
}
readFile, err := os.Open("testdata/logging/logtest-json.txt")
if err != nil {
t.Fatal(err)
}
defer readFile.Close()
wantLines := split(readFile)
haveLines := split(bytes.NewBuffer(haveB))
for i, wantLine := range wantLines {
if i > len(haveLines)-1 {
t.Fatalf("format %v, line %d missing, want:%v", "json", i, wantLine)
}
haveLine := haveLines[i]
for strings.Contains(haveLine, "Unknown config environment variable") {
// This can happen on CI runs. Drop it.
haveLines = append(haveLines[:i], haveLines[i+1:]...)
haveLine = haveLines[i]
}
var have, want []byte
{
var h map[string]any
if err := json.Unmarshal([]byte(haveLine), &h); err != nil {
t.Fatal(err)
}
h["t"] = "xxx"
have, _ = json.Marshal(h)
}
{
var w map[string]any
if err := json.Unmarshal([]byte(wantLine), &w); err != nil {
t.Fatal(err)
}
w["t"] = "xxx"
want, _ = json.Marshal(w)
}
if !bytes.Equal(have, want) {
// show an intelligent diff
t.Logf(nicediff(have, want))
t.Errorf("file content wrong")
}
}
}
func TestVmodule(t *testing.T) {
t.Parallel()
checkOutput := func(level int, want, wantNot string) {
t.Helper()
output, err := runSelf("--log.format", "terminal", "--verbosity=0", "--log.vmodule", fmt.Sprintf("logtestcmd_active.go=%d", level), "logtest")
if err != nil {
t.Fatal(err)
}
if len(want) > 0 && !strings.Contains(string(output), want) { // trace should be present at 5
t.Errorf("failed to find expected string ('%s') in output", want)
}
if len(wantNot) > 0 && strings.Contains(string(output), wantNot) { // trace should be present at 5
t.Errorf("string ('%s') should not be present in output", wantNot)
}
}
checkOutput(5, "log at level trace", "") // trace should be present at 5
checkOutput(4, "log at level debug", "log at level trace") // debug should be present at 4, but trace should be missing
checkOutput(3, "log at level info", "log at level debug") // info should be present at 3, but debug should be missing
checkOutput(2, "log at level warn", "log at level info") // warn should be present at 2, but info should be missing
checkOutput(1, "log at level error", "log at level warn") // error should be present at 1, but warn should be missing
}
func nicediff(have, want []byte) string {
var i = 0
for ; i < len(have) && i < len(want); i++ {
if want[i] != have[i] {
break
}
}
var end = i + 40
var start = i - 50
if start < 0 {
start = 0
}
var h, w string
if end < len(have) {
h = string(have[start:end])
} else {
h = string(have[start:])
}
if end < len(want) {
w = string(want[start:end])
} else {
w = string(want[start:])
}
return fmt.Sprintf("have vs want:\n%q\n%q\n", h, w)
}
func TestFileOut(t *testing.T) {
t.Parallel()
var (
have, want []byte
err error
path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63())
)
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "logtest"); err != nil {
t.Fatal(err)
}
if have, err = os.ReadFile(path); err != nil {
t.Fatal(err)
}
if !bytes.Equal(have, want) {
// show an intelligent diff
t.Logf(nicediff(have, want))
t.Errorf("file content wrong")
}
}
func TestRotatingFileOut(t *testing.T) {
t.Parallel()
var (
have, want []byte
err error
path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63())
)
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "--log.rotate", "logtest"); err != nil {
t.Fatal(err)
}
if have, err = os.ReadFile(path); err != nil {
t.Fatal(err)
}
if !bytes.Equal(have, want) {
// show an intelligent diff
t.Logf(nicediff(have, want))
t.Errorf("file content wrong")
}
}

View file

@ -0,0 +1,171 @@
// Copyright 2023 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
//go:build integrationtests
package main
import (
"errors"
"fmt"
"math"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/holiman/uint256"
"github.com/urfave/cli/v2"
)
var logTestCommand = &cli.Command{
Action: logTest,
Name: "logtest",
Usage: "Print some log messages",
ArgsUsage: " ",
Description: `
This command is only meant for testing.
`}
type customQuotedStringer struct {
}
func (c customQuotedStringer) String() string {
return "output with 'quotes'"
}
// logTest is an entry point which spits out some logs. This is used by testing
// to verify expected outputs
func logTest(ctx *cli.Context) error {
{ // big.Int
ba, _ := new(big.Int).SetString("111222333444555678999", 10) // "111,222,333,444,555,678,999"
bb, _ := new(big.Int).SetString("-111222333444555678999", 10) // "-111,222,333,444,555,678,999"
bc, _ := new(big.Int).SetString("11122233344455567899900", 10) // "11,122,233,344,455,567,899,900"
bd, _ := new(big.Int).SetString("-11122233344455567899900", 10) // "-11,122,233,344,455,567,899,900"
log.Info("big.Int", "111,222,333,444,555,678,999", ba)
log.Info("-big.Int", "-111,222,333,444,555,678,999", bb)
log.Info("big.Int", "11,122,233,344,455,567,899,900", bc)
log.Info("-big.Int", "-11,122,233,344,455,567,899,900", bd)
}
{ //uint256
ua, _ := uint256.FromDecimal("111222333444555678999")
ub, _ := uint256.FromDecimal("11122233344455567899900")
log.Info("uint256", "111,222,333,444,555,678,999", ua)
log.Info("uint256", "11,122,233,344,455,567,899,900", ub)
}
{ // int64
log.Info("int64", "1,000,000", int64(1000000))
log.Info("int64", "-1,000,000", int64(-1000000))
log.Info("int64", "9,223,372,036,854,775,807", int64(math.MaxInt64))
log.Info("int64", "-9,223,372,036,854,775,808", int64(math.MinInt64))
}
{ // uint64
log.Info("uint64", "1,000,000", uint64(1000000))
log.Info("uint64", "18,446,744,073,709,551,615", uint64(math.MaxUint64))
}
{ // Special characters
log.Info("Special chars in value", "key", "special \r\n\t chars")
log.Info("Special chars in key", "special \n\t chars", "value")
log.Info("nospace", "nospace", "nospace")
log.Info("with space", "with nospace", "with nospace")
log.Info("Bash escapes in value", "key", "\u001b[1G\u001b[K\u001b[1A")
log.Info("Bash escapes in key", "\u001b[1G\u001b[K\u001b[1A", "value")
log.Info("Bash escapes in message \u001b[1G\u001b[K\u001b[1A end", "key", "value")
colored := fmt.Sprintf("\u001B[%dmColored\u001B[0m[", 35)
log.Info(colored, colored, colored)
err := errors.New("this is an 'error'")
log.Info("an error message with quotes", "error", err)
}
{ // Custom Stringer() - type
log.Info("Custom Stringer value", "2562047h47m16.854s", common.PrettyDuration(time.Duration(9223372036854775807)))
var c customQuotedStringer
log.Info("a custom stringer that emits quoted text", "output", c)
}
{ // Multi-line message
log.Info("A message with wonky \U0001F4A9 characters")
log.Info("A multiline message \nINFO [10-18|14:11:31.106] with wonky characters \U0001F4A9")
log.Info("A multiline message \nLALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above")
}
{ // Miscellaneous json-quirks
// This will check if the json output uses strings or json-booleans to represent bool values
log.Info("boolean", "true", true, "false", false)
// Handling of duplicate keys.
// This is actually ill-handled by the current handler: the format.go
// uses a global 'fieldPadding' map and mixes up the two keys. If 'alpha'
// is shorter than beta, it sometimes causes erroneous padding -- and what's more
// it causes _different_ padding in multi-handler context, e.g. both file-
// and console output, making the two mismatch.
log.Info("repeated-key 1", "foo", "alpha", "foo", "beta")
log.Info("repeated-key 2", "xx", "short", "xx", "longer")
}
{ // loglevels
log.Debug("log at level debug")
log.Trace("log at level trace")
log.Info("log at level info")
log.Warn("log at level warn")
log.Error("log at level error")
}
{
// The current log formatter has a global map of paddings, storing the
// longest seen padding per key in a map. This results in a statefulness
// which has some odd side-effects. Demonstrated here:
log.Info("test", "bar", "short", "a", "aligned left")
log.Info("test", "bar", "a long message", "a", 1)
log.Info("test", "bar", "short", "a", "aligned right")
}
{
// This sequence of logs should be output with alignment, so each field becoems a column.
log.Info("The following logs should align so that the key-fields make 5 columns")
log.Info("Inserted known block", "number", 1_012, "hash", common.HexToHash("0x1234"), "txs", 200, "gas", 1_123_123, "other", "first")
log.Info("Inserted new block", "number", 1, "hash", common.HexToHash("0x1235"), "txs", 2, "gas", 1_123, "other", "second")
log.Info("Inserted known block", "number", 99, "hash", common.HexToHash("0x12322"), "txs", 10, "gas", 1, "other", "third")
log.Warn("Inserted known block", "number", 1_012, "hash", common.HexToHash("0x1234"), "txs", 200, "gas", 99, "other", "fourth")
}
{ // Various types of nil
type customStruct struct {
A string
B *uint64
}
log.Info("(*big.Int)(nil)", "<nil>", (*big.Int)(nil))
log.Info("(*uint256.Int)(nil)", "<nil>", (*uint256.Int)(nil))
log.Info("(fmt.Stringer)(nil)", "res", (fmt.Stringer)(nil))
log.Info("nil-concrete-stringer", "res", (*time.Time)(nil))
log.Info("error(nil) ", "res", error(nil))
log.Info("nil-concrete-error", "res", (*customError)(nil))
log.Info("nil-custom-struct", "res", (*customStruct)(nil))
log.Info("raw nil", "res", nil)
log.Info("(*uint64)(nil)", "res", (*uint64)(nil))
}
{ // Logging with 'reserved' keys
log.Info("Using keys 't', 'lvl', 'time', 'level' and 'msg'", "t", "t", "time", "time", "lvl", "lvl", "level", "level", "msg", "msg")
}
{ // Logging with wrong attr-value pairs
log.Info("Odd pair (1 attr)", "key")
log.Info("Odd pair (3 attr)", "key", "value", "key2")
}
return nil
}
// customError is a type which implements error
type customError struct{}
func (c *customError) Error() string { return "" }

View file

@ -0,0 +1,23 @@
// Copyright 2023 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
//go:build !integrationtests
package main
import "github.com/urfave/cli/v2"
var logTestCommand *cli.Command

428
cmd/aiigo/main.go Normal file
View file

@ -0,0 +1,428 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// aiigo is a command-line client for Ethereum.
package main
import (
"fmt"
"os"
"slices"
"sort"
"strconv"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/console/prompt"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"go.uber.org/automaxprocs/maxprocs"
// Force-load the tracer engines to trigger registration
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
_ "github.com/ethereum/go-ethereum/eth/tracers/live"
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
"github.com/urfave/cli/v2"
)
const (
clientIdentifier = "aiigo" // Client identifier to advertise over the network
)
var (
// flags that configure the node
nodeFlags = slices.Concat([]cli.Flag{
utils.IdentityFlag,
utils.UnlockedAccountFlag,
utils.PasswordFileFlag,
utils.BootnodesFlag,
utils.MinFreeDiskSpaceFlag,
utils.KeyStoreDirFlag,
utils.ExternalSignerFlag,
utils.NoUSBFlag, // deprecated
utils.USBFlag,
utils.SmartCardDaemonPathFlag,
utils.OverridePrague,
utils.OverrideVerkle,
utils.EnablePersonal, // deprecated
utils.TxPoolLocalsFlag,
utils.TxPoolNoLocalsFlag,
utils.TxPoolJournalFlag,
utils.TxPoolRejournalFlag,
utils.TxPoolPriceLimitFlag,
utils.TxPoolPriceBumpFlag,
utils.TxPoolAccountSlotsFlag,
utils.TxPoolGlobalSlotsFlag,
utils.TxPoolAccountQueueFlag,
utils.TxPoolGlobalQueueFlag,
utils.TxPoolLifetimeFlag,
utils.BlobPoolDataDirFlag,
utils.BlobPoolDataCapFlag,
utils.BlobPoolPriceBumpFlag,
utils.SyncModeFlag,
utils.SyncTargetFlag,
utils.ExitWhenSyncedFlag,
utils.GCModeFlag,
utils.SnapshotFlag,
utils.TxLookupLimitFlag, // deprecated
utils.TransactionHistoryFlag,
utils.ChainHistoryFlag,
utils.LogHistoryFlag,
utils.LogNoHistoryFlag,
utils.LogExportCheckpointsFlag,
utils.StateHistoryFlag,
utils.LightServeFlag, // deprecated
utils.LightIngressFlag, // deprecated
utils.LightEgressFlag, // deprecated
utils.LightMaxPeersFlag, // deprecated
utils.LightNoPruneFlag, // deprecated
utils.LightKDFFlag,
utils.LightNoSyncServeFlag, // deprecated
utils.EthRequiredBlocksFlag,
utils.LegacyWhitelistFlag, // deprecated
utils.BloomFilterSizeFlag,
utils.CacheFlag,
utils.CacheDatabaseFlag,
utils.CacheTrieFlag,
utils.CacheTrieJournalFlag, // deprecated
utils.CacheTrieRejournalFlag, // deprecated
utils.CacheGCFlag,
utils.CacheSnapshotFlag,
utils.CacheNoPrefetchFlag,
utils.CachePreimagesFlag,
utils.CacheLogSizeFlag,
utils.FDLimitFlag,
utils.CryptoKZGFlag,
utils.ListenPortFlag,
utils.DiscoveryPortFlag,
utils.MaxPeersFlag,
utils.MaxPendingPeersFlag,
utils.MiningEnabledFlag, // deprecated
utils.MinerGasLimitFlag,
utils.MinerGasPriceFlag,
utils.MinerEtherbaseFlag, // deprecated
utils.MinerExtraDataFlag,
utils.MinerRecommitIntervalFlag,
utils.MinerPendingFeeRecipientFlag,
utils.MinerNewPayloadTimeoutFlag, // deprecated
utils.NATFlag,
utils.NoDiscoverFlag,
utils.DiscoveryV4Flag,
utils.DiscoveryV5Flag,
utils.LegacyDiscoveryV5Flag, // deprecated
utils.NetrestrictFlag,
utils.NodeKeyFileFlag,
utils.NodeKeyHexFlag,
utils.DNSDiscoveryFlag,
utils.DeveloperFlag,
utils.DeveloperGasLimitFlag,
utils.DeveloperPeriodFlag,
utils.VMEnableDebugFlag,
utils.VMTraceFlag,
utils.VMTraceJsonConfigFlag,
utils.NetworkIdFlag,
utils.EthStatsURLFlag,
utils.GpoBlocksFlag,
utils.GpoPercentileFlag,
utils.GpoMaxGasPriceFlag,
utils.GpoIgnoreGasPriceFlag,
configFileFlag,
utils.LogDebugFlag,
utils.LogBacktraceAtFlag,
utils.BeaconApiFlag,
utils.BeaconApiHeaderFlag,
utils.BeaconThresholdFlag,
utils.BeaconNoFilterFlag,
utils.BeaconConfigFlag,
utils.BeaconGenesisRootFlag,
utils.BeaconGenesisTimeFlag,
utils.BeaconCheckpointFlag,
}, utils.NetworkFlags, utils.DatabaseFlags)
rpcFlags = []cli.Flag{
utils.HTTPEnabledFlag,
utils.HTTPListenAddrFlag,
utils.HTTPPortFlag,
utils.HTTPCORSDomainFlag,
utils.AuthListenFlag,
utils.AuthPortFlag,
utils.AuthVirtualHostsFlag,
utils.JWTSecretFlag,
utils.HTTPVirtualHostsFlag,
utils.GraphQLEnabledFlag,
utils.GraphQLCORSDomainFlag,
utils.GraphQLVirtualHostsFlag,
utils.HTTPApiFlag,
utils.HTTPPathPrefixFlag,
utils.WSEnabledFlag,
utils.WSListenAddrFlag,
utils.WSPortFlag,
utils.WSApiFlag,
utils.WSAllowedOriginsFlag,
utils.WSPathPrefixFlag,
utils.IPCDisabledFlag,
utils.IPCPathFlag,
utils.InsecureUnlockAllowedFlag,
utils.RPCGlobalGasCapFlag,
utils.RPCGlobalEVMTimeoutFlag,
utils.RPCGlobalTxFeeCapFlag,
utils.AllowUnprotectedTxs,
utils.BatchRequestLimit,
utils.BatchResponseMaxSize,
}
metricsFlags = []cli.Flag{
utils.MetricsEnabledFlag,
utils.MetricsEnabledExpensiveFlag,
utils.MetricsHTTPFlag,
utils.MetricsPortFlag,
utils.MetricsEnableInfluxDBFlag,
utils.MetricsInfluxDBEndpointFlag,
utils.MetricsInfluxDBDatabaseFlag,
utils.MetricsInfluxDBUsernameFlag,
utils.MetricsInfluxDBPasswordFlag,
utils.MetricsInfluxDBTagsFlag,
utils.MetricsEnableInfluxDBV2Flag,
utils.MetricsInfluxDBTokenFlag,
utils.MetricsInfluxDBBucketFlag,
utils.MetricsInfluxDBOrganizationFlag,
}
)
var app = flags.NewApp("the go-ethereum command line interface")
func init() {
// Initialize the CLI app and start aiigo
app.Action = aiigo
app.Commands = []*cli.Command{
// See chaincmd.go:
initCommand,
importCommand,
exportCommand,
importHistoryCommand,
exportHistoryCommand,
importPreimagesCommand,
removedbCommand,
dumpCommand,
dumpGenesisCommand,
pruneCommand,
// See accountcmd.go:
accountCommand,
walletCommand,
// See consolecmd.go:
consoleCommand,
attachCommand,
javascriptCommand,
// See misccmd.go:
versionCommand,
versionCheckCommand,
licenseCommand,
// See config.go
dumpConfigCommand,
// see dbcmd.go
dbCommand,
// See cmd/utils/flags_legacy.go
utils.ShowDeprecated,
// See snapshot.go
snapshotCommand,
// See verkle.go
verkleCommand,
}
if logTestCommand != nil {
app.Commands = append(app.Commands, logTestCommand)
}
sort.Sort(cli.CommandsByName(app.Commands))
app.Flags = slices.Concat(
nodeFlags,
rpcFlags,
consoleFlags,
debug.Flags,
metricsFlags,
)
flags.AutoEnvVars(app.Flags, "aiigo")
app.Before = func(ctx *cli.Context) error {
maxprocs.Set() // Automatically set GOMAXPROCS to match Linux container CPU quota.
flags.MigrateGlobalFlags(ctx)
if err := debug.Setup(ctx); err != nil {
return err
}
flags.CheckEnvVars(ctx, app.Flags, "aiigo")
return nil
}
app.After = func(ctx *cli.Context) error {
debug.Exit()
prompt.Stdin.Close() // Resets terminal mode.
return nil
}
}
func main() {
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
// prepare manipulates memory cache allowance and setups metric system.
// This function should be called before launching devp2p stack.
func prepare(ctx *cli.Context) {
// If we're running a known preset, log it for convenience.
switch {
case ctx.IsSet(utils.SepoliaFlag.Name):
log.Info("Starting aiigo on Sepolia testnet...")
case ctx.IsSet(utils.HoleskyFlag.Name):
log.Info("Starting aiigo on Holesky testnet...")
case ctx.IsSet(utils.HoodiFlag.Name):
log.Info("Starting aiigo on Hoodi testnet...")
case ctx.IsSet(utils.DeveloperFlag.Name):
log.Info("Starting aiigo in ephemeral dev mode...")
log.Warn(`You are running aiigo in --dev mode. Please note the following:
1. This mode is only intended for fast, iterative development without assumptions on
security or persistence.
2. The database is created in memory unless specified otherwise. Therefore, shutting down
your computer or losing power will wipe your entire block data and chain state for
your dev environment.
3. A random, pre-allocated developer account will be available and unlocked as
eth.coinbase, which can be used for testing. The random dev account is temporary,
stored on a ramdisk, and will be lost if your machine is restarted.
4. Mining is enabled by default. However, the client will only seal blocks if transactions
are pending in the mempool. The miner's minimum accepted gas price is 1.
5. Networking is disabled; there is no listen-address, the maximum number of peers is set
to 0, and discovery is disabled.
`)
case !ctx.IsSet(utils.NetworkIdFlag.Name):
log.Info("Starting aiigo on Ethereum mainnet...")
}
// If we're a full node on mainnet without --cache specified, bump default cache allowance
if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {
// Make sure we're not on any supported preconfigured testnet either
if !ctx.IsSet(utils.HoleskyFlag.Name) &&
!ctx.IsSet(utils.SepoliaFlag.Name) &&
!ctx.IsSet(utils.HoodiFlag.Name) &&
!ctx.IsSet(utils.DeveloperFlag.Name) {
// Nope, we're really on mainnet. Bump that cache up!
log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)
ctx.Set(utils.CacheFlag.Name, strconv.Itoa(4096))
}
}
}
// aiigo is the main entry point into the system if no special subcommand is run.
// It creates a default node based on the command line arguments and runs it in
// blocking mode, waiting for it to be shut down.
func aiigo(ctx *cli.Context) error {
if args := ctx.Args().Slice(); len(args) > 0 {
return fmt.Errorf("invalid command: %q", args[0])
}
prepare(ctx)
stack := makeFullNode(ctx)
defer stack.Close()
startNode(ctx, stack, false)
stack.Wait()
return nil
}
// startNode boots up the system node and all registered protocols, after which
// it starts the RPC/IPC interfaces and the miner.
func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) {
// Start up the node itself
utils.StartNode(ctx, stack, isConsole)
if ctx.IsSet(utils.UnlockedAccountFlag.Name) {
log.Warn(`The "unlock" flag has been deprecated and has no effect`)
}
// Register wallet event handlers to open and auto-derive wallets
events := make(chan accounts.WalletEvent, 16)
stack.AccountManager().Subscribe(events)
// Create a client to interact with local aiigo node.
rpcClient := stack.Attach()
ethClient := ethclient.NewClient(rpcClient)
go func() {
// Open any wallets already attached
for _, wallet := range stack.AccountManager().Wallets() {
if err := wallet.Open(""); err != nil {
log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
}
}
// Listen for wallet event till termination
for event := range events {
switch event.Kind {
case accounts.WalletArrived:
if err := event.Wallet.Open(""); err != nil {
log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
}
case accounts.WalletOpened:
status, _ := event.Wallet.Status()
log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
var derivationPaths []accounts.DerivationPath
if event.Wallet.URL().Scheme == "ledger" {
derivationPaths = append(derivationPaths, accounts.LegacyLedgerBaseDerivationPath)
}
derivationPaths = append(derivationPaths, accounts.DefaultBaseDerivationPath)
event.Wallet.SelfDerive(derivationPaths, ethClient)
case accounts.WalletDropped:
log.Info("Old wallet dropped", "url", event.Wallet.URL())
event.Wallet.Close()
}
}
}()
// Spawn a standalone goroutine for status synchronization monitoring,
// close the node when synchronization is complete if user required.
if ctx.Bool(utils.ExitWhenSyncedFlag.Name) {
go func() {
sub := stack.EventMux().Subscribe(downloader.DoneEvent{})
defer sub.Unsubscribe()
for {
event := <-sub.Chan()
if event == nil {
continue
}
done, ok := event.Data.(downloader.DoneEvent)
if !ok {
continue
}
if timestamp := time.Unix(int64(done.Latest.Time), 0); time.Since(timestamp) < 10*time.Minute {
log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(),
"age", common.PrettyAge(timestamp))
stack.Close()
}
}
}()
}
}

104
cmd/aiigo/misccmd.go Normal file
View file

@ -0,0 +1,104 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"fmt"
"os"
"runtime"
"strings"
"github.com/ethereum/go-ethereum/internal/version"
"github.com/urfave/cli/v2"
)
var (
VersionCheckUrlFlag = &cli.StringFlag{
Name: "check.url",
Usage: "URL to use when checking vulnerabilities",
Value: "https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities.json",
}
VersionCheckVersionFlag = &cli.StringFlag{
Name: "check.version",
Usage: "Version to check",
Value: version.ClientName(clientIdentifier),
}
versionCommand = &cli.Command{
Action: printVersion,
Name: "version",
Usage: "Print version numbers",
ArgsUsage: " ",
Description: `
The output of this command is supposed to be machine-readable.
`,
}
versionCheckCommand = &cli.Command{
Action: versionCheck,
Flags: []cli.Flag{
VersionCheckUrlFlag,
VersionCheckVersionFlag,
},
Name: "version-check",
Usage: "Checks (online) for known aiigo security vulnerabilities",
ArgsUsage: "<versionstring (optional)>",
Description: `
The version-check command fetches vulnerability-information from https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities.json,
and displays information about any security vulnerabilities that affect the currently executing version.
`,
}
licenseCommand = &cli.Command{
Action: license,
Name: "license",
Usage: "Display license information",
ArgsUsage: " ",
}
)
func printVersion(ctx *cli.Context) error {
git, _ := version.VCS()
fmt.Println(strings.Title(clientIdentifier))
fmt.Println("Version:", version.WithMeta)
if git.Commit != "" {
fmt.Println("Git Commit:", git.Commit)
}
if git.Date != "" {
fmt.Println("Git Commit Date:", git.Date)
}
fmt.Println("Architecture:", runtime.GOARCH)
fmt.Println("Go Version:", runtime.Version())
fmt.Println("Operating System:", runtime.GOOS)
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
return nil
}
func license(_ *cli.Context) error {
fmt.Println(`aiigo is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
aiigo 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with aiigo. If not, see <http://www.gnu.org/licenses/>.`)
return nil
}

120
cmd/aiigo/run_test.go Normal file
View file

@ -0,0 +1,120 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"context"
"fmt"
"os"
"testing"
"time"
"github.com/ethereum/go-ethereum/internal/cmdtest"
"github.com/ethereum/go-ethereum/internal/reexec"
"github.com/ethereum/go-ethereum/rpc"
)
type testaiigo struct {
*cmdtest.TestCmd
// template variables for expect
Datadir string
Etherbase string
}
func init() {
// Run the app if we've been exec'd as "aiigo-test" in runaiigo.
reexec.Register("aiigo-test", func() {
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
os.Exit(0)
})
}
func TestMain(m *testing.M) {
// check if we have been reexec'd
if reexec.Init() {
return
}
os.Exit(m.Run())
}
func initaiigo(t *testing.T) string {
args := []string{"--networkid=42", "init", "./testdata/clique.json"}
t.Logf("Initializing aiigo: %v ", args)
g := runaiigo(t, args...)
datadir := g.Datadir
g.WaitExit()
return datadir
}
// spawns aiigo with the given command line args. If the args don't set --datadir, the
// child g gets a temporary data directory.
func runaiigo(t *testing.T, args ...string) *testaiigo {
tt := &testaiigo{}
tt.TestCmd = cmdtest.NewTestCmd(t, tt)
for i, arg := range args {
switch arg {
case "--datadir":
if i < len(args)-1 {
tt.Datadir = args[i+1]
}
case "--miner.etherbase":
if i < len(args)-1 {
tt.Etherbase = args[i+1]
}
}
}
if tt.Datadir == "" {
// The temporary datadir will be removed automatically if something fails below.
tt.Datadir = t.TempDir()
args = append([]string{"--datadir", tt.Datadir}, args...)
}
// Boot "aiigo". This actually runs the test binary but the TestMain
// function will prevent any tests from running.
tt.Run("aiigo-test", args...)
return tt
}
// waitForEndpoint attempts to connect to an RPC endpoint until it succeeds.
func waitForEndpoint(t *testing.T, endpoint string, timeout time.Duration) {
probe := func() bool {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
c, err := rpc.DialContext(ctx, endpoint)
if c != nil {
_, err = c.SupportedModules()
c.Close()
}
return err == nil
}
start := time.Now()
for {
if probe() {
return
}
if time.Since(start) > timeout {
t.Fatal("endpoint", endpoint, "did not open within", timeout)
}
time.Sleep(200 * time.Millisecond)
}
}

694
cmd/aiigo/snapshot.go Normal file
View file

@ -0,0 +1,694 @@
// Copyright 2021 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"os"
"slices"
"time"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/pruner"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/urfave/cli/v2"
)
var (
snapshotCommand = &cli.Command{
Name: "snapshot",
Usage: "A set of commands based on the snapshot",
Description: "",
Subcommands: []*cli.Command{
{
Name: "prune-state",
Usage: "Prune stale ethereum state data based on the snapshot",
ArgsUsage: "<root>",
Action: pruneState,
Flags: slices.Concat([]cli.Flag{
utils.BloomFilterSizeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags),
Description: `
aiigo snapshot prune-state <state-root>
will prune historical state data with the help of the state snapshot.
All trie nodes and contract codes that do not belong to the specified
version state will be deleted from the database. After pruning, only
two version states are available: genesis and the specific one.
The default pruning target is the HEAD-127 state.
WARNING: it's only supported in hash mode(--state.scheme=hash)".
`,
},
{
Name: "verify-state",
Usage: "Recalculate state hash based on the snapshot for verification",
ArgsUsage: "<root>",
Action: verifyState,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: `
aiigo snapshot verify-state <state-root>
will traverse the whole accounts and storages set based on the specified
snapshot and recalculate the root hash of state for verification.
In other words, this command does the snapshot to trie conversion.
`,
},
{
Name: "check-dangling-storage",
Usage: "Check that there is no 'dangling' snap storage",
ArgsUsage: "<root>",
Action: checkDanglingStorage,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: `
aiigo snapshot check-dangling-storage <state-root> traverses the snap storage
data, and verifies that all snapshot storage data has a corresponding account.
`,
},
{
Name: "inspect-account",
Usage: "Check all snapshot layers for the specific account",
ArgsUsage: "<address | hash>",
Action: checkAccount,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: `
aiigo snapshot inspect-account <address | hash> checks all snapshot layers and prints out
information about the specified address.
`,
},
{
Name: "traverse-state",
Usage: "Traverse the state with given root hash and perform quick verification",
ArgsUsage: "<root>",
Action: traverseState,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: `
aiigo snapshot traverse-state <state-root>
will traverse the whole state from the given state root and will abort if any
referenced trie node or contract code is missing. This command can be used for
state integrity verification. The default checking target is the HEAD state.
It's also usable without snapshot enabled.
`,
},
{
Name: "traverse-rawstate",
Usage: "Traverse the state with given root hash and perform detailed verification",
ArgsUsage: "<root>",
Action: traverseRawState,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: `
aiigo snapshot traverse-rawstate <state-root>
will traverse the whole state from the given root and will abort if any referenced
trie node or contract code is missing. This command can be used for state integrity
verification. The default checking target is the HEAD state. It's basically identical
to traverse-state, but the check granularity is smaller.
It's also usable without snapshot enabled.
`,
},
{
Name: "dump",
Usage: "Dump a specific block from storage (same as 'aiigo dump' but using snapshots)",
ArgsUsage: "[? <blockHash> | <blockNum>]",
Action: dumpState,
Flags: slices.Concat([]cli.Flag{
utils.ExcludeCodeFlag,
utils.ExcludeStorageFlag,
utils.StartKeyFlag,
utils.DumpLimitFlag,
}, utils.NetworkFlags, utils.DatabaseFlags),
Description: `
This command is semantically equivalent to 'aiigo dump', but uses the snapshots
as the backend data source, making this command a lot faster.
The argument is interpreted as block number or hash. If none is provided, the latest
block is used.
`,
},
{
Action: snapshotExportPreimages,
Name: "export-preimages",
Usage: "Export the preimage in snapshot enumeration order",
ArgsUsage: "<dumpfile> [<root>]",
Flags: utils.DatabaseFlags,
Description: `
The export-preimages command exports hash preimages to a flat file, in exactly
the expected order for the overlay tree migration.
`,
},
},
}
)
// Deprecation: this command should be deprecated once the hash-based
// scheme is deprecated.
func pruneState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chaindb := utils.MakeChainDatabase(ctx, stack, false)
defer chaindb.Close()
if rawdb.ReadStateScheme(chaindb) != rawdb.HashScheme {
log.Crit("Offline pruning is not required for path scheme")
}
prunerconfig := pruner.Config{
Datadir: stack.ResolvePath(""),
BloomSize: ctx.Uint64(utils.BloomFilterSizeFlag.Name),
}
pruner, err := pruner.NewPruner(chaindb, prunerconfig)
if err != nil {
log.Error("Failed to open snapshot tree", "err", err)
return err
}
if ctx.NArg() > 1 {
log.Error("Too many arguments given")
return errors.New("too many arguments")
}
var targetRoot common.Hash
if ctx.NArg() == 1 {
targetRoot, err = parseRoot(ctx.Args().First())
if err != nil {
log.Error("Failed to resolve state root", "err", err)
return err
}
}
if err = pruner.Prune(targetRoot); err != nil {
log.Error("Failed to prune state", "err", err)
return err
}
return nil
}
func verifyState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chaindb := utils.MakeChainDatabase(ctx, stack, true)
defer chaindb.Close()
headBlock := rawdb.ReadHeadBlock(chaindb)
if headBlock == nil {
log.Error("Failed to load head block")
return errors.New("no head block")
}
triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true, false)
defer triedb.Close()
snapConfig := snapshot.Config{
CacheSize: 256,
Recovery: false,
NoBuild: true,
AsyncBuild: false,
}
snaptree, err := snapshot.New(snapConfig, chaindb, triedb, headBlock.Root())
if err != nil {
log.Error("Failed to open snapshot tree", "err", err)
return err
}
if ctx.NArg() > 1 {
log.Error("Too many arguments given")
return errors.New("too many arguments")
}
var root = headBlock.Root()
if ctx.NArg() == 1 {
root, err = parseRoot(ctx.Args().First())
if err != nil {
log.Error("Failed to resolve state root", "err", err)
return err
}
}
if err := snaptree.Verify(root); err != nil {
log.Error("Failed to verify state", "root", root, "err", err)
return err
}
log.Info("Verified the state", "root", root)
return snapshot.CheckDanglingStorage(chaindb)
}
// checkDanglingStorage iterates the snap storage data, and verifies that all
// storage also has corresponding account data.
func checkDanglingStorage(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
return snapshot.CheckDanglingStorage(db)
}
// traverseState is a helper function used for pruning verification.
// Basically it just iterates the trie, ensure all nodes and associated
// contract codes are present.
func traverseState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chaindb := utils.MakeChainDatabase(ctx, stack, true)
defer chaindb.Close()
triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true, false)
defer triedb.Close()
headBlock := rawdb.ReadHeadBlock(chaindb)
if headBlock == nil {
log.Error("Failed to load head block")
return errors.New("no head block")
}
if ctx.NArg() > 1 {
log.Error("Too many arguments given")
return errors.New("too many arguments")
}
var (
root common.Hash
err error
)
if ctx.NArg() == 1 {
root, err = parseRoot(ctx.Args().First())
if err != nil {
log.Error("Failed to resolve state root", "err", err)
return err
}
log.Info("Start traversing the state", "root", root)
} else {
root = headBlock.Root()
log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
}
t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb)
if err != nil {
log.Error("Failed to open trie", "root", root, "err", err)
return err
}
var (
accounts int
slots int
codes int
lastReport time.Time
start = time.Now()
)
acctIt, err := t.NodeIterator(nil)
if err != nil {
log.Error("Failed to open iterator", "root", root, "err", err)
return err
}
accIter := trie.NewIterator(acctIt)
for accIter.Next() {
accounts += 1
var acc types.StateAccount
if err := rlp.DecodeBytes(accIter.Value, &acc); err != nil {
log.Error("Invalid account encountered during traversal", "err", err)
return err
}
if acc.Root != types.EmptyRootHash {
id := trie.StorageTrieID(root, common.BytesToHash(accIter.Key), acc.Root)
storageTrie, err := trie.NewStateTrie(id, triedb)
if err != nil {
log.Error("Failed to open storage trie", "root", acc.Root, "err", err)
return err
}
storageIt, err := storageTrie.NodeIterator(nil)
if err != nil {
log.Error("Failed to open storage iterator", "root", acc.Root, "err", err)
return err
}
storageIter := trie.NewIterator(storageIt)
for storageIter.Next() {
slots += 1
if time.Since(lastReport) > time.Second*8 {
log.Info("Traversing state", "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
lastReport = time.Now()
}
}
if storageIter.Err != nil {
log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Err)
return storageIter.Err
}
}
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
if !rawdb.HasCode(chaindb, common.BytesToHash(acc.CodeHash)) {
log.Error("Code is missing", "hash", common.BytesToHash(acc.CodeHash))
return errors.New("missing code")
}
codes += 1
}
if time.Since(lastReport) > time.Second*8 {
log.Info("Traversing state", "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
lastReport = time.Now()
}
}
if accIter.Err != nil {
log.Error("Failed to traverse state trie", "root", root, "err", accIter.Err)
return accIter.Err
}
log.Info("State is complete", "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
return nil
}
// traverseRawState is a helper function used for pruning verification.
// Basically it just iterates the trie, ensure all nodes and associated
// contract codes are present. It's basically identical to traverseState
// but it will check each trie node.
func traverseRawState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chaindb := utils.MakeChainDatabase(ctx, stack, true)
defer chaindb.Close()
triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true, false)
defer triedb.Close()
headBlock := rawdb.ReadHeadBlock(chaindb)
if headBlock == nil {
log.Error("Failed to load head block")
return errors.New("no head block")
}
if ctx.NArg() > 1 {
log.Error("Too many arguments given")
return errors.New("too many arguments")
}
var (
root common.Hash
err error
)
if ctx.NArg() == 1 {
root, err = parseRoot(ctx.Args().First())
if err != nil {
log.Error("Failed to resolve state root", "err", err)
return err
}
log.Info("Start traversing the state", "root", root)
} else {
root = headBlock.Root()
log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
}
t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb)
if err != nil {
log.Error("Failed to open trie", "root", root, "err", err)
return err
}
var (
nodes int
accounts int
slots int
codes int
lastReport time.Time
start = time.Now()
hasher = crypto.NewKeccakState()
got = make([]byte, 32)
)
accIter, err := t.NodeIterator(nil)
if err != nil {
log.Error("Failed to open iterator", "root", root, "err", err)
return err
}
reader, err := triedb.NodeReader(root)
if err != nil {
log.Error("State is non-existent", "root", root)
return nil
}
for accIter.Next(true) {
nodes += 1
node := accIter.Hash()
// Check the present for non-empty hash node(embedded node doesn't
// have their own hash).
if node != (common.Hash{}) {
blob, _ := reader.Node(common.Hash{}, accIter.Path(), node)
if len(blob) == 0 {
log.Error("Missing trie node(account)", "hash", node)
return errors.New("missing account")
}
hasher.Reset()
hasher.Write(blob)
hasher.Read(got)
if !bytes.Equal(got, node.Bytes()) {
log.Error("Invalid trie node(account)", "hash", node.Hex(), "value", blob)
return errors.New("invalid account node")
}
}
// If it's a leaf node, yes we are touching an account,
// dig into the storage trie further.
if accIter.Leaf() {
accounts += 1
var acc types.StateAccount
if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil {
log.Error("Invalid account encountered during traversal", "err", err)
return errors.New("invalid account")
}
if acc.Root != types.EmptyRootHash {
id := trie.StorageTrieID(root, common.BytesToHash(accIter.LeafKey()), acc.Root)
storageTrie, err := trie.NewStateTrie(id, triedb)
if err != nil {
log.Error("Failed to open storage trie", "root", acc.Root, "err", err)
return errors.New("missing storage trie")
}
storageIter, err := storageTrie.NodeIterator(nil)
if err != nil {
log.Error("Failed to open storage iterator", "root", acc.Root, "err", err)
return err
}
for storageIter.Next(true) {
nodes += 1
node := storageIter.Hash()
// Check the presence for non-empty hash node(embedded node doesn't
// have their own hash).
if node != (common.Hash{}) {
blob, _ := reader.Node(common.BytesToHash(accIter.LeafKey()), storageIter.Path(), node)
if len(blob) == 0 {
log.Error("Missing trie node(storage)", "hash", node)
return errors.New("missing storage")
}
hasher.Reset()
hasher.Write(blob)
hasher.Read(got)
if !bytes.Equal(got, node.Bytes()) {
log.Error("Invalid trie node(storage)", "hash", node.Hex(), "value", blob)
return errors.New("invalid storage node")
}
}
// Bump the counter if it's leaf node.
if storageIter.Leaf() {
slots += 1
}
if time.Since(lastReport) > time.Second*8 {
log.Info("Traversing state", "nodes", nodes, "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
lastReport = time.Now()
}
}
if storageIter.Error() != nil {
log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Error())
return storageIter.Error()
}
}
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
if !rawdb.HasCode(chaindb, common.BytesToHash(acc.CodeHash)) {
log.Error("Code is missing", "account", common.BytesToHash(accIter.LeafKey()))
return errors.New("missing code")
}
codes += 1
}
if time.Since(lastReport) > time.Second*8 {
log.Info("Traversing state", "nodes", nodes, "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
lastReport = time.Now()
}
}
}
if accIter.Error() != nil {
log.Error("Failed to traverse state trie", "root", root, "err", accIter.Error())
return accIter.Error()
}
log.Info("State is complete", "nodes", nodes, "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
return nil
}
func parseRoot(input string) (common.Hash, error) {
var h common.Hash
if err := h.UnmarshalText([]byte(input)); err != nil {
return h, err
}
return h, nil
}
func dumpState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
defer db.Close()
conf, root, err := parseDumpConfig(ctx, db)
if err != nil {
return err
}
triedb := utils.MakeTrieDatabase(ctx, db, false, true, false)
defer triedb.Close()
snapConfig := snapshot.Config{
CacheSize: 256,
Recovery: false,
NoBuild: true,
AsyncBuild: false,
}
snaptree, err := snapshot.New(snapConfig, db, triedb, root)
if err != nil {
return err
}
accIt, err := snaptree.AccountIterator(root, common.BytesToHash(conf.Start))
if err != nil {
return err
}
defer accIt.Release()
log.Info("Snapshot dumping started", "root", root)
var (
start = time.Now()
logged = time.Now()
accounts uint64
)
enc := json.NewEncoder(os.Stdout)
enc.Encode(struct {
Root common.Hash `json:"root"`
}{root})
for accIt.Next() {
account, err := types.FullAccount(accIt.Account())
if err != nil {
return err
}
da := &state.DumpAccount{
Balance: account.Balance.String(),
Nonce: account.Nonce,
Root: account.Root.Bytes(),
CodeHash: account.CodeHash,
AddressHash: accIt.Hash().Bytes(),
}
if !conf.SkipCode && !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash))
}
if !conf.SkipStorage {
da.Storage = make(map[common.Hash]string)
stIt, err := snaptree.StorageIterator(root, accIt.Hash(), common.Hash{})
if err != nil {
return err
}
for stIt.Next() {
da.Storage[stIt.Hash()] = common.Bytes2Hex(stIt.Slot())
}
}
enc.Encode(da)
accounts++
if time.Since(logged) > 8*time.Second {
log.Info("Snapshot dumping in progress", "at", accIt.Hash(), "accounts", accounts,
"elapsed", common.PrettyDuration(time.Since(start)))
logged = time.Now()
}
if conf.Max > 0 && accounts >= conf.Max {
break
}
}
log.Info("Snapshot dumping complete", "accounts", accounts,
"elapsed", common.PrettyDuration(time.Since(start)))
return nil
}
// snapshotExportPreimages dumps the preimage data to a flat file.
func snapshotExportPreimages(ctx *cli.Context) error {
if ctx.NArg() < 1 {
utils.Fatalf("This command requires an argument.")
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chaindb := utils.MakeChainDatabase(ctx, stack, true)
defer chaindb.Close()
triedb := utils.MakeTrieDatabase(ctx, chaindb, false, true, false)
defer triedb.Close()
var root common.Hash
if ctx.NArg() > 1 {
rootBytes := common.FromHex(ctx.Args().Get(1))
if len(rootBytes) != common.HashLength {
return fmt.Errorf("invalid hash: %s", ctx.Args().Get(1))
}
root = common.BytesToHash(rootBytes)
} else {
headBlock := rawdb.ReadHeadBlock(chaindb)
if headBlock == nil {
log.Error("Failed to load head block")
return errors.New("no head block")
}
root = headBlock.Root()
}
snapConfig := snapshot.Config{
CacheSize: 256,
Recovery: false,
NoBuild: true,
AsyncBuild: false,
}
snaptree, err := snapshot.New(snapConfig, chaindb, triedb, root)
if err != nil {
return err
}
return utils.ExportSnapshotPreimages(chaindb, snaptree, ctx.Args().First(), root)
}
// checkAccount iterates the snap data layers, and looks up the given account
// across all layers.
func checkAccount(ctx *cli.Context) error {
if ctx.NArg() != 1 {
return errors.New("need <address|hash> arg")
}
var (
hash common.Hash
addr common.Address
)
switch arg := ctx.Args().First(); len(arg) {
case 40, 42:
addr = common.HexToAddress(arg)
hash = crypto.Keccak256Hash(addr.Bytes())
case 64, 66:
hash = common.HexToHash(arg)
default:
return errors.New("malformed address or hash")
}
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chaindb := utils.MakeChainDatabase(ctx, stack, true)
defer chaindb.Close()
start := time.Now()
log.Info("Checking difflayer journal", "address", addr, "hash", hash)
if err := snapshot.CheckJournalAccount(chaindb, hash); err != nil {
return err
}
log.Info("Checked the snapshot journalled storage", "time", common.PrettyDuration(time.Since(start)))
return nil
}

BIN
cmd/aiigo/testdata/blockchain.blocks vendored Normal file

Binary file not shown.

25
cmd/aiigo/testdata/clique.json vendored Normal file
View file

@ -0,0 +1,25 @@
{
"config": {
"chainId": 15,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"terminalTotalDifficulty": 0,
"clique": {
"period": 5,
"epoch": 30000
}
},
"difficulty": "1",
"gasLimit": "8000000",
"extradata": "0x000000000000000000000000000000000000000000000000000000000000000002f0d131f1f97aef08aec6e3291b957d9efe71050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"alloc": {
"02f0d131f1f97aef08aec6e3291b957d9efe7105": {
"balance": "300000"
}
}
}

1
cmd/aiigo/testdata/empty.js vendored Normal file
View file

@ -0,0 +1 @@

6
cmd/aiigo/testdata/guswallet.json vendored Normal file
View file

@ -0,0 +1,6 @@
{
"encseed": "26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba",
"ethaddr": "d4584b5f6229b7be90727b0fc8c6b91bb427821f",
"email": "gustav.simonsson@gmail.com",
"btcaddr": "1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx"
}

1
cmd/aiigo/testdata/key.prv vendored Normal file
View file

@ -0,0 +1 @@
48aa455c373ec5ce7fefb0e54f44a215decdc85b9047bc4d09801e038909bdbe

View file

@ -0,0 +1,52 @@
{"t":"2023-11-22T15:42:00.407963+08:00","lvl":"info","msg":"big.Int","111,222,333,444,555,678,999":"111222333444555678999"}
{"t":"2023-11-22T15:42:00.408084+08:00","lvl":"info","msg":"-big.Int","-111,222,333,444,555,678,999":"-111222333444555678999"}
{"t":"2023-11-22T15:42:00.408092+08:00","lvl":"info","msg":"big.Int","11,122,233,344,455,567,899,900":"11122233344455567899900"}
{"t":"2023-11-22T15:42:00.408097+08:00","lvl":"info","msg":"-big.Int","-11,122,233,344,455,567,899,900":"-11122233344455567899900"}
{"t":"2023-11-22T15:42:00.408127+08:00","lvl":"info","msg":"uint256","111,222,333,444,555,678,999":"111222333444555678999"}
{"t":"2023-11-22T15:42:00.408133+08:00","lvl":"info","msg":"uint256","11,122,233,344,455,567,899,900":"11122233344455567899900"}
{"t":"2023-11-22T15:42:00.408137+08:00","lvl":"info","msg":"int64","1,000,000":1000000}
{"t":"2023-11-22T15:42:00.408145+08:00","lvl":"info","msg":"int64","-1,000,000":-1000000}
{"t":"2023-11-22T15:42:00.408149+08:00","lvl":"info","msg":"int64","9,223,372,036,854,775,807":9223372036854775807}
{"t":"2023-11-22T15:42:00.408153+08:00","lvl":"info","msg":"int64","-9,223,372,036,854,775,808":-9223372036854775808}
{"t":"2023-11-22T15:42:00.408156+08:00","lvl":"info","msg":"uint64","1,000,000":1000000}
{"t":"2023-11-22T15:42:00.40816+08:00","lvl":"info","msg":"uint64","18,446,744,073,709,551,615":18446744073709551615}
{"t":"2023-11-22T15:42:00.408164+08:00","lvl":"info","msg":"Special chars in value","key":"special \r\n\t chars"}
{"t":"2023-11-22T15:42:00.408167+08:00","lvl":"info","msg":"Special chars in key","special \n\t chars":"value"}
{"t":"2023-11-22T15:42:00.408171+08:00","lvl":"info","msg":"nospace","nospace":"nospace"}
{"t":"2023-11-22T15:42:00.408174+08:00","lvl":"info","msg":"with space","with nospace":"with nospace"}
{"t":"2023-11-22T15:42:00.408178+08:00","lvl":"info","msg":"Bash escapes in value","key":"\u001b[1G\u001b[K\u001b[1A"}
{"t":"2023-11-22T15:42:00.408182+08:00","lvl":"info","msg":"Bash escapes in key","\u001b[1G\u001b[K\u001b[1A":"value"}
{"t":"2023-11-22T15:42:00.408186+08:00","lvl":"info","msg":"Bash escapes in message \u001b[1G\u001b[K\u001b[1A end","key":"value"}
{"t":"2023-11-22T15:42:00.408194+08:00","lvl":"info","msg":"\u001b[35mColored\u001b[0m[","\u001b[35mColored\u001b[0m[":"\u001b[35mColored\u001b[0m["}
{"t":"2023-11-22T15:42:00.408197+08:00","lvl":"info","msg":"an error message with quotes","error":"this is an 'error'"}
{"t":"2023-11-22T15:42:00.408202+08:00","lvl":"info","msg":"Custom Stringer value","2562047h47m16.854s":"2562047h47m16.854s"}
{"t":"2023-11-22T15:42:00.408208+08:00","lvl":"info","msg":"a custom stringer that emits quoted text","output":"output with 'quotes'"}
{"t":"2023-11-22T15:42:00.408219+08:00","lvl":"info","msg":"A message with wonky 💩 characters"}
{"t":"2023-11-22T15:42:00.408222+08:00","lvl":"info","msg":"A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩"}
{"t":"2023-11-22T15:42:00.408226+08:00","lvl":"info","msg":"A multiline message \nLALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above"}
{"t":"2023-11-22T15:42:00.408229+08:00","lvl":"info","msg":"boolean","true":true,"false":false}
{"t":"2023-11-22T15:42:00.408234+08:00","lvl":"info","msg":"repeated-key 1","foo":"alpha","foo":"beta"}
{"t":"2023-11-22T15:42:00.408237+08:00","lvl":"info","msg":"repeated-key 2","xx":"short","xx":"longer"}
{"t":"2023-11-22T15:42:00.408241+08:00","lvl":"info","msg":"log at level info"}
{"t":"2023-11-22T15:42:00.408244+08:00","lvl":"warn","msg":"log at level warn"}
{"t":"2023-11-22T15:42:00.408247+08:00","lvl":"error","msg":"log at level error"}
{"t":"2023-11-22T15:42:00.408251+08:00","lvl":"info","msg":"test","bar":"short","a":"aligned left"}
{"t":"2023-11-22T15:42:00.408254+08:00","lvl":"info","msg":"test","bar":"a long message","a":1}
{"t":"2023-11-22T15:42:00.408258+08:00","lvl":"info","msg":"test","bar":"short","a":"aligned right"}
{"t":"2023-11-22T15:42:00.408261+08:00","lvl":"info","msg":"The following logs should align so that the key-fields make 5 columns"}
{"t":"2023-11-22T15:42:00.408275+08:00","lvl":"info","msg":"Inserted known block","number":1012,"hash":"0x0000000000000000000000000000000000000000000000000000000000001234","txs":200,"gas":1123123,"other":"first"}
{"t":"2023-11-22T15:42:00.408281+08:00","lvl":"info","msg":"Inserted new block","number":1,"hash":"0x0000000000000000000000000000000000000000000000000000000000001235","txs":2,"gas":1123,"other":"second"}
{"t":"2023-11-22T15:42:00.408287+08:00","lvl":"info","msg":"Inserted known block","number":99,"hash":"0x0000000000000000000000000000000000000000000000000000000000012322","txs":10,"gas":1,"other":"third"}
{"t":"2023-11-22T15:42:00.408296+08:00","lvl":"warn","msg":"Inserted known block","number":1012,"hash":"0x0000000000000000000000000000000000000000000000000000000000001234","txs":200,"gas":99,"other":"fourth"}
{"t":"2023-11-22T15:42:00.4083+08:00","lvl":"info","msg":"(*big.Int)(nil)","<nil>":"<nil>"}
{"t":"2023-11-22T15:42:00.408303+08:00","lvl":"info","msg":"(*uint256.Int)(nil)","<nil>":"<nil>"}
{"t":"2023-11-22T15:42:00.408311+08:00","lvl":"info","msg":"(fmt.Stringer)(nil)","res":null}
{"t":"2023-11-22T15:42:00.408318+08:00","lvl":"info","msg":"nil-concrete-stringer","res":"<nil>"}
{"t":"2023-11-22T15:42:00.408322+08:00","lvl":"info","msg":"error(nil) ","res":null}
{"t":"2023-11-22T15:42:00.408326+08:00","lvl":"info","msg":"nil-concrete-error","res":""}
{"t":"2023-11-22T15:42:00.408334+08:00","lvl":"info","msg":"nil-custom-struct","res":null}
{"t":"2023-11-22T15:42:00.40835+08:00","lvl":"info","msg":"raw nil","res":null}
{"t":"2023-11-22T15:42:00.408354+08:00","lvl":"info","msg":"(*uint64)(nil)","res":null}
{"t":"2023-11-22T15:42:00.408361+08:00","lvl":"info","msg":"Using keys 't', 'lvl', 'time', 'level' and 'msg'","t":"t","time":"time","lvl":"lvl","level":"level","msg":"msg"}
{"t":"2023-11-29T15:13:00.195655931+01:00","lvl":"info","msg":"Odd pair (1 attr)","key":null,"LOG_ERROR":"Normalized odd number of arguments by adding nil"}
{"t":"2023-11-29T15:13:00.195681832+01:00","lvl":"info","msg":"Odd pair (3 attr)","key":"value","key2":null,"LOG_ERROR":"Normalized odd number of arguments by adding nil"}

View file

@ -0,0 +1,52 @@
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=big.Int 111,222,333,444,555,678,999=111222333444555678999
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=-big.Int -111,222,333,444,555,678,999=-111222333444555678999
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=big.Int 11,122,233,344,455,567,899,900=11122233344455567899900
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=-big.Int -11,122,233,344,455,567,899,900=-11122233344455567899900
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=uint256 111,222,333,444,555,678,999=111222333444555678999
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=uint256 11,122,233,344,455,567,899,900=11122233344455567899900
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=int64 1,000,000=1000000
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=int64 -1,000,000=-1000000
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=int64 9,223,372,036,854,775,807=9223372036854775807
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=int64 -9,223,372,036,854,775,808=-9223372036854775808
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=uint64 1,000,000=1000000
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=uint64 18,446,744,073,709,551,615=18446744073709551615
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Special chars in value" key="special \r\n\t chars"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Special chars in key" "special \n\t chars"=value
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=nospace nospace=nospace
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="with space" "with nospace"="with nospace"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Bash escapes in value" key="\x1b[1G\x1b[K\x1b[1A"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Bash escapes in key" "\x1b[1G\x1b[K\x1b[1A"=value
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Bash escapes in message \x1b[1G\x1b[K\x1b[1A end" key=value
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="\x1b[35mColored\x1b[0m[" "\x1b[35mColored\x1b[0m["="\x1b[35mColored\x1b[0m["
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="an error message with quotes" error="this is an 'error'"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Custom Stringer value" 2562047h47m16.854s=2562047h47m16.854s
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="a custom stringer that emits quoted text" output="output with 'quotes'"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="A message with wonky 💩 characters"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="A multiline message \nLALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=boolean true=true false=false
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="repeated-key 1" foo=alpha foo=beta
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="repeated-key 2" xx=short xx=longer
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="log at level info"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=warn msg="log at level warn"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=error msg="log at level error"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar=short a="aligned left"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar="a long message" a=1
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar=short a="aligned right"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="The following logs should align so that the key-fields make 5 columns"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Inserted known block" number=1012 hash=0x0000000000000000000000000000000000000000000000000000000000001234 txs=200 gas=1123123 other=first
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Inserted new block" number=1 hash=0x0000000000000000000000000000000000000000000000000000000000001235 txs=2 gas=1123 other=second
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Inserted known block" number=99 hash=0x0000000000000000000000000000000000000000000000000000000000012322 txs=10 gas=1 other=third
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=warn msg="Inserted known block" number=1012 hash=0x0000000000000000000000000000000000000000000000000000000000001234 txs=200 gas=99 other=fourth
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=(*big.Int)(nil) <nil>=<nil>
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=(*uint256.Int)(nil) <nil>=<nil>
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=(fmt.Stringer)(nil) res=<nil>
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=nil-concrete-stringer res=<nil>
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="error(nil) " res=<nil>
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=nil-concrete-error res=""
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=nil-custom-struct res=<nil>
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="raw nil" res=<nil>
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=(*uint64)(nil) res=<nil>
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Using keys 't', 'lvl', 'time', 'level' and 'msg'" t=t time=time lvl=lvl level=level msg=msg
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Odd pair (1 attr)" key=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Odd pair (3 attr)" key=value key2=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"

View file

@ -0,0 +1,53 @@
INFO [xx-xx|xx:xx:xx.xxx] big.Int 111,222,333,444,555,678,999=111,222,333,444,555,678,999
INFO [xx-xx|xx:xx:xx.xxx] -big.Int -111,222,333,444,555,678,999=-111,222,333,444,555,678,999
INFO [xx-xx|xx:xx:xx.xxx] big.Int 11,122,233,344,455,567,899,900=11,122,233,344,455,567,899,900
INFO [xx-xx|xx:xx:xx.xxx] -big.Int -11,122,233,344,455,567,899,900=-11,122,233,344,455,567,899,900
INFO [xx-xx|xx:xx:xx.xxx] uint256 111,222,333,444,555,678,999=111,222,333,444,555,678,999
INFO [xx-xx|xx:xx:xx.xxx] uint256 11,122,233,344,455,567,899,900=11,122,233,344,455,567,899,900
INFO [xx-xx|xx:xx:xx.xxx] int64 1,000,000=1,000,000
INFO [xx-xx|xx:xx:xx.xxx] int64 -1,000,000=-1,000,000
INFO [xx-xx|xx:xx:xx.xxx] int64 9,223,372,036,854,775,807=9,223,372,036,854,775,807
INFO [xx-xx|xx:xx:xx.xxx] int64 -9,223,372,036,854,775,808=-9,223,372,036,854,775,808
INFO [xx-xx|xx:xx:xx.xxx] uint64 1,000,000=1,000,000
INFO [xx-xx|xx:xx:xx.xxx] uint64 18,446,744,073,709,551,615=18,446,744,073,709,551,615
INFO [xx-xx|xx:xx:xx.xxx] Special chars in value key="special \r\n\t chars"
INFO [xx-xx|xx:xx:xx.xxx] Special chars in key "special \n\t chars"=value
INFO [xx-xx|xx:xx:xx.xxx] nospace nospace=nospace
INFO [xx-xx|xx:xx:xx.xxx] with space "with nospace"="with nospace"
INFO [xx-xx|xx:xx:xx.xxx] Bash escapes in value key="\x1b[1G\x1b[K\x1b[1A"
INFO [xx-xx|xx:xx:xx.xxx] Bash escapes in key "\x1b[1G\x1b[K\x1b[1A"=value
INFO [xx-xx|xx:xx:xx.xxx] "Bash escapes in message \x1b[1G\x1b[K\x1b[1A end" key=value
INFO [xx-xx|xx:xx:xx.xxx] "\x1b[35mColored\x1b[0m[" "\x1b[35mColored\x1b[0m["="\x1b[35mColored\x1b[0m["
INFO [xx-xx|xx:xx:xx.xxx] an error message with quotes error="this is an 'error'"
INFO [xx-xx|xx:xx:xx.xxx] Custom Stringer value 2562047h47m16.854s=2562047h47m16.854s
INFO [xx-xx|xx:xx:xx.xxx] a custom stringer that emits quoted text output="output with 'quotes'"
INFO [xx-xx|xx:xx:xx.xxx] "A message with wonky 💩 characters"
INFO [xx-xx|xx:xx:xx.xxx] "A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩"
INFO [xx-xx|xx:xx:xx.xxx] A multiline message
LALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above
INFO [xx-xx|xx:xx:xx.xxx] boolean true=true false=false
INFO [xx-xx|xx:xx:xx.xxx] repeated-key 1 foo=alpha foo=beta
INFO [xx-xx|xx:xx:xx.xxx] repeated-key 2 xx=short xx=longer
INFO [xx-xx|xx:xx:xx.xxx] log at level info
WARN [xx-xx|xx:xx:xx.xxx] log at level warn
ERROR[xx-xx|xx:xx:xx.xxx] log at level error
INFO [xx-xx|xx:xx:xx.xxx] test bar=short a="aligned left"
INFO [xx-xx|xx:xx:xx.xxx] test bar="a long message" a=1
INFO [xx-xx|xx:xx:xx.xxx] test bar=short a="aligned right"
INFO [xx-xx|xx:xx:xx.xxx] The following logs should align so that the key-fields make 5 columns
INFO [xx-xx|xx:xx:xx.xxx] Inserted known block number=1012 hash=000000..001234 txs=200 gas=1,123,123 other=first
INFO [xx-xx|xx:xx:xx.xxx] Inserted new block number=1 hash=000000..001235 txs=2 gas=1123 other=second
INFO [xx-xx|xx:xx:xx.xxx] Inserted known block number=99 hash=000000..012322 txs=10 gas=1 other=third
WARN [xx-xx|xx:xx:xx.xxx] Inserted known block number=1012 hash=000000..001234 txs=200 gas=99 other=fourth
INFO [xx-xx|xx:xx:xx.xxx] (*big.Int)(nil) <nil>=<nil>
INFO [xx-xx|xx:xx:xx.xxx] (*uint256.Int)(nil) <nil>=<nil>
INFO [xx-xx|xx:xx:xx.xxx] (fmt.Stringer)(nil) res=<nil>
INFO [xx-xx|xx:xx:xx.xxx] nil-concrete-stringer res=<nil>
INFO [xx-xx|xx:xx:xx.xxx] error(nil) res=<nil>
INFO [xx-xx|xx:xx:xx.xxx] nil-concrete-error res=
INFO [xx-xx|xx:xx:xx.xxx] nil-custom-struct res=<nil>
INFO [xx-xx|xx:xx:xx.xxx] raw nil res=<nil>
INFO [xx-xx|xx:xx:xx.xxx] (*uint64)(nil) res=<nil>
INFO [xx-xx|xx:xx:xx.xxx] Using keys 't', 'lvl', 'time', 'level' and 'msg' t=t time=time lvl=lvl level=level msg=msg
INFO [xx-xx|xx:xx:xx.xxx] Odd pair (1 attr) key=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"
INFO [xx-xx|xx:xx:xx.xxx] Odd pair (3 attr) key=value key2=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"

1
cmd/aiigo/testdata/password.txt vendored Normal file
View file

@ -0,0 +1 @@
foobar

3
cmd/aiigo/testdata/passwords.txt vendored Normal file
View file

@ -0,0 +1,3 @@
foobar
foobar
foobar

61
cmd/aiigo/testdata/vcheck/data.json vendored Normal file
View file

@ -0,0 +1,61 @@
[
{
"name": "CorruptedDAG",
"uid": "aiigo-2020-01",
"summary": "Mining nodes will generate erroneous PoW on epochs > `385`.",
"description": "A mining flaw could cause miners to erroneously calculate PoW, due to an index overflow, if DAG size is exceeding the maximum 32 bit unsigned value.\n\nThis occurred on the ETC chain on 2020-11-06. This is likely to trigger for ETH mainnet around block `11550000`/epoch `385`, slated to occur early January 2021.\n\nThis issue is relevant only for miners, non-mining nodes are unaffected, since non-mining nodes use a smaller verification cache instead of a full DAG.",
"links": [
"https://github.com/ethereum/go-ethereum/pull/21793",
"https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://github.com/ethereum/go-ethereum/commit/567d41d9363706b4b13ce0903804e8acf214af49"
],
"introduced": "v1.6.0",
"fixed": "v1.9.24",
"published": "2020-11-12",
"severity": "Medium",
"check": "aiigo\\/v1\\.(6|7|8)\\..*|aiigo\\/v1\\.9\\.2(1|2|3)-.*"
},
{
"name": "GoCrash",
"uid": "aiigo-2020-02",
"summary": "A denial-of-service issue can be used to crash aiigo nodes during block processing, due to an underlying bug in Go (CVE-2020-28362) versions < `1.15.5`, or `<1.14.12`",
"description": "The DoS issue can be used to crash all aiigo nodes during block processing, the effects of which would be that a major part of the Ethereum network went offline.\n\nOutside of Go-Ethereum, the issue is most likely relevant for all forks of aiigo (such as Turboaiigo or ETCs core-aiigo) which is built with versions of Go which contains the vulnerability.",
"links": [
"https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://groups.google.com/g/golang-announce/c/NpBGTTmKzpM",
"https://github.com/golang/go/issues/42552"
],
"fixed": "v1.9.24",
"published": "2020-11-12",
"severity": "Critical",
"check": "aiigo.*\\/go1\\.(11(.*)|12(.*)|13(.*)|14|14\\.(\\d|10|11|)|15|15\\.[0-4])$"
},
{
"name": "ShallowCopy",
"uid": "aiigo-2020-03",
"summary": "A consensus flaw in aiigo, related to `datacopy` precompile",
"description": "aiigo erroneously performed a 'shallow' copy when the precompiled `datacopy` (at `0x00...04`) was invoked. An attacker could deploy a contract that uses the shallow copy to corrupt the contents of the `RETURNDATA`, thus causing a consensus failure.",
"links": [
"https://blog.ethereum.org/2020/11/12/aiigo_security_release/"
],
"introduced": "v1.9.7",
"fixed": "v1.9.17",
"published": "2020-11-12",
"severity": "Critical",
"check": "aiigo\\/v1\\.9\\.(7|8|9|10|11|12|13|14|15|16).*$"
},
{
"name": "aiigoCrash",
"uid": "aiigo-2020-04",
"summary": "A denial-of-service issue can be used to crash aiigo nodes during block processing",
"description": "Full details to be disclosed at a later date",
"links": [
"https://blog.ethereum.org/2020/11/12/aiigo_security_release/"
],
"introduced": "v1.9.16",
"fixed": "v1.9.18",
"published": "2020-11-12",
"severity": "Critical",
"check": "aiigo\\/v1\\.9.(16|17).*$"
}
]

View file

@ -0,0 +1,4 @@
untrusted comment: signature from minisign secret key
RUQkliYstQBOKLK05Sy5f3bVRMBqJT26ABo6Vbp3BNJAVjejoqYCu4GWE/+7qcDfHBqYIniDCbFIUvYEnOHxV6vZ93wO1xJWDQw=
trusted comment: timestamp:1693986492 file:data.json hashed
6Fdw2H+W1ZXK7QXSF77Z5AWC7+AEFAfDmTSxNGylU5HLT1AuSJQmxslj+VjtUBamYCvOuET7plbXza942AlWDw==

View file

@ -0,0 +1,4 @@
untrusted comment: signature from minisign secret key
RWQkliYstQBOKFQFQTjmCd6TPw07VZyWFSB3v4+1BM1kv8eHLE5FDy2OkPEqtdaL53xftlrHoJQie0uCcovdlSV8kpyxiLrxEQ0=
trusted comment: timestamp:1605618622 file:vulnerabilities.json
osAPs4QPdDkmiWQxqeMIzYv/b+ZGxJ+19Sbrk1Cpq4t2gHBT+lqFtwL3OCzKWWyjGRTmHfsVGBYpzEdPRQ0/BQ==

View file

@ -0,0 +1,4 @@
untrusted comment: Here's a comment
RWQkliYstQBOKFQFQTjmCd6TPw07VZyWFSB3v4+1BM1kv8eHLE5FDy2OkPEqtdaL53xftlrHoJQie0uCcovdlSV8kpyxiLrxEQ0=
trusted comment: Here's a trusted comment
3CnkIuz9MEDa7uNyGZAbKZhuirwfiqm7E1uQHrd2SiO4Y8+Akw9vs052AyKw0s5nhbYHCZE2IMQdHNjKwxEGAQ==

View file

@ -0,0 +1,4 @@
untrusted comment: One more (untrusted) comment
RWQkliYstQBOKFQFQTjmCd6TPw07VZyWFSB3v4+1BM1kv8eHLE5FDy2OkPEqtdaL53xftlrHoJQie0uCcovdlSV8kpyxiLrxEQ0=
trusted comment: Here's a trusted comment
3CnkIuz9MEDa7uNyGZAbKZhuirwfiqm7E1uQHrd2SiO4Y8+Akw9vs052AyKw0s5nhbYHCZE2IMQdHNjKwxEGAQ==

View file

@ -0,0 +1,2 @@
untrusted comment: minisign public key 284E00B52C269624
RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp

View file

@ -0,0 +1,2 @@
untrusted comment: minisign encrypted secret key
RWRTY0Iyz8kmPMKrqk6DCtlO9a33akKiaOQG1aLolqDxs52qvPoAAAACAAAAAAAAAEAAAAAArEiggdvyn6+WzTprirLtgiYQoU+ihz/HyGgjhuF+Pz2ddMduyCO+xjCHeq+vgVVW039fbsI8hW6LRGJZLBKV5/jdxCXAVVQE7qTQ6xpEdO0z8Z731/pV1hlspQXG2PNd16NMtwd9dWw=

View file

@ -0,0 +1,2 @@
untrusted comment: verify with ./signifykey.pub
RWSKLNhZb0KdAbhRUhW2LQZXdnwttu2SYhM9EuC4mMgOJB85h7/YIPupf8/ldTs4N8e9Y/fhgdY40q5LQpt5IFC62fq0v8U1/w8=

View file

@ -0,0 +1,2 @@
untrusted comment: signify public key
RWSKLNhZb0KdATtRT7mZC/bybI3t3+Hv/O2i3ye04Dq9fnT9slpZ1a2/

View file

@ -0,0 +1,2 @@
untrusted comment: signify secret key
RWRCSwAAACpLQDLawSQCtI7eAVIvaiHzjTsTyJsfV5aKLNhZb0KdAWeICXJGa93/bHAcsY6jUh9I8RdEcDWEoGxmaXZC+IdVBPxDpkix9fBRGEUdKWHi3dOfqME0YRzErWI5AVg3cRw=

View file

@ -0,0 +1,4 @@
untrusted comment: signature from minisign secret key
RWQkliYstQBOKFQFQTjmCd6TPw07VZyWFSB3v4+1BM1kv8eHLE5FDy2OkPEqtdaL53xftlrHoJQie0uCcovdlSV8kpyxiLrxEQ0=
trusted comment: timestamp:1605618622 file:vulnerabilities.json
osAPs4QPdDkmiWQxqeMIzYv/b+ZGxJ+19Sbrk1Cpq4t2gHBT+lqFtwL3OCzKWWyjGRTmHfsVGBYpzEdPRQ0/BQ==

View file

@ -0,0 +1,4 @@
untrusted comment: Here's a comment
RWQkliYstQBOKFQFQTjmCd6TPw07VZyWFSB3v4+1BM1kv8eHLE5FDy2OkPEqtdaL53xftlrHoJQie0uCcovdlSV8kpyxiLrxEQ0=
trusted comment: Here's a trusted comment
3CnkIuz9MEDa7uNyGZAbKZhuirwfiqm7E1uQHrd2SiO4Y8+Akw9vs052AyKw0s5nhbYHCZE2IMQdHNjKwxEGAQ==

View file

@ -0,0 +1,4 @@
untrusted comment: One more (untrusted) comment
RWQkliYstQBOKFQFQTjmCd6TPw07VZyWFSB3v4+1BM1kv8eHLE5FDy2OkPEqtdaL53xftlrHoJQie0uCcovdlSV8kpyxiLrxEQ0=
trusted comment: Here's a trusted comment
3CnkIuz9MEDa7uNyGZAbKZhuirwfiqm7E1uQHrd2SiO4Y8+Akw9vs052AyKw0s5nhbYHCZE2IMQdHNjKwxEGAQ==

View file

@ -0,0 +1,202 @@
[
{
"name": "CorruptedDAG",
"uid": "aiigo-2020-01",
"summary": "Mining nodes will generate erroneous PoW on epochs > `385`.",
"description": "A mining flaw could cause miners to erroneously calculate PoW, due to an index overflow, if DAG size is exceeding the maximum 32 bit unsigned value.\n\nThis occurred on the ETC chain on 2020-11-06. This is likely to trigger for ETH mainnet around block `11550000`/epoch `385`, slated to occur early January 2021.\n\nThis issue is relevant only for miners, non-mining nodes are unaffected, since non-mining nodes use a smaller verification cache instead of a full DAG.",
"links": [
"https://github.com/ethereum/go-ethereum/pull/21793",
"https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://github.com/ethereum/go-ethereum/commit/567d41d9363706b4b13ce0903804e8acf214af49",
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-v592-xf75-856p"
],
"introduced": "v1.6.0",
"fixed": "v1.9.24",
"published": "2020-11-12",
"severity": "Medium",
"CVE": "CVE-2020-26240",
"check": "aiigo\\/v1\\.(6|7|8)\\..*|aiigo\\/v1\\.9\\.\\d-.*|aiigo\\/v1\\.9\\.1.*|aiigo\\/v1\\.9\\.2(0|1|2|3)-.*"
},
{
"name": "Denial of service due to Go CVE-2020-28362",
"uid": "aiigo-2020-02",
"summary": "A denial-of-service issue can be used to crash aiigo nodes during block processing, due to an underlying bug in Go (CVE-2020-28362) versions < `1.15.5`, or `<1.14.12`",
"description": "The DoS issue can be used to crash all aiigo nodes during block processing, the effects of which would be that a major part of the Ethereum network went offline.\n\nOutside of Go-Ethereum, the issue is most likely relevant for all forks of aiigo (such as Turboaiigo or ETCs core-aiigo) which is built with versions of Go which contains the vulnerability.",
"links": [
"https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://groups.google.com/g/golang-announce/c/NpBGTTmKzpM",
"https://github.com/golang/go/issues/42552",
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-m6gx-rhvj-fh52"
],
"introduced": "v0.0.0",
"fixed": "v1.9.24",
"published": "2020-11-12",
"severity": "Critical",
"CVE": "CVE-2020-28362",
"check": "aiigo.*\\/go1\\.(11(.*)|12(.*)|13(.*)|14|14\\.(\\d|10|11|)|15|15\\.[0-4])$"
},
{
"name": "ShallowCopy",
"uid": "aiigo-2020-03",
"summary": "A consensus flaw in aiigo, related to `datacopy` precompile",
"description": "aiigo erroneously performed a 'shallow' copy when the precompiled `datacopy` (at `0x00...04`) was invoked. An attacker could deploy a contract that uses the shallow copy to corrupt the contents of the `RETURNDATA`, thus causing a consensus failure.",
"links": [
"https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-69v6-xc2j-r2jf"
],
"introduced": "v1.9.7",
"fixed": "v1.9.17",
"published": "2020-11-12",
"severity": "Critical",
"CVE": "CVE-2020-26241",
"check": "aiigo\\/v1\\.9\\.(7|8|9|10|11|12|13|14|15|16).*$"
},
{
"name": "aiigo DoS via MULMOD",
"uid": "aiigo-2020-04",
"summary": "A denial-of-service issue can be used to crash aiigo nodes during block processing",
"description": "Affected versions suffer from a vulnerability which can be exploited through the `MULMOD` operation, by specifying a modulo of `0`: `mulmod(a,b,0)`, causing a `panic` in the underlying library. \nThe crash was in the `uint256` library, where a buffer [underflowed](https://github.com/holiman/uint256/blob/4ce82e695c10ddad57215bdbeafb68b8c5df2c30/uint256.go#L442).\n\n\tif `d == 0`, `dLen` remains `0`\n\nand https://github.com/holiman/uint256/blob/4ce82e695c10ddad57215bdbeafb68b8c5df2c30/uint256.go#L451 will try to access index `[-1]`.\n\nThe `uint256` library was first merged in this [commit](https://github.com/ethereum/go-ethereum/commit/cf6674539c589f80031f3371a71c6a80addbe454), on 2020-06-08. \nExploiting this vulnerabilty would cause all vulnerable nodes to drop off the network. \n\nThe issue was brought to our attention through a [bug report](https://github.com/ethereum/go-ethereum/issues/21367), showing a `panic` occurring on sync from genesis on the Ropsten network.\n \nIt was estimated that the least obvious way to fix this would be to merge the fix into `uint256`, make a new release of that library and then update the aiigo-dependency.\n",
"links": [
"https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-jm5c-rv3w-w83m",
"https://github.com/holiman/uint256/releases/tag/v1.1.1",
"https://github.com/holiman/uint256/pull/80",
"https://github.com/ethereum/go-ethereum/pull/21368"
],
"introduced": "v1.9.16",
"fixed": "v1.9.18",
"published": "2020-11-12",
"severity": "Critical",
"CVE": "CVE-2020-26242",
"check": "aiigo\\/v1\\.9.(16|17).*$"
},
{
"name": "LES Server DoS via GetProofsV2",
"uid": "aiigo-2020-05",
"summary": "A DoS vulnerability can make a LES server crash.",
"description": "A DoS vulnerability can make a LES server crash via malicious GetProofsV2 request from a connected LES client.\n\nThe vulnerability was patched in #21896.\n\nThis vulnerability only concern users explicitly running aiigo as a light server",
"links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-r33q-22hv-j29q",
"https://github.com/ethereum/go-ethereum/pull/21896"
],
"introduced": "v1.8.0",
"fixed": "v1.9.25",
"published": "2020-12-10",
"severity": "Medium",
"CVE": "CVE-2020-26264",
"check": "(aiigo\\/v1\\.8\\.*)|(aiigo\\/v1\\.9\\.\\d-.*)|(aiigo\\/v1\\.9\\.1\\d-.*)|(aiigo\\/v1\\.9\\.(20|21|22|23|24)-.*)$"
},
{
"name": "SELFDESTRUCT-recreate consensus flaw",
"uid": "aiigo-2020-06",
"introduced": "v1.9.4",
"fixed": "v1.9.20",
"summary": "A consensus-vulnerability in aiigo could cause a chain split, where vulnerable versions refuse to accept the canonical chain.",
"description": "A flaw was repoted at 2020-08-11 by John Youngseok Yang (Software Platform Lab), where a particular sequence of transactions could cause a consensus failure.\n\n- Tx 1:\n - `sender` invokes `caller`.\n - `caller` invokes `0xaa`. `0xaa` has 3 wei, does a self-destruct-to-self\n - `caller` does a `1 wei` -call to `0xaa`, who thereby has 1 wei (the code in `0xaa` still executed, since the tx is still ongoing, but doesn't redo the selfdestruct, it takes a different path if callvalue is non-zero)\n\n-Tx 2:\n - `sender` does a 5-wei call to 0xaa. No exec (since no code). \n\nIn aiigo, the result would be that `0xaa` had `6 wei`, whereas OE reported (correctly) `5` wei. Furthermore, in aiigo, if the second tx was not executed, the `0xaa` would be destructed, resulting in `0 wei`. Thus obviously wrong. \n\nIt was determined that the root cause was this [commit](https://github.com/ethereum/go-ethereum/commit/223b950944f494a5b4e0957fd9f92c48b09037ad) from [this PR](https://github.com/ethereum/go-ethereum/pull/19953). The semantics of `createObject` was subtly changd, into returning a non-nil object (with `deleted=true`) where it previously did not if the account had been destructed. This return value caused the new object to inherit the old `balance`.\n",
"links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4"
],
"published": "2020-12-10",
"severity": "High",
"CVE": "CVE-2020-26265",
"check": "(aiigo\\/v1\\.9\\.(4|5|6|7|8|9)-.*)|(aiigo\\/v1\\.9\\.1\\d-.*)$"
},
{
"name": "Not ready for London upgrade",
"uid": "aiigo-2021-01",
"summary": "The client is not ready for the 'London' technical upgrade, and will deviate from the canonical chain when the London upgrade occurs (at block '12965000' around August 4, 2021.",
"description": "At (or around) August 4, Ethereum will undergo a technical upgrade called 'London'. Clients not upgraded will fail to progress on the canonical chain.",
"links": [
"https://github.com/ethereum/eth1.0-specs/blob/master/network-upgrades/mainnet-upgrades/london.md",
"https://notes.ethereum.org/@timbeiko/ropsten-postmortem"
],
"introduced": "v1.10.1",
"fixed": "v1.10.6",
"published": "2021-07-22",
"severity": "High",
"check": "(aiigo\\/v1\\.10\\.(1|2|3|4|5)-.*)$"
},
{
"name": "RETURNDATA corruption via datacopy",
"uid": "aiigo-2021-02",
"summary": "A consensus-flaw in the aiigo EVM could cause a node to deviate from the canonical chain.",
"description": "A memory-corruption bug within the EVM can cause a consensus error, where vulnerable nodes obtain a different `stateRoot` when processing a maliciously crafted transaction. This, in turn, would lead to the chain being split: mainnet splitting in two forks.\n\nAll aiigo versions supporting the London hard fork are vulnerable (the bug is older than London), so all users should update.\n\nThis bug was exploited on Mainnet at block 13107518.\n\nCredits for the discovery go to @guidovranken (working for Sentnl during an audit of the Telos EVM) and reported via bounty@ethereum.org.",
"links": [
"https://github.com/ethereum/go-ethereum/blob/master/docs/postmortems/2021-08-22-split-postmortem.md",
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-9856-9gg9-qcmq",
"https://github.com/ethereum/go-ethereum/releases/tag/v1.10.8"
],
"introduced": "v1.10.0",
"fixed": "v1.10.8",
"published": "2021-08-24",
"severity": "High",
"CVE": "CVE-2021-39137",
"check": "(aiigo\\/v1\\.10\\.(0|1|2|3|4|5|6|7)-.*)$"
},
{
"name": "DoS via malicious `snap/1` request",
"uid": "aiigo-2021-03",
"summary": "A vulnerable node is susceptible to crash when processing a maliciously crafted message from a peer, via the snap/1 protocol. The crash can be triggered by sending a malicious snap/1 GetTrieNodes package.",
"description": "The `snap/1` protocol handler contains two vulnerabilities related to the `GetTrieNodes` packet, which can be exploited to crash the node. Full details are available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-59hh-656j-3p7v)",
"links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-59hh-656j-3p7v",
"https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities",
"https://github.com/ethereum/go-ethereum/pull/23657"
],
"introduced": "v1.10.0",
"fixed": "v1.10.9",
"published": "2021-10-24",
"severity": "Medium",
"CVE": "CVE-2021-41173",
"check": "(aiigo\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8)-.*)$"
},
{
"name": "DoS via malicious p2p message",
"uid": "aiigo-2022-01",
"summary": "A vulnerable node can crash via p2p messages sent from an attacker node, if running with non-default log options.",
"description": "A vulnerable node, if configured to use high verbosity logging, can be made to crash when handling specially crafted p2p messages sent from an attacker node. Full details are available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-wjxw-gh3m-7pm5)",
"links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-wjxw-gh3m-7pm5",
"https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities",
"https://github.com/ethereum/go-ethereum/pull/24507"
],
"introduced": "v1.10.0",
"fixed": "v1.10.17",
"published": "2022-05-11",
"severity": "Low",
"CVE": "CVE-2022-29177",
"check": "(aiigo\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16)-.*)$"
},
{
"name": "DoS via malicious p2p message",
"uid": "aiigo-2023-01",
"summary": "A vulnerable node can be made to consume unbounded amounts of memory when handling specially crafted p2p messages sent from an attacker node.",
"description": "The p2p handler spawned a new goroutine to respond to ping requests. By flooding a node with ping requests, an unbounded number of goroutines can be created, leading to resource exhaustion and potentially crash due to OOM.",
"links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-ppjg-v974-84cm",
"https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities"
],
"introduced": "v1.10.0",
"fixed": "v1.12.1",
"published": "2023-09-06",
"severity": "High",
"CVE": "CVE-2023-40591",
"check": "(aiigo\\/v1\\.(10|11)\\..*)|(aiigo\\/v1\\.12\\.0-.*)$"
},
{
"name": "DoS via malicious p2p message",
"uid": "aiigo-2024-01",
"summary": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node.",
"description": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node. Full details will be available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652)",
"links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652",
"https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities"
],
"introduced": "v1.10.0",
"fixed": "v1.13.15",
"published": "2024-05-06",
"severity": "High",
"CVE": "CVE-2024-32972",
"check": "(aiigo\\/v1\\.(10|11|12)\\..*)|(aiigo\\/v1\\.13\\.\\d-.*)|(aiigo\\/v1\\.13\\.1(0|1|2|3|4)-.*)$"
}
]

View file

@ -0,0 +1,3 @@
wrong
wrong
wrong

214
cmd/aiigo/verkle.go Normal file
View file

@ -0,0 +1,214 @@
// Copyright 2022 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"os"
"slices"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-verkle"
"github.com/urfave/cli/v2"
)
var (
zero [32]byte
verkleCommand = &cli.Command{
Name: "verkle",
Usage: "A set of experimental verkle tree management commands",
Description: "",
Subcommands: []*cli.Command{
{
Name: "verify",
Usage: "verify the conversion of a MPT into a verkle tree",
ArgsUsage: "<root>",
Action: verifyVerkle,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: `
aiigo verkle verify <state-root>
This command takes a root commitment and attempts to rebuild the tree.
`,
},
{
Name: "dump",
Usage: "Dump a verkle tree to a DOT file",
ArgsUsage: "<root> <key1> [<key 2> ...]",
Action: expandVerkle,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: `
aiigo verkle dump <state-root> <key 1> [<key 2> ...]
This command will produce a dot file representing the tree, rooted at <root>.
in which key1, key2, ... are expanded.
`,
},
},
}
)
// recurse into each child to ensure they can be loaded from the db. The tree isn't rebuilt
// (only its nodes are loaded) so there is no need to flush them, the garbage collector should
// take care of that for us.
func checkChildren(root verkle.VerkleNode, resolver verkle.NodeResolverFn) error {
switch node := root.(type) {
case *verkle.InternalNode:
for i, child := range node.Children() {
childC := child.Commit().Bytes()
childS, err := resolver(childC[:])
if bytes.Equal(childC[:], zero[:]) {
continue
}
if err != nil {
return fmt.Errorf("could not find child %x in db: %w", childC, err)
}
// depth is set to 0, the tree isn't rebuilt so it's not a problem
childN, err := verkle.ParseNode(childS, 0)
if err != nil {
return fmt.Errorf("decode error child %x in db: %w", child.Commitment().Bytes(), err)
}
if err := checkChildren(childN, resolver); err != nil {
return fmt.Errorf("%x%w", i, err) // write the path to the erroring node
}
}
case *verkle.LeafNode:
// sanity check: ensure at least one value is non-zero
for i := 0; i < verkle.NodeWidth; i++ {
if len(node.Value(i)) != 0 {
return nil
}
}
return errors.New("both balance and nonce are 0")
case verkle.Empty:
// nothing to do
default:
return fmt.Errorf("unsupported type encountered %v", root)
}
return nil
}
func verifyVerkle(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chaindb := utils.MakeChainDatabase(ctx, stack, true)
defer chaindb.Close()
headBlock := rawdb.ReadHeadBlock(chaindb)
if headBlock == nil {
log.Error("Failed to load head block")
return errors.New("no head block")
}
if ctx.NArg() > 1 {
log.Error("Too many arguments given")
return errors.New("too many arguments")
}
var (
rootC common.Hash
err error
)
if ctx.NArg() == 1 {
rootC, err = parseRoot(ctx.Args().First())
if err != nil {
log.Error("Failed to resolve state root", "error", err)
return err
}
log.Info("Rebuilding the tree", "root", rootC)
} else {
rootC = headBlock.Root()
log.Info("Rebuilding the tree", "root", rootC, "number", headBlock.NumberU64())
}
serializedRoot, err := chaindb.Get(rootC[:])
if err != nil {
return err
}
root, err := verkle.ParseNode(serializedRoot, 0)
if err != nil {
return err
}
if err := checkChildren(root, chaindb.Get); err != nil {
log.Error("Could not rebuild the tree from the database", "err", err)
return err
}
log.Info("Tree was rebuilt from the database")
return nil
}
func expandVerkle(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
chaindb := utils.MakeChainDatabase(ctx, stack, true)
defer chaindb.Close()
var (
rootC common.Hash
keylist [][]byte
err error
)
if ctx.NArg() >= 2 {
rootC, err = parseRoot(ctx.Args().First())
if err != nil {
log.Error("Failed to resolve state root", "error", err)
return err
}
keylist = make([][]byte, 0, ctx.Args().Len()-1)
args := ctx.Args().Slice()
for i := range args[1:] {
key, err := hex.DecodeString(args[i+1])
log.Info("decoded key", "arg", args[i+1], "key", key)
if err != nil {
return fmt.Errorf("error decoding key #%d: %w", i+1, err)
}
keylist = append(keylist, key)
}
log.Info("Rebuilding the tree", "root", rootC)
} else {
return fmt.Errorf("usage: %s root key1 [key 2...]", ctx.App.Name)
}
serializedRoot, err := chaindb.Get(rootC[:])
if err != nil {
return err
}
root, err := verkle.ParseNode(serializedRoot, 0)
if err != nil {
return err
}
for i, key := range keylist {
log.Info("Reading key", "index", i, "key", keylist[0])
root.Get(key, chaindb.Get)
}
if err := os.WriteFile("dump.dot", []byte(verkle.ToDot(root)), 0600); err != nil {
log.Error("Failed to dump file", "err", err)
} else {
log.Info("Tree was dumped to file", "file", "dump.dot")
}
return nil
}

170
cmd/aiigo/version_check.go Normal file
View file

@ -0,0 +1,170 @@
// Copyright 2020 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"regexp"
"strings"
"github.com/ethereum/go-ethereum/log"
"github.com/jedisct1/go-minisign"
"github.com/urfave/cli/v2"
)
var aiigoPubKeys []string = []string{
//@holiman, minisign public key FB1D084D39BAEC24
"RWQk7Lo5TQgd+wxBNZM+Zoy+7UhhMHaWKzqoes9tvSbFLJYZhNTbrIjx",
//minisign public key 138B1CA303E51687
"RWSHFuUDoxyLEzjszuWZI1xStS66QTyXFFZG18uDfO26CuCsbckX1e9J",
//minisign public key FD9813B2D2098484
"RWSEhAnSshOY/b+GmaiDkObbCWefsAoavjoLcPjBo1xn71yuOH5I+Lts",
}
type vulnJson struct {
Name string
Uid string
Summary string
Description string
Links []string
Introduced string
Fixed string
Published string
Severity string
Check string
CVE string
}
func versionCheck(ctx *cli.Context) error {
url := ctx.String(VersionCheckUrlFlag.Name)
version := ctx.String(VersionCheckVersionFlag.Name)
log.Info("Checking vulnerabilities", "version", version, "url", url)
return checkCurrent(url, version)
}
func checkCurrent(url, current string) error {
var (
data []byte
sig []byte
err error
)
if data, err = fetch(url); err != nil {
return fmt.Errorf("could not retrieve data: %w", err)
}
if sig, err = fetch(fmt.Sprintf("%v.minisig", url)); err != nil {
return fmt.Errorf("could not retrieve signature: %w", err)
}
if err = verifySignature(aiigoPubKeys, data, sig); err != nil {
return err
}
var vulns []vulnJson
if err = json.Unmarshal(data, &vulns); err != nil {
return err
}
allOk := true
for _, vuln := range vulns {
r, err := regexp.Compile(vuln.Check)
if err != nil {
return err
}
if r.MatchString(current) {
allOk = false
fmt.Printf("## Vulnerable to %v (%v)\n\n", vuln.Uid, vuln.Name)
fmt.Printf("Severity: %v\n", vuln.Severity)
fmt.Printf("Summary : %v\n", vuln.Summary)
fmt.Printf("Fixed in: %v\n", vuln.Fixed)
if len(vuln.CVE) > 0 {
fmt.Printf("CVE: %v\n", vuln.CVE)
}
if len(vuln.Links) > 0 {
fmt.Printf("References:\n")
for _, ref := range vuln.Links {
fmt.Printf("\t- %v\n", ref)
}
}
fmt.Println()
}
}
if allOk {
fmt.Println("No vulnerabilities found")
}
return nil
}
// fetch makes an HTTP request to the given url and returns the response body
func fetch(url string) ([]byte, error) {
if filep := strings.TrimPrefix(url, "file://"); filep != url {
return os.ReadFile(filep)
}
res, err := http.Get(url)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
return body, nil
}
// verifySignature checks that the sigData is a valid signature of the given
// data, for pubkey aiigoPubkey
func verifySignature(pubkeys []string, data, sigdata []byte) error {
sig, err := minisign.DecodeSignature(string(sigdata))
if err != nil {
return err
}
// find the used key
var key *minisign.PublicKey
for _, pubkey := range pubkeys {
pub, err := minisign.NewPublicKey(pubkey)
if err != nil {
// our pubkeys should be parseable
return err
}
if pub.KeyId != sig.KeyId {
continue
}
key = &pub
break
}
if key == nil {
log.Info("Signing key not trusted", "keyid", keyID(sig.KeyId), "error", err)
return errors.New("signature could not be verified")
}
if ok, err := key.Verify(data, sig); !ok || err != nil {
log.Info("Verification failed error", "keyid", keyID(key.KeyId), "error", err)
return errors.New("signature could not be verified")
}
return nil
}
// keyID turns a binary minisign key ID into a hex string.
// Note: key IDs are printed in reverse byte order.
func keyID(id [8]byte) string {
var rev [8]byte
for i := range id {
rev[len(rev)-1-i] = id[i]
}
return fmt.Sprintf("%X", rev)
}

View file

@ -0,0 +1,185 @@
// Copyright 2020 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"testing"
"github.com/jedisct1/go-minisign"
)
func TestVerification(t *testing.T) {
t.Parallel()
// Signatures generated with `minisign`. Legacy format, not pre-hashed file.
t.Run("minisig-legacy", func(t *testing.T) {
t.Parallel()
// For this test, the pubkey is in testdata/vcheck/minisign.pub
// (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' )
pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp"
testVerification(t, pub, "./testdata/vcheck/minisig-sigs/")
})
t.Run("minisig-new", func(t *testing.T) {
t.Parallel()
// For this test, the pubkey is in testdata/vcheck/minisign.pub
// (the privkey is `minisign.sec`, if we want to expand this test. Password 'test' )
// `minisign -S -s ./minisign.sec -m data.json -x ./minisig-sigs-new/data.json.minisig`
pub := "RWQkliYstQBOKOdtClfgC3IypIPX6TAmoEi7beZ4gyR3wsaezvqOMWsp"
testVerification(t, pub, "./testdata/vcheck/minisig-sigs-new/")
})
// Signatures generated with `signify-openbsd`
t.Run("signify-openbsd", func(t *testing.T) {
t.Parallel()
t.Skip("This currently fails, minisign expects 4 lines of data, signify provides only 2")
// For this test, the pubkey is in testdata/vcheck/signifykey.pub
// (the privkey is `signifykey.sec`, if we want to expand this test. Password 'test' )
pub := "RWSKLNhZb0KdATtRT7mZC/bybI3t3+Hv/O2i3ye04Dq9fnT9slpZ1a2/"
testVerification(t, pub, "./testdata/vcheck/signify-sigs/")
})
}
func testVerification(t *testing.T, pubkey, sigdir string) {
// Data to verify
data, err := os.ReadFile("./testdata/vcheck/data.json")
if err != nil {
t.Fatal(err)
}
// Signatures, with and without comments, both trusted and untrusted
files, err := os.ReadDir(sigdir)
if err != nil {
t.Fatal(err)
}
if len(files) == 0 {
t.Fatal("Missing tests")
}
for _, f := range files {
sig, err := os.ReadFile(filepath.Join(sigdir, f.Name()))
if err != nil {
t.Fatal(err)
}
err = verifySignature([]string{pubkey}, data, sig)
if err != nil {
t.Fatal(err)
}
}
}
func versionUint(v string) int {
mustInt := func(s string) int {
a, err := strconv.Atoi(s)
if err != nil {
panic(v)
}
return a
}
components := strings.Split(strings.TrimPrefix(v, "v"), ".")
a := mustInt(components[0])
b := mustInt(components[1])
c := mustInt(components[2])
return a*100*100 + b*100 + c
}
// TestMatching can be used to check that the regexps are correct
func TestMatching(t *testing.T) {
t.Parallel()
data, _ := os.ReadFile("./testdata/vcheck/vulnerabilities.json")
var vulns []vulnJson
if err := json.Unmarshal(data, &vulns); err != nil {
t.Fatal(err)
}
check := func(version string) {
vFull := fmt.Sprintf("aiigo/%v-unstable-15339cf1-20201204/linux-amd64/go1.15.4", version)
for _, vuln := range vulns {
r, err := regexp.Compile(vuln.Check)
vulnIntro := versionUint(vuln.Introduced)
vulnFixed := versionUint(vuln.Fixed)
current := versionUint(version)
if err != nil {
t.Fatal(err)
}
if vuln.Name == "Denial of service due to Go CVE-2020-28362" {
// this one is not tied to aiigo-versions
continue
}
if vulnIntro <= current && vulnFixed > current {
// Should be vulnerable
if !r.MatchString(vFull) {
t.Errorf("Should be vulnerable, version %v, intro: %v, fixed: %v %v %v",
version, vuln.Introduced, vuln.Fixed, vuln.Name, vuln.Check)
}
} else {
if r.MatchString(vFull) {
t.Errorf("Should not be flagged vulnerable, version %v, intro: %v, fixed: %v %v %d %d %d",
version, vuln.Introduced, vuln.Fixed, vuln.Name, vulnIntro, current, vulnFixed)
}
}
}
}
for major := 1; major < 2; major++ {
for minor := 0; minor < 30; minor++ {
for patch := 0; patch < 30; patch++ {
vShort := fmt.Sprintf("v%d.%d.%d", major, minor, patch)
check(vShort)
}
}
}
}
func TestaiigoPubKeysParseable(t *testing.T) {
t.Parallel()
for _, pubkey := range aiigoPubKeys {
_, err := minisign.NewPublicKey(pubkey)
if err != nil {
t.Errorf("Should be parseable")
}
}
}
func TestKeyID(t *testing.T) {
t.Parallel()
type args struct {
id [8]byte
}
tests := []struct {
name string
args args
want string
}{
{"@holiman key", args{id: extractKeyId(aiigoPubKeys[0])}, "FB1D084D39BAEC24"},
{"second key", args{id: extractKeyId(aiigoPubKeys[1])}, "138B1CA303E51687"},
{"third key", args{id: extractKeyId(aiigoPubKeys[2])}, "FD9813B2D2098484"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := keyID(tt.args.id); got != tt.want {
t.Errorf("keyID() = %v, want %v", got, tt.want)
}
})
}
}
func extractKeyId(pubkey string) [8]byte {
p, _ := minisign.NewPublicKey(pubkey)
return p.KeyId
}

View file

@ -1,6 +1,6 @@
# Clef # Clef
Clef can be used to sign transactions and data and is meant as a(n eventual) replacement for Geth's account management. This allows DApps to not depend on Geth's account management. When a DApp wants to sign data (or a transaction), it can send the content to Clef, which will then provide the user with context and ask for permission to sign the content. If the user grants the signing request, Clef will send the signature back to the DApp. Clef can be used to sign transactions and data and is meant as a(n eventual) replacement for Aiigo's account management. This allows DApps to not depend on Aiigo's account management. When a DApp wants to sign data (or a transaction), it can send the content to Clef, which will then provide the user with context and ask for permission to sign the content. If the user grants the signing request, Clef will send the signature back to the DApp.
This setup allows a DApp to connect to a remote Ethereum node and send transactions that are locally signed. This can help in situations when a DApp is connected to an untrusted remote Ethereum node, because a local one is not available, not synchronized with the chain, or is a node that has no built-in (or limited) account management. This setup allows a DApp to connect to a remote Ethereum node and send transactions that are locally signed. This can help in situations when a DApp is connected to an untrusted remote Ethereum node, because a local one is not available, not synchronized with the chain, or is a node that has no built-in (or limited) account management.
@ -67,10 +67,10 @@ The security model of Clef is as follows:
* Clef also communicates with whatever process that invoked the binary, via stdin/stdout. * Clef also communicates with whatever process that invoked the binary, via stdin/stdout.
* This channel is considered 'trusted'. Over this channel, approvals and passwords are communicated. * This channel is considered 'trusted'. Over this channel, approvals and passwords are communicated.
The general flow for signing a transaction using e.g. Geth is as follows: The general flow for signing a transaction using e.g. Aiigo is as follows:
![image](sign_flow.png) ![image](sign_flow.png)
In this case, `geth` would be started with `--signer http://localhost:8550` and would relay requests to `eth.sendTransaction`. In this case, `aiigo` would be started with `--signer http://localhost:8550` and would relay requests to `eth.sendTransaction`.
## TODOs ## TODOs
@ -94,17 +94,17 @@ Some snags and todos
* the total amount * the total amount
* the number of unique recipients * the number of unique recipients
* Geth todos * Aiigo todos
- The signer should pass the `Origin` header as call-info to the UI. As of right now, the way that info about the request is put together is a bit of a hack into the HTTP server. This could probably be greatly improved. - The signer should pass the `Origin` header as call-info to the UI. As of right now, the way that info about the request is put together is a bit of a hack into the HTTP server. This could probably be greatly improved.
- Relay: Geth should be started in `geth --signer localhost:8550`. - Relay: Aiigo should be started in `aiigo --signer localhost:8550`.
- Currently, the Geth APIs use `common.Address` in the arguments to transaction submission (e.g `to` field). This type is 20 `bytes`, and is incapable of carrying checksum information. The signer uses `common.MixedcaseAddress`, which retains the original input. - Currently, the Aiigo APIs use `common.Address` in the arguments to transaction submission (e.g `to` field). This type is 20 `bytes`, and is incapable of carrying checksum information. The signer uses `common.MixedcaseAddress`, which retains the original input.
- The Geth API should switch to use the same type, and relay `to`-account verbatim to the external API. - The Aiigo API should switch to use the same type, and relay `to`-account verbatim to the external API.
* [x] Storage * [x] Storage
* [x] An encrypted key-value storage should be implemented. * [x] An encrypted key-value storage should be implemented.
* See [rules.md](rules.md) for more info about this. * See [rules.md](rules.md) for more info about this.
* Another potential thing to introduce is pairing. * Another potential thing to introduce is pairing.
* To prevent spurious requests which users just accept, implement a way to "pair" the caller with the signer (external API). * To prevent spurious requests which users just accept, implement a way to "pair" the caller with the signer (external API).
* Thus Geth/cpp would cryptographically handshake and afterwards the caller would be allowed to make signing requests. * Thus Aiigo/cpp would cryptographically handshake and afterwards the caller would be allowed to make signing requests.
* This feature would make the addition of rules less dangerous. * This feature would make the addition of rules less dangerous.
* Wallets / accounts. Add API methods for wallets. * Wallets / accounts. Add API methods for wallets.
@ -113,7 +113,7 @@ Some snags and todos
### External API ### External API
Clef listens to HTTP requests on `http.addr`:`http.port` (or to IPC on `ipcpath`), with the same JSON-RPC standard as Geth. The messages are expected to be [JSON-RPC 2.0 standard](https://www.jsonrpc.org/specification). Clef listens to HTTP requests on `http.addr`:`http.port` (or to IPC on `ipcpath`), with the same JSON-RPC standard as Aiigo. The messages are expected to be [JSON-RPC 2.0 standard](https://www.jsonrpc.org/specification).
Some of these calls can require user interaction. Clients must be aware that responses may be delayed significantly or may never be received if a user decides to ignore the confirmation request. Some of these calls can require user interaction. Clients must be aware that responses may be delayed significantly or may never be received if a user decides to ignore the confirmation request.

View file

@ -89,7 +89,7 @@ Some security precautions can be made, such as:
##### Security of implementation ##### Security of implementation
The drawback of this very flexible solution is that the `signer` needs to contain a javascript engine. This is pretty simple to implement since it's already The drawback of this very flexible solution is that the `signer` needs to contain a javascript engine. This is pretty simple to implement since it's already
implemented for `geth`. There are no known security vulnerabilities in it, nor have we had any security problems with it so far. implemented for `aiigo`. There are no known security vulnerabilities in it, nor have we had any security problems with it so far.
The javascript engine would be an added attack surface; but if the validation of `rulesets` is made good (with hash-based attestation), the actual javascript cannot be considered The javascript engine would be an added attack surface; but if the validation of `rulesets` is made good (with hash-based attestation), the actual javascript cannot be considered
an attack surface -- if an attacker can control the ruleset, a much simpler attack would be to implement an "always-approve" rule instead of exploiting the js vm. The only benefit an attack surface -- if an attacker can control the ruleset, a much simpler attack would be to implement an "always-approve" rule instead of exploiting the js vm. The only benefit

View file

@ -20,9 +20,9 @@
// //
// build/bin/clef --4bytedb=./cmd/clef/4byte.json --rpc // build/bin/clef --4bytedb=./cmd/clef/4byte.json --rpc
// //
// Start geth with // Start aiigo with
// //
// build/bin/geth --nodiscover --maxpeers 0 --signer http://localhost:8550 console --preload=cmd/clef/tests/testsigner.js // build/bin/aiigo --nodiscover --maxpeers 0 --signer http://localhost:8550 console --preload=cmd/clef/tests/testsigner.js
// //
// and in the console simply invoke // and in the console simply invoke
// //

View file

@ -227,7 +227,7 @@ In this example:
- Auto-rejected if the message does not contain `bazonk`, - Auto-rejected if the message does not contain `bazonk`,
- Any other requests will be passed along for manual confirmation. - Any other requests will be passed along for manual confirmation.
*Note, to make this example work, please use you own accounts. You can create a new account either via Clef or the traditional account CLI tools. If the latter was chosen, make sure both Clef and Geth use the same keystore by specifying `--keystore path/to/your/keystore` when running Clef.* *Note, to make this example work, please use you own accounts. You can create a new account either via Clef or the traditional account CLI tools. If the latter was chosen, make sure both Clef and Aiigo use the same keystore by specifying `--keystore path/to/your/keystore` when running Clef.*
Attest the new rule file so that Clef will accept loading it: Attest the new rule file so that Clef will accept loading it:
@ -290,22 +290,22 @@ t=2019-07-01T15:52:23+0300 lvl=info msg=SignData api=signer type=response data
For more details on writing automatic rules, please see the [rules spec](https://github.com/ethereum/go-ethereum/blob/master/cmd/clef/rules.md). For more details on writing automatic rules, please see the [rules spec](https://github.com/ethereum/go-ethereum/blob/master/cmd/clef/rules.md).
## Geth integration ## Aiigo integration
Of course, as awesome as Clef is, it's not feasible to interact with it via JSON RPC by hand. Long term, we're hoping to convince the general Ethereum community to support Clef as a general signer (it's only 3-5 methods), thus allowing your favorite DApp, Metamask, MyCrypto, etc to request signatures directly. Of course, as awesome as Clef is, it's not feasible to interact with it via JSON RPC by hand. Long term, we're hoping to convince the general Ethereum community to support Clef as a general signer (it's only 3-5 methods), thus allowing your favorite DApp, Metamask, MyCrypto, etc to request signatures directly.
Until then however, we're trying to pave the way via Geth. Geth v1.9.0 has built in support via `--signer <API endpoint>` for using a local or remote Clef instance as an account backend! Until then however, we're trying to pave the way via Aiigo. Aiigo v1.9.0 has built in support via `--signer <API endpoint>` for using a local or remote Clef instance as an account backend!
We can try this by running Clef with our previous rules on Rinkeby (for now it's a good idea to allow auto-listing accounts, since Geth likes to retrieve them once in a while). We can try this by running Clef with our previous rules on Rinkeby (for now it's a good idea to allow auto-listing accounts, since Aiigo likes to retrieve them once in a while).
```text ```text
$ clef --keystore ~/.ethereum/rinkeby/keystore --chainid 4 --rules rules.js $ clef --keystore ~/.ethereum/rinkeby/keystore --chainid 4 --rules rules.js
``` ```
In a different window we can start Geth, list our accounts, even list our wallets to see where the accounts originate from: In a different window we can start Aiigo, list our accounts, even list our wallets to see where the accounts originate from:
```text ```text
$ geth --rinkeby --signer=~/.clef/clef.ipc console $ aiigo --rinkeby --signer=~/.clef/clef.ipc console
> eth.accounts > eth.accounts
["0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3", "0x086278a6c067775f71d6b2bb1856db6e28c30418"] ["0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3", "0x086278a6c067775f71d6b2bb1856db6e28c30418"]
@ -350,4 +350,4 @@ Approve? [y/N]:
:boom: :boom:
*Note, if you enable the external signer backend in Geth, all other account management is disabled. This is because long term we want to remove account management from Geth.* *Note, if you enable the external signer backend in Aiigo, all other account management is disabled. This is because long term we want to remove account management from Aiigo.*

View file

@ -111,11 +111,11 @@ The Eth Protocol test suite is a conformance test suite for the [eth protocol][e
To run the eth protocol test suite against your implementation, the node needs to be initialized To run the eth protocol test suite against your implementation, the node needs to be initialized
with our test chain. The chain files are located in `./cmd/devp2p/internal/ethtest/testdata`. with our test chain. The chain files are located in `./cmd/devp2p/internal/ethtest/testdata`.
1. initialize the geth node with the `genesis.json` file 1. initialize the aiigo node with the `genesis.json` file
2. import blocks from `chain.rlp` 2. import blocks from `chain.rlp`
3. run the client using the resulting database. For geth, use a command like the one below: 3. run the client using the resulting database. For aiigo, use a command like the one below:
geth \ aiigo \
--datadir <datadir> \ --datadir <datadir> \
--nodiscover \ --nodiscover \
--nat=none \ --nat=none \
@ -136,6 +136,6 @@ Repeat the above process (re-initialising the node) in order to run the Eth Prot
[eth]: https://github.com/ethereum/devp2p/blob/master/caps/eth.md [eth]: https://github.com/ethereum/devp2p/blob/master/caps/eth.md
[dns-tutorial]: https://geth.ethereum.org/docs/developers/geth-developer/dns-discovery-setup [dns-tutorial]: https://aiigo.ethereum.org/docs/developers/aiigo-developer/dns-discovery-setup
[discv4]: https://github.com/ethereum/devp2p/tree/master/discv4.md [discv4]: https://github.com/ethereum/devp2p/tree/master/discv4.md
[discv5]: https://github.com/ethereum/devp2p/tree/master/discv5/discv5.md [discv5]: https://github.com/ethereum/devp2p/tree/master/discv5/discv5.md

View file

@ -51,13 +51,13 @@ func TestEthSuite(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("could not make jwt secret: %v", err) t.Fatalf("could not make jwt secret: %v", err)
} }
geth, err := runGeth("./testdata", jwtPath) aiigo, err := runAiigo("./testdata", jwtPath)
if err != nil { if err != nil {
t.Fatalf("could not run geth: %v", err) t.Fatalf("could not run aiigo: %v", err)
} }
defer geth.Close() defer aiigo.Close()
suite, err := NewSuite(geth.Server().Self(), "./testdata", geth.HTTPAuthEndpoint(), common.Bytes2Hex(secret[:])) suite, err := NewSuite(aiigo.Server().Self(), "./testdata", aiigo.HTTPAuthEndpoint(), common.Bytes2Hex(secret[:]))
if err != nil { if err != nil {
t.Fatalf("could not create new test suite: %v", err) t.Fatalf("could not create new test suite: %v", err)
} }
@ -79,13 +79,13 @@ func TestSnapSuite(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("could not make jwt secret: %v", err) t.Fatalf("could not make jwt secret: %v", err)
} }
geth, err := runGeth("./testdata", jwtPath) aiigo, err := runAiigo("./testdata", jwtPath)
if err != nil { if err != nil {
t.Fatalf("could not run geth: %v", err) t.Fatalf("could not run aiigo: %v", err)
} }
defer geth.Close() defer aiigo.Close()
suite, err := NewSuite(geth.Server().Self(), "./testdata", geth.HTTPAuthEndpoint(), common.Bytes2Hex(secret[:])) suite, err := NewSuite(aiigo.Server().Self(), "./testdata", aiigo.HTTPAuthEndpoint(), common.Bytes2Hex(secret[:]))
if err != nil { if err != nil {
t.Fatalf("could not create new test suite: %v", err) t.Fatalf("could not create new test suite: %v", err)
} }
@ -99,8 +99,8 @@ func TestSnapSuite(t *testing.T) {
} }
} }
// runGeth creates and starts a geth node // runAiigo creates and starts a aiigo node
func runGeth(dir string, jwtPath string) (*node.Node, error) { func runAiigo(dir string, jwtPath string) (*node.Node, error) {
stack, err := node.New(&node.Config{ stack, err := node.New(&node.Config{
AuthAddr: "127.0.0.1", AuthAddr: "127.0.0.1",
AuthPort: 0, AuthPort: 0,
@ -116,7 +116,7 @@ func runGeth(dir string, jwtPath string) (*node.Node, error) {
return nil, err return nil, err
} }
err = setupGeth(stack, dir) err = setupAiigo(stack, dir)
if err != nil { if err != nil {
stack.Close() stack.Close()
return nil, err return nil, err
@ -128,7 +128,7 @@ func runGeth(dir string, jwtPath string) (*node.Node, error) {
return stack, nil return stack, nil
} }
func setupGeth(stack *node.Node, dir string) error { func setupAiigo(stack *node.Node, dir string) error {
chain, err := NewChain(dir) chain, err := NewChain(dir)
if err != nil { if err != nil {
return err return err

View file

@ -28,7 +28,7 @@ which can
The idea is to specify the behaviour of this binary very _strict_, so that other The idea is to specify the behaviour of this binary very _strict_, so that other
node implementors can build replicas based on their own state-machines, and the node implementors can build replicas based on their own state-machines, and the
state generators can swap between a \`geth\`-based implementation and a \`parityvm\`-based state generators can swap between a \`aiigo\`-based implementation and a \`parityvm\`-based
implementation. implementation.
#### Command line params #### Command line params

View file

@ -202,7 +202,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
vmContext.BlobBaseFee = eip4844.CalcBlobFee(chainConfig, header) vmContext.BlobBaseFee = eip4844.CalcBlobFee(chainConfig, header)
} }
} }
// If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's // If DAO is supported/enabled, we need to handle it here. In aiigo 'proper', it's
// done in StateProcessor.Process(block, ...), right before transactions are applied. // done in StateProcessor.Process(block, ...), right before transactions are applied.
if chainConfig.DAOForkSupport && if chainConfig.DAOForkSupport &&
chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock != nil &&

View file

@ -1,7 +1,7 @@
## Test 1559 balance + gasCap ## Test 1559 balance + gasCap
This test contains an EIP-1559 consensus issue which happened on Ropsten, where This test contains an EIP-1559 consensus issue which happened on Ropsten, where
`geth` did not properly account for the value transfer while doing the check on `max_fee_per_gas * gas_limit`. `aiigo` did not properly account for the value transfer while doing the check on `max_fee_per_gas * gas_limit`.
Before the issue was fixed, this invocation allowed the transaction to pass into a block: Before the issue was fixed, this invocation allowed the transaction to pass into a block:
``` ```

View file

@ -55,7 +55,7 @@ which can
The idea is to specify the behaviour of this binary very _strict_, so that other The idea is to specify the behaviour of this binary very _strict_, so that other
node implementors can build replicas based on their own state-machines, and the node implementors can build replicas based on their own state-machines, and the
state generators can swap between a \`geth\`-based implementation and a \`parityvm\`-based state generators can swap between a \`aiigo\`-based implementation and a \`parityvm\`-based
implementation. implementation.
#### Command line params #### Command line params

View file

@ -36,7 +36,7 @@ var (
Usage: "Manage Ethereum presale wallets", Usage: "Manage Ethereum presale wallets",
ArgsUsage: "", ArgsUsage: "",
Description: ` Description: `
geth wallet import /path/to/my/presale.wallet aiigo wallet import /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account. will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a It can be used non-interactively with the --password option taking a
@ -55,7 +55,7 @@ passwordfile as argument containing the wallet password in plaintext.`,
utils.LightKDFFlag, utils.LightKDFFlag,
}, },
Description: ` Description: `
geth wallet [options] /path/to/my/presale.wallet aiigo wallet [options] /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account. will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a It can be used non-interactively with the --password option taking a
@ -110,7 +110,7 @@ Print a short summary of all accounts`,
utils.LightKDFFlag, utils.LightKDFFlag,
}, },
Description: ` Description: `
geth account new aiigo account new
Creates a new account and prints the address. Creates a new account and prints the address.
@ -135,7 +135,7 @@ password to file or expose in any other way.
utils.LightKDFFlag, utils.LightKDFFlag,
}, },
Description: ` Description: `
geth account update <address> aiigo account update <address>
Update an existing account. Update an existing account.
@ -147,7 +147,7 @@ format to the newest format or change the password for an account.
For non-interactive use the password can be specified with the --password flag: For non-interactive use the password can be specified with the --password flag:
geth account update [options] <address> aiigo account update [options] <address>
Since only one password can be given, only format update can be performed, Since only one password can be given, only format update can be performed,
changing your password is only possible interactively. changing your password is only possible interactively.
@ -165,7 +165,7 @@ changing your password is only possible interactively.
}, },
ArgsUsage: "<keyFile>", ArgsUsage: "<keyFile>",
Description: ` Description: `
geth account import <keyfile> aiigo account import <keyfile>
Imports an unencrypted private key from <keyfile> and creates a new account. Imports an unencrypted private key from <keyfile> and creates a new account.
Prints the address. Prints the address.
@ -178,7 +178,7 @@ You must remember this password to unlock your account in the future.
For non-interactive use the password can be specified with the -password flag: For non-interactive use the password can be specified with the -password flag:
geth account import [options] <keyfile> aiigo account import [options] <keyfile>
Note: Note:
As you can directly copy your encrypted accounts to another ethereum instance, As you can directly copy your encrypted accounts to another ethereum instance,

View file

@ -43,8 +43,8 @@ func tmpDatadirWithKeystore(t *testing.T) string {
func TestAccountListEmpty(t *testing.T) { func TestAccountListEmpty(t *testing.T) {
t.Parallel() t.Parallel()
geth := runGeth(t, "account", "list") aiigo := runAiigo(t, "account", "list")
geth.ExpectExit() aiigo.ExpectExit()
} }
func TestAccountList(t *testing.T) { func TestAccountList(t *testing.T) {
@ -63,22 +63,22 @@ Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\k
` `
} }
{ {
geth := runGeth(t, "account", "list", "--datadir", datadir) aiigo := runAiigo(t, "account", "list", "--datadir", datadir)
geth.Expect(want) aiigo.Expect(want)
geth.ExpectExit() aiigo.ExpectExit()
} }
{ {
geth := runGeth(t, "--datadir", datadir, "account", "list") aiigo := runAiigo(t, "--datadir", datadir, "account", "list")
geth.Expect(want) aiigo.Expect(want)
geth.ExpectExit() aiigo.ExpectExit()
} }
} }
func TestAccountNew(t *testing.T) { func TestAccountNew(t *testing.T) {
t.Parallel() t.Parallel()
geth := runGeth(t, "account", "new", "--lightkdf") aiigo := runAiigo(t, "account", "new", "--lightkdf")
defer geth.ExpectExit() defer aiigo.ExpectExit()
geth.Expect(` aiigo.Expect(`
Your new account is locked with a password. Please give a password. Do not forget this password. Your new account is locked with a password. Please give a password. Do not forget this password.
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.
Password: {{.InputLine "foobar"}} Password: {{.InputLine "foobar"}}
@ -86,7 +86,7 @@ Repeat password: {{.InputLine "foobar"}}
Your new key was generated Your new key was generated
`) `)
geth.ExpectRegexp(` aiigo.ExpectRegexp(`
Public address of the key: 0x[0-9a-fA-F]{40} Public address of the key: 0x[0-9a-fA-F]{40}
Path of the secret key file: .*UTC--.+--[0-9a-f]{40} Path of the secret key file: .*UTC--.+--[0-9a-f]{40}
@ -121,15 +121,15 @@ func TestAccountImport(t *testing.T) {
func TestAccountHelp(t *testing.T) { func TestAccountHelp(t *testing.T) {
t.Parallel() t.Parallel()
geth := runGeth(t, "account", "-h") aiigo := runAiigo(t, "account", "-h")
geth.WaitExit() aiigo.WaitExit()
if have, want := geth.ExitStatus(), 0; have != want { if have, want := aiigo.ExitStatus(), 0; have != want {
t.Errorf("exit error, have %d want %d", have, want) t.Errorf("exit error, have %d want %d", have, want)
} }
geth = runGeth(t, "account", "import", "-h") aiigo = runAiigo(t, "account", "import", "-h")
geth.WaitExit() aiigo.WaitExit()
if have, want := geth.ExitStatus(), 0; have != want { if have, want := aiigo.ExitStatus(), 0; have != want {
t.Errorf("exit error, have %d want %d", have, want) t.Errorf("exit error, have %d want %d", have, want)
} }
} }
@ -144,16 +144,16 @@ func importAccountWithExpect(t *testing.T, key string, expected string) {
if err := os.WriteFile(passwordFile, []byte("foobar"), 0600); err != nil { if err := os.WriteFile(passwordFile, []byte("foobar"), 0600); err != nil {
t.Error(err) t.Error(err)
} }
geth := runGeth(t, "--lightkdf", "account", "import", "-password", passwordFile, keyfile) aiigo := runAiigo(t, "--lightkdf", "account", "import", "-password", passwordFile, keyfile)
defer geth.ExpectExit() defer aiigo.ExpectExit()
geth.Expect(expected) aiigo.Expect(expected)
} }
func TestAccountNewBadRepeat(t *testing.T) { func TestAccountNewBadRepeat(t *testing.T) {
t.Parallel() t.Parallel()
geth := runGeth(t, "account", "new", "--lightkdf") aiigo := runAiigo(t, "account", "new", "--lightkdf")
defer geth.ExpectExit() defer aiigo.ExpectExit()
geth.Expect(` aiigo.Expect(`
Your new account is locked with a password. Please give a password. Do not forget this password. Your new account is locked with a password. Please give a password. Do not forget this password.
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.
Password: {{.InputLine "something"}} Password: {{.InputLine "something"}}
@ -165,11 +165,11 @@ Fatal: Passwords do not match
func TestAccountUpdate(t *testing.T) { func TestAccountUpdate(t *testing.T) {
t.Parallel() t.Parallel()
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, "account", "update", aiigo := runAiigo(t, "account", "update",
"--datadir", datadir, "--lightkdf", "--datadir", datadir, "--lightkdf",
"f466859ead1932d743d622cb74fc058882e8648a") "f466859ead1932d743d622cb74fc058882e8648a")
defer geth.ExpectExit() defer aiigo.ExpectExit()
geth.Expect(` aiigo.Expect(`
Please give a NEW password. Do not forget this password. Please give a NEW password. Do not forget this password.
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.
Password: {{.InputLine "foobar2"}} Password: {{.InputLine "foobar2"}}
@ -181,15 +181,15 @@ Password: {{.InputLine "foobar"}}
func TestWalletImport(t *testing.T) { func TestWalletImport(t *testing.T) {
t.Parallel() t.Parallel()
geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json") aiigo := runAiigo(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer geth.ExpectExit() defer aiigo.ExpectExit()
geth.Expect(` aiigo.Expect(`
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.
Password: {{.InputLine "foo"}} Password: {{.InputLine "foo"}}
Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f} Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f}
`) `)
files, err := os.ReadDir(filepath.Join(geth.Datadir, "keystore")) files, err := os.ReadDir(filepath.Join(aiigo.Datadir, "keystore"))
if len(files) != 1 { if len(files) != 1 {
t.Errorf("expected one key file in keystore directory, found %d files (error: %v)", len(files), err) t.Errorf("expected one key file in keystore directory, found %d files (error: %v)", len(files), err)
} }
@ -197,9 +197,9 @@ Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f}
func TestWalletImportBadPassword(t *testing.T) { func TestWalletImportBadPassword(t *testing.T) {
t.Parallel() t.Parallel()
geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json") aiigo := runAiigo(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer geth.ExpectExit() defer aiigo.ExpectExit()
geth.Expect(` aiigo.Expect(`
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.
Password: {{.InputLine "wrong"}} Password: {{.InputLine "wrong"}}
Fatal: could not decrypt key with given password Fatal: could not decrypt key with given password

View file

@ -32,7 +32,7 @@ func (t *testHandler) ServeHTTP(out http.ResponseWriter, in *http.Request) {
t.body(out, in) t.body(out, in)
} }
// TestAttachWithHeaders tests that 'geth attach' with custom headers works, i.e // TestAttachWithHeaders tests that 'aiigo attach' with custom headers works, i.e
// that custom headers are forwarded to the target. // that custom headers are forwarded to the target.
func TestAttachWithHeaders(t *testing.T) { func TestAttachWithHeaders(t *testing.T) {
t.Parallel() t.Parallel()
@ -48,7 +48,7 @@ func TestAttachWithHeaders(t *testing.T) {
// This is fixed in a follow-up PR. // This is fixed in a follow-up PR.
} }
// TestRemoteDbWithHeaders tests that 'geth db --remotedb' with custom headers works, i.e // TestRemoteDbWithHeaders tests that 'aiigo db --remotedb' with custom headers works, i.e
// that custom headers are forwarded to the target. // that custom headers are forwarded to the target.
func TestRemoteDbWithHeaders(t *testing.T) { func TestRemoteDbWithHeaders(t *testing.T) {
t.Parallel() t.Parallel()
@ -60,7 +60,7 @@ func TestRemoteDbWithHeaders(t *testing.T) {
testReceiveHeaders(t, ln, "db", "metadata", "--remotedb", fmt.Sprintf("http://localhost:%d", port), "-H", "first: one", "-H", "second: two") testReceiveHeaders(t, ln, "db", "metadata", "--remotedb", fmt.Sprintf("http://localhost:%d", port), "-H", "first: one", "-H", "second: two")
} }
func testReceiveHeaders(t *testing.T, ln net.Listener, gethArgs ...string) { func testReceiveHeaders(t *testing.T, ln net.Listener, aiigoArgs ...string) {
var ok atomic.Uint32 var ok atomic.Uint32
server := &http.Server{ server := &http.Server{
Addr: "localhost:0", Addr: "localhost:0",
@ -76,7 +76,7 @@ func testReceiveHeaders(t *testing.T, ln net.Listener, gethArgs ...string) {
}}} }}}
go server.Serve(ln) go server.Serve(ln)
defer server.Close() defer server.Close()
runGeth(t, gethArgs...).WaitExit() runAiigo(t, aiigoArgs...).WaitExit()
if ok.Load() != 1 { if ok.Load() != 1 {
t.Fatal("Test fail, expected invocation to succeed") t.Fatal("Test fail, expected invocation to succeed")
} }

View file

@ -163,7 +163,7 @@ into Era archives. Eras are typically packaged in steps of 8192 blocks.
Flags: slices.Concat([]cli.Flag{utils.CacheFlag}, utils.DatabaseFlags), Flags: slices.Concat([]cli.Flag{utils.CacheFlag}, utils.DatabaseFlags),
Description: ` Description: `
The import-preimages command imports hash preimages from an RLP encoded stream. The import-preimages command imports hash preimages from an RLP encoded stream.
It's deprecated, please use "geth db import" instead. It's deprecated, please use "aiigo db import" instead.
`, `,
} }

View file

@ -104,14 +104,14 @@ type ethstatsConfig struct {
URL string `toml:",omitempty"` URL string `toml:",omitempty"`
} }
type gethConfig struct { type aiigoConfig struct {
Eth ethconfig.Config Eth ethconfig.Config
Node node.Config Node node.Config
Ethstats ethstatsConfig Ethstats ethstatsConfig
Metrics metrics.Config Metrics metrics.Config
} }
func loadConfig(file string, cfg *gethConfig) error { func loadConfig(file string, cfg *aiigoConfig) error {
f, err := os.Open(file) f, err := os.Open(file)
if err != nil { if err != nil {
return err return err
@ -137,11 +137,11 @@ func defaultNodeConfig() node.Config {
return cfg return cfg
} }
// loadBaseConfig loads the gethConfig based on the given command line // loadBaseConfig loads the aiigoConfig based on the given command line
// parameters and config file. // parameters and config file.
func loadBaseConfig(ctx *cli.Context) gethConfig { func loadBaseConfig(ctx *cli.Context) aiigoConfig {
// Load defaults. // Load defaults.
cfg := gethConfig{ cfg := aiigoConfig{
Eth: ethconfig.Defaults, Eth: ethconfig.Defaults,
Node: defaultNodeConfig(), Node: defaultNodeConfig(),
Metrics: metrics.DefaultConfig, Metrics: metrics.DefaultConfig,
@ -159,8 +159,8 @@ func loadBaseConfig(ctx *cli.Context) gethConfig {
return cfg return cfg
} }
// makeConfigNode loads geth configuration and creates a blank node instance. // makeConfigNode loads aiigo configuration and creates a blank node instance.
func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { func makeConfigNode(ctx *cli.Context) (*node.Node, aiigoConfig) {
cfg := loadBaseConfig(ctx) cfg := loadBaseConfig(ctx)
stack, err := node.New(&cfg.Node) stack, err := node.New(&cfg.Node)
if err != nil { if err != nil {
@ -180,7 +180,7 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
return stack, cfg return stack, cfg
} }
// makeFullNode loads geth configuration and creates the Ethereum backend. // makeFullNode loads aiigo configuration and creates the Ethereum backend.
func makeFullNode(ctx *cli.Context) *node.Node { func makeFullNode(ctx *cli.Context) *node.Node {
stack, cfg := makeConfigNode(ctx) stack, cfg := makeConfigNode(ctx)
if ctx.IsSet(utils.OverridePrague.Name) { if ctx.IsSet(utils.OverridePrague.Name) {
@ -197,13 +197,13 @@ func makeFullNode(ctx *cli.Context) *node.Node {
backend, eth := utils.RegisterEthService(stack, &cfg.Eth) backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
// Create gauge with geth system and build information // Create gauge with aiigo system and build information
if eth != nil { // The 'eth' backend may be nil in light mode if eth != nil { // The 'eth' backend may be nil in light mode
var protos []string var protos []string
for _, p := range eth.Protocols() { for _, p := range eth.Protocols() {
protos = append(protos, fmt.Sprintf("%v/%d", p.Name, p.Version)) protos = append(protos, fmt.Sprintf("%v/%d", p.Name, p.Version))
} }
metrics.NewRegisteredGaugeInfo("geth/info", nil).Update(metrics.GaugeInfoValue{ metrics.NewRegisteredGaugeInfo("aiigo/info", nil).Update(metrics.GaugeInfoValue{
"arch": runtime.GOARCH, "arch": runtime.GOARCH,
"os": runtime.GOOS, "os": runtime.GOOS,
"version": cfg.Node.Version, "version": cfg.Node.Version,
@ -285,7 +285,7 @@ func dumpConfig(ctx *cli.Context) error {
return nil return nil
} }
func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) { func applyMetricConfig(ctx *cli.Context, cfg *aiigoConfig) {
if ctx.IsSet(utils.MetricsEnabledFlag.Name) { if ctx.IsSet(utils.MetricsEnabledFlag.Name) {
cfg.Metrics.Enabled = ctx.Bool(utils.MetricsEnabledFlag.Name) cfg.Metrics.Enabled = ctx.Bool(utils.MetricsEnabledFlag.Name)
} }

View file

@ -35,9 +35,9 @@ var (
Usage: "Start an interactive JavaScript environment", Usage: "Start an interactive JavaScript environment",
Flags: slices.Concat(nodeFlags, rpcFlags, consoleFlags), Flags: slices.Concat(nodeFlags, rpcFlags, consoleFlags),
Description: ` Description: `
The Geth console is an interactive shell for the JavaScript runtime environment The Aiigo console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console.`, See https://aiigo.ethereum.org/docs/interacting-with-aiigo/javascript-console.`,
} }
attachCommand = &cli.Command{ attachCommand = &cli.Command{
@ -47,10 +47,10 @@ See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console.`,
ArgsUsage: "[endpoint]", ArgsUsage: "[endpoint]",
Flags: slices.Concat([]cli.Flag{utils.DataDirFlag, utils.HttpHeaderFlag}, consoleFlags), Flags: slices.Concat([]cli.Flag{utils.DataDirFlag, utils.HttpHeaderFlag}, consoleFlags),
Description: ` Description: `
The Geth console is an interactive shell for the JavaScript runtime environment The Aiigo console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console. See https://aiigo.ethereum.org/docs/interacting-with-aiigo/javascript-console.
This command allows to open a console on a running geth node.`, This command allows to open a console on a running aiigo node.`,
} }
javascriptCommand = &cli.Command{ javascriptCommand = &cli.Command{
@ -61,11 +61,11 @@ This command allows to open a console on a running geth node.`,
Flags: slices.Concat(nodeFlags, consoleFlags), Flags: slices.Concat(nodeFlags, consoleFlags),
Description: ` Description: `
The JavaScript VM exposes a node admin interface as well as the Ðapp The JavaScript VM exposes a node admin interface as well as the Ðapp
JavaScript API. See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console`, JavaScript API. See https://aiigo.ethereum.org/docs/interacting-with-aiigo/javascript-console`,
} }
) )
// localConsole starts a new geth node, attaching a JavaScript console to it at the // localConsole starts a new aiigo node, attaching a JavaScript console to it at the
// same time. // same time.
func localConsole(ctx *cli.Context) error { func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags // Create and start the node based on the CLI flags
@ -107,7 +107,7 @@ func localConsole(ctx *cli.Context) error {
return nil return nil
} }
// remoteConsole will connect to a remote geth instance, attaching a JavaScript // remoteConsole will connect to a remote aiigo instance, attaching a JavaScript
// console to it. // console to it.
func remoteConsole(ctx *cli.Context) error { func remoteConsole(ctx *cli.Context) error {
if ctx.Args().Len() > 1 { if ctx.Args().Len() > 1 {
@ -121,7 +121,7 @@ func remoteConsole(ctx *cli.Context) error {
} }
client, err := utils.DialRPCWithHeaders(endpoint, ctx.StringSlice(utils.HttpHeaderFlag.Name)) client, err := utils.DialRPCWithHeaders(endpoint, ctx.StringSlice(utils.HttpHeaderFlag.Name))
if err != nil { if err != nil {
utils.Fatalf("Unable to attach to remote geth: %v", err) utils.Fatalf("Unable to attach to remote aiigo: %v", err)
} }
config := console.Config{ config := console.Config{
DataDir: utils.MakeDataDir(ctx), DataDir: utils.MakeDataDir(ctx),
@ -146,7 +146,7 @@ func remoteConsole(ctx *cli.Context) error {
return nil return nil
} }
// ephemeralConsole starts a new geth node, attaches an ephemeral JavaScript // ephemeralConsole starts a new aiigo node, attaches an ephemeral JavaScript
// console to it, executes each of the files specified as arguments and tears // console to it, executes each of the files specified as arguments and tears
// everything down. // everything down.
func ephemeralConsole(ctx *cli.Context) error { func ephemeralConsole(ctx *cli.Context) error {
@ -155,6 +155,6 @@ func ephemeralConsole(ctx *cli.Context) error {
b.WriteString(fmt.Sprintf("loadScript('%s');", file)) b.WriteString(fmt.Sprintf("loadScript('%s');", file))
} }
utils.Fatalf(`The "js" command is deprecated. Please use the following instead: utils.Fatalf(`The "js" command is deprecated. Please use the following instead:
geth --exec "%s" console`, b.String()) aiigo --exec "%s" console`, b.String())
return nil return nil
} }

View file

@ -34,17 +34,17 @@ const (
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0" httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
) )
// spawns geth with the given command line args, using a set of flags to minimise // spawns aiigo with the given command line args, using a set of flags to minimise
// memory and disk IO. If the args don't set --datadir, the // memory and disk IO. If the args don't set --datadir, the
// child g gets a temporary data directory. // child g gets a temporary data directory.
func runMinimalGeth(t *testing.T, args ...string) *testgeth { func runMinimalAiigo(t *testing.T, args ...string) *testaiigo {
// --holesky to make the 'writing genesis to disk' faster (no accounts) // --holesky to make the 'writing genesis to disk' faster (no accounts)
// --networkid=1337 to avoid cache bump // --networkid=1337 to avoid cache bump
// --syncmode=full to avoid allocating fast sync bloom // --syncmode=full to avoid allocating fast sync bloom
allArgs := []string{"--holesky", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0", allArgs := []string{"--holesky", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
"--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64", "--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64",
"--datadir.minfreedisk", "0"} "--datadir.minfreedisk", "0"}
return runGeth(t, append(allArgs, args...)...) return runAiigo(t, append(allArgs, args...)...)
} }
// Tests that a node embedded within a console can be started up properly and // Tests that a node embedded within a console can be started up properly and
@ -53,24 +53,24 @@ func TestConsoleWelcome(t *testing.T) {
t.Parallel() t.Parallel()
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
// Start a geth console, make sure it's cleaned up and terminate the console // Start a aiigo console, make sure it's cleaned up and terminate the console
geth := runMinimalGeth(t, "--miner.etherbase", coinbase, "console") aiigo := runMinimalAiigo(t, "--miner.etherbase", coinbase, "console")
// Gather all the infos the welcome message needs to contain // Gather all the infos the welcome message needs to contain
geth.SetTemplateFunc("goos", func() string { return runtime.GOOS }) aiigo.SetTemplateFunc("goos", func() string { return runtime.GOOS })
geth.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) aiigo.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
geth.SetTemplateFunc("gover", runtime.Version) aiigo.SetTemplateFunc("gover", runtime.Version)
geth.SetTemplateFunc("gethver", func() string { return version.WithCommit("", "") }) aiigo.SetTemplateFunc("aiigover", func() string { return version.WithCommit("", "") })
geth.SetTemplateFunc("niltime", func() string { aiigo.SetTemplateFunc("niltime", func() string {
return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
}) })
geth.SetTemplateFunc("apis", func() string { return ipcAPIs }) aiigo.SetTemplateFunc("apis", func() string { return ipcAPIs })
// Verify the actual welcome message to the required template // Verify the actual welcome message to the required template
geth.Expect(` aiigo.Expect(`
Welcome to the Geth JavaScript console! Welcome to the Aiigo JavaScript console!
instance: Geth/v{{gethver}}/{{goos}}-{{goarch}}/{{gover}} instance: Aiigo/v{{aiigover}}/{{goos}}-{{goarch}}/{{gover}}
at block: 0 ({{niltime}}) at block: 0 ({{niltime}})
datadir: {{.Datadir}} datadir: {{.Datadir}}
modules: {{apis}} modules: {{apis}}
@ -78,7 +78,7 @@ at block: 0 ({{niltime}})
To exit, press ctrl-d or type exit To exit, press ctrl-d or type exit
> {{.InputLine "exit"}} > {{.InputLine "exit"}}
`) `)
geth.ExpectExit() aiigo.ExpectExit()
} }
// Tests that a console can be attached to a running node via various means. // Tests that a console can be attached to a running node via various means.
@ -90,38 +90,38 @@ func TestAttachWelcome(t *testing.T) {
) )
// Configure the instance for IPC attachment // Configure the instance for IPC attachment
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
ipc = `\\.\pipe\geth` + strconv.Itoa(trulyRandInt(100000, 999999)) ipc = `\\.\pipe\aiigo` + strconv.Itoa(trulyRandInt(100000, 999999))
} else { } else {
ipc = filepath.Join(t.TempDir(), "geth.ipc") ipc = filepath.Join(t.TempDir(), "aiigo.ipc")
} }
// And HTTP + WS attachment // And HTTP + WS attachment
p := trulyRandInt(1024, 65533) // Yeah, sometimes this will fail, sorry :P p := trulyRandInt(1024, 65533) // Yeah, sometimes this will fail, sorry :P
httpPort = strconv.Itoa(p) httpPort = strconv.Itoa(p)
wsPort = strconv.Itoa(p + 1) wsPort = strconv.Itoa(p + 1)
geth := runMinimalGeth(t, "--miner.etherbase", "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182", aiigo := runMinimalAiigo(t, "--miner.etherbase", "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182",
"--ipcpath", ipc, "--ipcpath", ipc,
"--http", "--http.port", httpPort, "--http", "--http.port", httpPort,
"--ws", "--ws.port", wsPort) "--ws", "--ws.port", wsPort)
t.Run("ipc", func(t *testing.T) { t.Run("ipc", func(t *testing.T) {
waitForEndpoint(t, ipc, 4*time.Second) waitForEndpoint(t, ipc, 4*time.Second)
testAttachWelcome(t, geth, "ipc:"+ipc, ipcAPIs) testAttachWelcome(t, aiigo, "ipc:"+ipc, ipcAPIs)
}) })
t.Run("http", func(t *testing.T) { t.Run("http", func(t *testing.T) {
endpoint := "http://127.0.0.1:" + httpPort endpoint := "http://127.0.0.1:" + httpPort
waitForEndpoint(t, endpoint, 4*time.Second) waitForEndpoint(t, endpoint, 4*time.Second)
testAttachWelcome(t, geth, endpoint, httpAPIs) testAttachWelcome(t, aiigo, endpoint, httpAPIs)
}) })
t.Run("ws", func(t *testing.T) { t.Run("ws", func(t *testing.T) {
endpoint := "ws://127.0.0.1:" + wsPort endpoint := "ws://127.0.0.1:" + wsPort
waitForEndpoint(t, endpoint, 4*time.Second) waitForEndpoint(t, endpoint, 4*time.Second)
testAttachWelcome(t, geth, endpoint, httpAPIs) testAttachWelcome(t, aiigo, endpoint, httpAPIs)
}) })
geth.Kill() aiigo.Kill()
} }
func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { func testAttachWelcome(t *testing.T, aiigo *testaiigo, endpoint, apis string) {
// Attach to a running geth node and terminate immediately // Attach to a running aiigo node and terminate immediately
attach := runGeth(t, "attach", endpoint) attach := runAiigo(t, "attach", endpoint)
defer attach.ExpectExit() defer attach.ExpectExit()
attach.CloseStdin() attach.CloseStdin()
@ -129,19 +129,19 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
attach.SetTemplateFunc("goos", func() string { return runtime.GOOS }) attach.SetTemplateFunc("goos", func() string { return runtime.GOOS })
attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
attach.SetTemplateFunc("gover", runtime.Version) attach.SetTemplateFunc("gover", runtime.Version)
attach.SetTemplateFunc("gethver", func() string { return version.WithCommit("", "") }) attach.SetTemplateFunc("aiigover", func() string { return version.WithCommit("", "") })
attach.SetTemplateFunc("niltime", func() string { attach.SetTemplateFunc("niltime", func() string {
return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
}) })
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") }) attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir }) attach.SetTemplateFunc("datadir", func() string { return aiigo.Datadir })
attach.SetTemplateFunc("apis", func() string { return apis }) attach.SetTemplateFunc("apis", func() string { return apis })
// Verify the actual welcome message to the required template // Verify the actual welcome message to the required template
attach.Expect(` attach.Expect(`
Welcome to the Geth JavaScript console! Welcome to the Aiigo JavaScript console!
instance: Geth/v{{gethver}}/{{goos}}-{{goarch}}/{{gover}} instance: Aiigo/v{{aiigover}}/{{goos}}-{{goarch}}/{{gover}}
at block: 0 ({{niltime}}){{if ipc}} at block: 0 ({{niltime}}){{if ipc}}
datadir: {{datadir}}{{end}} datadir: {{datadir}}{{end}}
modules: {{apis}} modules: {{apis}}

View file

@ -25,13 +25,13 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
// TestExport does a basic test of "geth export", exporting the test-genesis. // TestExport does a basic test of "aiigo export", exporting the test-genesis.
func TestExport(t *testing.T) { func TestExport(t *testing.T) {
t.Parallel() t.Parallel()
outfile := fmt.Sprintf("%v/testExport.out", t.TempDir()) outfile := fmt.Sprintf("%v/testExport.out", t.TempDir())
geth := runGeth(t, "--datadir", initGeth(t), "export", outfile) aiigo := runAiigo(t, "--datadir", initAiigo(t), "export", outfile)
geth.WaitExit() aiigo.WaitExit()
if have, want := geth.ExitStatus(), 0; have != want { if have, want := aiigo.ExitStatus(), 0; have != want {
t.Errorf("exit error, have %d want %d", have, want) t.Errorf("exit error, have %d want %d", have, want)
} }
have, err := os.ReadFile(outfile) have, err := os.ReadFile(outfile)

View file

@ -72,7 +72,7 @@ var customGenesisTests = []struct {
}, },
} }
// Tests that initializing Geth with a custom genesis block and chain definitions // Tests that initializing Aiigo with a custom genesis block and chain definitions
// work properly. // work properly.
func TestCustomGenesis(t *testing.T) { func TestCustomGenesis(t *testing.T) {
t.Parallel() t.Parallel()
@ -85,15 +85,15 @@ func TestCustomGenesis(t *testing.T) {
if err := os.WriteFile(json, []byte(tt.genesis), 0600); err != nil { if err := os.WriteFile(json, []byte(tt.genesis), 0600); err != nil {
t.Fatalf("test %d: failed to write genesis file: %v", i, err) t.Fatalf("test %d: failed to write genesis file: %v", i, err)
} }
runGeth(t, "--datadir", datadir, "init", json).WaitExit() runAiigo(t, "--datadir", datadir, "init", json).WaitExit()
// Query the custom genesis block // Query the custom genesis block
geth := runGeth(t, "--networkid", "1337", "--syncmode=full", "--cache", "16", aiigo := runAiigo(t, "--networkid", "1337", "--syncmode=full", "--cache", "16",
"--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0", "--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0",
"--nodiscover", "--nat", "none", "--ipcdisable", "--nodiscover", "--nat", "none", "--ipcdisable",
"--exec", tt.query, "console") "--exec", tt.query, "console")
geth.ExpectRegexp(tt.result) aiigo.ExpectRegexp(tt.result)
geth.ExpectExit() aiigo.ExpectExit()
} }
} }
@ -135,18 +135,18 @@ func TestCustomBackend(t *testing.T) {
} }
{ // Init { // Init
args := append(tt.initArgs, "--datadir", datadir, "init", json) args := append(tt.initArgs, "--datadir", datadir, "init", json)
geth := runGeth(t, args...) aiigo := runAiigo(t, args...)
geth.ExpectRegexp(tt.initExpect) aiigo.ExpectRegexp(tt.initExpect)
geth.ExpectExit() aiigo.ExpectExit()
} }
{ // Exec + query { // Exec + query
args := append(tt.execArgs, "--networkid", "1337", "--syncmode=full", "--cache", "16", args := append(tt.execArgs, "--networkid", "1337", "--syncmode=full", "--cache", "16",
"--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0", "--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0",
"--nodiscover", "--nat", "none", "--ipcdisable", "--nodiscover", "--nat", "none", "--ipcdisable",
"--exec", "eth.getBlock(0).nonce", "console") "--exec", "eth.getBlock(0).nonce", "console")
geth := runGeth(t, args...) aiigo := runAiigo(t, args...)
geth.ExpectRegexp(tt.execExpect) aiigo.ExpectRegexp(tt.execExpect)
geth.ExpectExit() aiigo.ExpectExit()
} }
return nil return nil
} }

View file

@ -36,7 +36,7 @@ import (
func runSelf(args ...string) ([]byte, error) { func runSelf(args ...string) ([]byte, error) {
cmd := &exec.Cmd{ cmd := &exec.Cmd{
Path: reexec.Self(), Path: reexec.Self(),
Args: append([]string{"geth-test"}, args...), Args: append([]string{"aiigo-test"}, args...),
} }
return cmd.CombinedOutput() return cmd.CombinedOutput()
} }

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// geth is a command-line client for Ethereum. // aiigo is a command-line client for Ethereum.
package main package main
import ( import (
@ -46,7 +46,7 @@ import (
) )
const ( const (
clientIdentifier = "geth" // Client identifier to advertise over the network clientIdentifier = "aiigo" // Client identifier to advertise over the network
) )
var ( var (
@ -212,8 +212,8 @@ var (
var app = flags.NewApp("the go-ethereum command line interface") var app = flags.NewApp("the go-ethereum command line interface")
func init() { func init() {
// Initialize the CLI app and start Geth // Initialize the CLI app and start Aiigo
app.Action = geth app.Action = aiigo
app.Commands = []*cli.Command{ app.Commands = []*cli.Command{
// See chaincmd.go: // See chaincmd.go:
initCommand, initCommand,
@ -291,17 +291,17 @@ func prepare(ctx *cli.Context) {
// If we're running a known preset, log it for convenience. // If we're running a known preset, log it for convenience.
switch { switch {
case ctx.IsSet(utils.SepoliaFlag.Name): case ctx.IsSet(utils.SepoliaFlag.Name):
log.Info("Starting Geth on Sepolia testnet...") log.Info("Starting Aiigo on Sepolia testnet...")
case ctx.IsSet(utils.HoleskyFlag.Name): case ctx.IsSet(utils.HoleskyFlag.Name):
log.Info("Starting Geth on Holesky testnet...") log.Info("Starting Aiigo on Holesky testnet...")
case ctx.IsSet(utils.HoodiFlag.Name): case ctx.IsSet(utils.HoodiFlag.Name):
log.Info("Starting Geth on Hoodi testnet...") log.Info("Starting Aiigo on Hoodi testnet...")
case ctx.IsSet(utils.DeveloperFlag.Name): case ctx.IsSet(utils.DeveloperFlag.Name):
log.Info("Starting Geth in ephemeral dev mode...") log.Info("Starting Aiigo in ephemeral dev mode...")
log.Warn(`You are running Geth in --dev mode. Please note the following: log.Warn(`You are running Aiigo in --dev mode. Please note the following:
1. This mode is only intended for fast, iterative development without assumptions on 1. This mode is only intended for fast, iterative development without assumptions on
security or persistence. security or persistence.
@ -318,7 +318,7 @@ func prepare(ctx *cli.Context) {
`) `)
case !ctx.IsSet(utils.NetworkIdFlag.Name): case !ctx.IsSet(utils.NetworkIdFlag.Name):
log.Info("Starting Geth on Ethereum mainnet...") log.Info("Starting Aiigo on Ethereum mainnet...")
} }
// If we're a full node on mainnet without --cache specified, bump default cache allowance // If we're a full node on mainnet without --cache specified, bump default cache allowance
if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) { if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {
@ -334,10 +334,10 @@ func prepare(ctx *cli.Context) {
} }
} }
// geth is the main entry point into the system if no special subcommand is run. // aiigo is the main entry point into the system if no special subcommand is run.
// It creates a default node based on the command line arguments and runs it in // It creates a default node based on the command line arguments and runs it in
// blocking mode, waiting for it to be shut down. // blocking mode, waiting for it to be shut down.
func geth(ctx *cli.Context) error { func aiigo(ctx *cli.Context) error {
if args := ctx.Args().Slice(); len(args) > 0 { if args := ctx.Args().Slice(); len(args) > 0 {
return fmt.Errorf("invalid command: %q", args[0]) return fmt.Errorf("invalid command: %q", args[0])
} }
@ -365,7 +365,7 @@ func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) {
events := make(chan accounts.WalletEvent, 16) events := make(chan accounts.WalletEvent, 16)
stack.AccountManager().Subscribe(events) stack.AccountManager().Subscribe(events)
// Create a client to interact with local geth node. // Create a client to interact with local aiigo node.
rpcClient := stack.Attach() rpcClient := stack.Attach()
ethClient := ethclient.NewClient(rpcClient) ethClient := ethclient.NewClient(rpcClient)

View file

@ -30,7 +30,7 @@ var (
VersionCheckUrlFlag = &cli.StringFlag{ VersionCheckUrlFlag = &cli.StringFlag{
Name: "check.url", Name: "check.url",
Usage: "URL to use when checking vulnerabilities", Usage: "URL to use when checking vulnerabilities",
Value: "https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json", Value: "https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities.json",
} }
VersionCheckVersionFlag = &cli.StringFlag{ VersionCheckVersionFlag = &cli.StringFlag{
Name: "check.version", Name: "check.version",
@ -53,10 +53,10 @@ The output of this command is supposed to be machine-readable.
VersionCheckVersionFlag, VersionCheckVersionFlag,
}, },
Name: "version-check", Name: "version-check",
Usage: "Checks (online) for known Geth security vulnerabilities", Usage: "Checks (online) for known Aiigo security vulnerabilities",
ArgsUsage: "<versionstring (optional)>", ArgsUsage: "<versionstring (optional)>",
Description: ` Description: `
The version-check command fetches vulnerability-information from https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json, The version-check command fetches vulnerability-information from https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities.json,
and displays information about any security vulnerabilities that affect the currently executing version. and displays information about any security vulnerabilities that affect the currently executing version.
`, `,
} }
@ -88,17 +88,17 @@ func printVersion(ctx *cli.Context) error {
} }
func license(_ *cli.Context) error { func license(_ *cli.Context) error {
fmt.Println(`Geth is free software: you can redistribute it and/or modify fmt.Println(`Aiigo is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Geth is distributed in the hope that it will be useful, Aiigo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with geth. If not, see <http://www.gnu.org/licenses/>.`) along with aiigo. If not, see <http://www.gnu.org/licenses/>.`)
return nil return nil
} }

View file

@ -28,7 +28,7 @@ import (
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
type testgeth struct { type testaiigo struct {
*cmdtest.TestCmd *cmdtest.TestCmd
// template variables for expect // template variables for expect
@ -37,8 +37,8 @@ type testgeth struct {
} }
func init() { func init() {
// Run the app if we've been exec'd as "geth-test" in runGeth. // Run the app if we've been exec'd as "aiigo-test" in runAiigo.
reexec.Register("geth-test", func() { reexec.Register("aiigo-test", func() {
if err := app.Run(os.Args); err != nil { if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)
@ -55,19 +55,19 @@ func TestMain(m *testing.M) {
os.Exit(m.Run()) os.Exit(m.Run())
} }
func initGeth(t *testing.T) string { func initAiigo(t *testing.T) string {
args := []string{"--networkid=42", "init", "./testdata/clique.json"} args := []string{"--networkid=42", "init", "./testdata/clique.json"}
t.Logf("Initializing geth: %v ", args) t.Logf("Initializing aiigo: %v ", args)
g := runGeth(t, args...) g := runAiigo(t, args...)
datadir := g.Datadir datadir := g.Datadir
g.WaitExit() g.WaitExit()
return datadir return datadir
} }
// spawns geth with the given command line args. If the args don't set --datadir, the // spawns aiigo with the given command line args. If the args don't set --datadir, the
// child g gets a temporary data directory. // child g gets a temporary data directory.
func runGeth(t *testing.T, args ...string) *testgeth { func runAiigo(t *testing.T, args ...string) *testaiigo {
tt := &testgeth{} tt := &testaiigo{}
tt.TestCmd = cmdtest.NewTestCmd(t, tt) tt.TestCmd = cmdtest.NewTestCmd(t, tt)
for i, arg := range args { for i, arg := range args {
switch arg { switch arg {
@ -87,9 +87,9 @@ func runGeth(t *testing.T, args ...string) *testgeth {
args = append([]string{"--datadir", tt.Datadir}, args...) args = append([]string{"--datadir", tt.Datadir}, args...)
} }
// Boot "geth". This actually runs the test binary but the TestMain // Boot "aiigo". This actually runs the test binary but the TestMain
// function will prevent any tests from running. // function will prevent any tests from running.
tt.Run("geth-test", args...) tt.Run("aiigo-test", args...)
return tt return tt
} }

View file

@ -54,7 +54,7 @@ var (
utils.BloomFilterSizeFlag, utils.BloomFilterSizeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot prune-state <state-root> aiigo snapshot prune-state <state-root>
will prune historical state data with the help of the state snapshot. will prune historical state data with the help of the state snapshot.
All trie nodes and contract codes that do not belong to the specified All trie nodes and contract codes that do not belong to the specified
version state will be deleted from the database. After pruning, only version state will be deleted from the database. After pruning, only
@ -72,7 +72,7 @@ WARNING: it's only supported in hash mode(--state.scheme=hash)".
Action: verifyState, Action: verifyState,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot verify-state <state-root> aiigo snapshot verify-state <state-root>
will traverse the whole accounts and storages set based on the specified will traverse the whole accounts and storages set based on the specified
snapshot and recalculate the root hash of state for verification. snapshot and recalculate the root hash of state for verification.
In other words, this command does the snapshot to trie conversion. In other words, this command does the snapshot to trie conversion.
@ -85,7 +85,7 @@ In other words, this command does the snapshot to trie conversion.
Action: checkDanglingStorage, Action: checkDanglingStorage,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot check-dangling-storage <state-root> traverses the snap storage aiigo snapshot check-dangling-storage <state-root> traverses the snap storage
data, and verifies that all snapshot storage data has a corresponding account. data, and verifies that all snapshot storage data has a corresponding account.
`, `,
}, },
@ -96,7 +96,7 @@ data, and verifies that all snapshot storage data has a corresponding account.
Action: checkAccount, Action: checkAccount,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot inspect-account <address | hash> checks all snapshot layers and prints out aiigo snapshot inspect-account <address | hash> checks all snapshot layers and prints out
information about the specified address. information about the specified address.
`, `,
}, },
@ -107,7 +107,7 @@ information about the specified address.
Action: traverseState, Action: traverseState,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot traverse-state <state-root> aiigo snapshot traverse-state <state-root>
will traverse the whole state from the given state root and will abort if any will traverse the whole state from the given state root and will abort if any
referenced trie node or contract code is missing. This command can be used for referenced trie node or contract code is missing. This command can be used for
state integrity verification. The default checking target is the HEAD state. state integrity verification. The default checking target is the HEAD state.
@ -122,7 +122,7 @@ It's also usable without snapshot enabled.
Action: traverseRawState, Action: traverseRawState,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot traverse-rawstate <state-root> aiigo snapshot traverse-rawstate <state-root>
will traverse the whole state from the given root and will abort if any referenced will traverse the whole state from the given root and will abort if any referenced
trie node or contract code is missing. This command can be used for state integrity trie node or contract code is missing. This command can be used for state integrity
verification. The default checking target is the HEAD state. It's basically identical verification. The default checking target is the HEAD state. It's basically identical
@ -133,7 +133,7 @@ It's also usable without snapshot enabled.
}, },
{ {
Name: "dump", Name: "dump",
Usage: "Dump a specific block from storage (same as 'geth dump' but using snapshots)", Usage: "Dump a specific block from storage (same as 'aiigo dump' but using snapshots)",
ArgsUsage: "[? <blockHash> | <blockNum>]", ArgsUsage: "[? <blockHash> | <blockNum>]",
Action: dumpState, Action: dumpState,
Flags: slices.Concat([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
@ -143,7 +143,7 @@ It's also usable without snapshot enabled.
utils.DumpLimitFlag, utils.DumpLimitFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
This command is semantically equivalent to 'geth dump', but uses the snapshots This command is semantically equivalent to 'aiigo dump', but uses the snapshots
as the backend data source, making this command a lot faster. as the backend data source, making this command a lot faster.
The argument is interpreted as block number or hash. If none is provided, the latest The argument is interpreted as block number or hash. If none is provided, the latest

View file

@ -6,56 +6,56 @@
"description": "A mining flaw could cause miners to erroneously calculate PoW, due to an index overflow, if DAG size is exceeding the maximum 32 bit unsigned value.\n\nThis occurred on the ETC chain on 2020-11-06. This is likely to trigger for ETH mainnet around block `11550000`/epoch `385`, slated to occur early January 2021.\n\nThis issue is relevant only for miners, non-mining nodes are unaffected, since non-mining nodes use a smaller verification cache instead of a full DAG.", "description": "A mining flaw could cause miners to erroneously calculate PoW, due to an index overflow, if DAG size is exceeding the maximum 32 bit unsigned value.\n\nThis occurred on the ETC chain on 2020-11-06. This is likely to trigger for ETH mainnet around block `11550000`/epoch `385`, slated to occur early January 2021.\n\nThis issue is relevant only for miners, non-mining nodes are unaffected, since non-mining nodes use a smaller verification cache instead of a full DAG.",
"links": [ "links": [
"https://github.com/ethereum/go-ethereum/pull/21793", "https://github.com/ethereum/go-ethereum/pull/21793",
"https://blog.ethereum.org/2020/11/12/geth_security_release/", "https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://github.com/ethereum/go-ethereum/commit/567d41d9363706b4b13ce0903804e8acf214af49" "https://github.com/ethereum/go-ethereum/commit/567d41d9363706b4b13ce0903804e8acf214af49"
], ],
"introduced": "v1.6.0", "introduced": "v1.6.0",
"fixed": "v1.9.24", "fixed": "v1.9.24",
"published": "2020-11-12", "published": "2020-11-12",
"severity": "Medium", "severity": "Medium",
"check": "Geth\\/v1\\.(6|7|8)\\..*|Geth\\/v1\\.9\\.2(1|2|3)-.*" "check": "Aiigo\\/v1\\.(6|7|8)\\..*|Aiigo\\/v1\\.9\\.2(1|2|3)-.*"
}, },
{ {
"name": "GoCrash", "name": "GoCrash",
"uid": "GETH-2020-02", "uid": "GETH-2020-02",
"summary": "A denial-of-service issue can be used to crash Geth nodes during block processing, due to an underlying bug in Go (CVE-2020-28362) versions < `1.15.5`, or `<1.14.12`", "summary": "A denial-of-service issue can be used to crash Aiigo nodes during block processing, due to an underlying bug in Go (CVE-2020-28362) versions < `1.15.5`, or `<1.14.12`",
"description": "The DoS issue can be used to crash all Geth nodes during block processing, the effects of which would be that a major part of the Ethereum network went offline.\n\nOutside of Go-Ethereum, the issue is most likely relevant for all forks of Geth (such as TurboGeth or ETCs core-geth) which is built with versions of Go which contains the vulnerability.", "description": "The DoS issue can be used to crash all Aiigo nodes during block processing, the effects of which would be that a major part of the Ethereum network went offline.\n\nOutside of Go-Ethereum, the issue is most likely relevant for all forks of Aiigo (such as TurboAiigo or ETCs core-aiigo) which is built with versions of Go which contains the vulnerability.",
"links": [ "links": [
"https://blog.ethereum.org/2020/11/12/geth_security_release/", "https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://groups.google.com/g/golang-announce/c/NpBGTTmKzpM", "https://groups.google.com/g/golang-announce/c/NpBGTTmKzpM",
"https://github.com/golang/go/issues/42552" "https://github.com/golang/go/issues/42552"
], ],
"fixed": "v1.9.24", "fixed": "v1.9.24",
"published": "2020-11-12", "published": "2020-11-12",
"severity": "Critical", "severity": "Critical",
"check": "Geth.*\\/go1\\.(11(.*)|12(.*)|13(.*)|14|14\\.(\\d|10|11|)|15|15\\.[0-4])$" "check": "Aiigo.*\\/go1\\.(11(.*)|12(.*)|13(.*)|14|14\\.(\\d|10|11|)|15|15\\.[0-4])$"
}, },
{ {
"name": "ShallowCopy", "name": "ShallowCopy",
"uid": "GETH-2020-03", "uid": "GETH-2020-03",
"summary": "A consensus flaw in Geth, related to `datacopy` precompile", "summary": "A consensus flaw in Aiigo, related to `datacopy` precompile",
"description": "Geth erroneously performed a 'shallow' copy when the precompiled `datacopy` (at `0x00...04`) was invoked. An attacker could deploy a contract that uses the shallow copy to corrupt the contents of the `RETURNDATA`, thus causing a consensus failure.", "description": "Aiigo erroneously performed a 'shallow' copy when the precompiled `datacopy` (at `0x00...04`) was invoked. An attacker could deploy a contract that uses the shallow copy to corrupt the contents of the `RETURNDATA`, thus causing a consensus failure.",
"links": [ "links": [
"https://blog.ethereum.org/2020/11/12/geth_security_release/" "https://blog.ethereum.org/2020/11/12/aiigo_security_release/"
], ],
"introduced": "v1.9.7", "introduced": "v1.9.7",
"fixed": "v1.9.17", "fixed": "v1.9.17",
"published": "2020-11-12", "published": "2020-11-12",
"severity": "Critical", "severity": "Critical",
"check": "Geth\\/v1\\.9\\.(7|8|9|10|11|12|13|14|15|16).*$" "check": "Aiigo\\/v1\\.9\\.(7|8|9|10|11|12|13|14|15|16).*$"
}, },
{ {
"name": "GethCrash", "name": "AiigoCrash",
"uid": "GETH-2020-04", "uid": "GETH-2020-04",
"summary": "A denial-of-service issue can be used to crash Geth nodes during block processing", "summary": "A denial-of-service issue can be used to crash Aiigo nodes during block processing",
"description": "Full details to be disclosed at a later date", "description": "Full details to be disclosed at a later date",
"links": [ "links": [
"https://blog.ethereum.org/2020/11/12/geth_security_release/" "https://blog.ethereum.org/2020/11/12/aiigo_security_release/"
], ],
"introduced": "v1.9.16", "introduced": "v1.9.16",
"fixed": "v1.9.18", "fixed": "v1.9.18",
"published": "2020-11-12", "published": "2020-11-12",
"severity": "Critical", "severity": "Critical",
"check": "Geth\\/v1\\.9.(16|17).*$" "check": "Aiigo\\/v1\\.9.(16|17).*$"
} }
] ]

View file

@ -6,7 +6,7 @@
"description": "A mining flaw could cause miners to erroneously calculate PoW, due to an index overflow, if DAG size is exceeding the maximum 32 bit unsigned value.\n\nThis occurred on the ETC chain on 2020-11-06. This is likely to trigger for ETH mainnet around block `11550000`/epoch `385`, slated to occur early January 2021.\n\nThis issue is relevant only for miners, non-mining nodes are unaffected, since non-mining nodes use a smaller verification cache instead of a full DAG.", "description": "A mining flaw could cause miners to erroneously calculate PoW, due to an index overflow, if DAG size is exceeding the maximum 32 bit unsigned value.\n\nThis occurred on the ETC chain on 2020-11-06. This is likely to trigger for ETH mainnet around block `11550000`/epoch `385`, slated to occur early January 2021.\n\nThis issue is relevant only for miners, non-mining nodes are unaffected, since non-mining nodes use a smaller verification cache instead of a full DAG.",
"links": [ "links": [
"https://github.com/ethereum/go-ethereum/pull/21793", "https://github.com/ethereum/go-ethereum/pull/21793",
"https://blog.ethereum.org/2020/11/12/geth_security_release/", "https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://github.com/ethereum/go-ethereum/commit/567d41d9363706b4b13ce0903804e8acf214af49", "https://github.com/ethereum/go-ethereum/commit/567d41d9363706b4b13ce0903804e8acf214af49",
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-v592-xf75-856p" "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-v592-xf75-856p"
], ],
@ -15,15 +15,15 @@
"published": "2020-11-12", "published": "2020-11-12",
"severity": "Medium", "severity": "Medium",
"CVE": "CVE-2020-26240", "CVE": "CVE-2020-26240",
"check": "Geth\\/v1\\.(6|7|8)\\..*|Geth\\/v1\\.9\\.\\d-.*|Geth\\/v1\\.9\\.1.*|Geth\\/v1\\.9\\.2(0|1|2|3)-.*" "check": "Aiigo\\/v1\\.(6|7|8)\\..*|Aiigo\\/v1\\.9\\.\\d-.*|Aiigo\\/v1\\.9\\.1.*|Aiigo\\/v1\\.9\\.2(0|1|2|3)-.*"
}, },
{ {
"name": "Denial of service due to Go CVE-2020-28362", "name": "Denial of service due to Go CVE-2020-28362",
"uid": "GETH-2020-02", "uid": "GETH-2020-02",
"summary": "A denial-of-service issue can be used to crash Geth nodes during block processing, due to an underlying bug in Go (CVE-2020-28362) versions < `1.15.5`, or `<1.14.12`", "summary": "A denial-of-service issue can be used to crash Aiigo nodes during block processing, due to an underlying bug in Go (CVE-2020-28362) versions < `1.15.5`, or `<1.14.12`",
"description": "The DoS issue can be used to crash all Geth nodes during block processing, the effects of which would be that a major part of the Ethereum network went offline.\n\nOutside of Go-Ethereum, the issue is most likely relevant for all forks of Geth (such as TurboGeth or ETCs core-geth) which is built with versions of Go which contains the vulnerability.", "description": "The DoS issue can be used to crash all Aiigo nodes during block processing, the effects of which would be that a major part of the Ethereum network went offline.\n\nOutside of Go-Ethereum, the issue is most likely relevant for all forks of Aiigo (such as TurboAiigo or ETCs core-aiigo) which is built with versions of Go which contains the vulnerability.",
"links": [ "links": [
"https://blog.ethereum.org/2020/11/12/geth_security_release/", "https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://groups.google.com/g/golang-announce/c/NpBGTTmKzpM", "https://groups.google.com/g/golang-announce/c/NpBGTTmKzpM",
"https://github.com/golang/go/issues/42552", "https://github.com/golang/go/issues/42552",
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-m6gx-rhvj-fh52" "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-m6gx-rhvj-fh52"
@ -33,15 +33,15 @@
"published": "2020-11-12", "published": "2020-11-12",
"severity": "Critical", "severity": "Critical",
"CVE": "CVE-2020-28362", "CVE": "CVE-2020-28362",
"check": "Geth.*\\/go1\\.(11(.*)|12(.*)|13(.*)|14|14\\.(\\d|10|11|)|15|15\\.[0-4])$" "check": "Aiigo.*\\/go1\\.(11(.*)|12(.*)|13(.*)|14|14\\.(\\d|10|11|)|15|15\\.[0-4])$"
}, },
{ {
"name": "ShallowCopy", "name": "ShallowCopy",
"uid": "GETH-2020-03", "uid": "GETH-2020-03",
"summary": "A consensus flaw in Geth, related to `datacopy` precompile", "summary": "A consensus flaw in Aiigo, related to `datacopy` precompile",
"description": "Geth erroneously performed a 'shallow' copy when the precompiled `datacopy` (at `0x00...04`) was invoked. An attacker could deploy a contract that uses the shallow copy to corrupt the contents of the `RETURNDATA`, thus causing a consensus failure.", "description": "Aiigo erroneously performed a 'shallow' copy when the precompiled `datacopy` (at `0x00...04`) was invoked. An attacker could deploy a contract that uses the shallow copy to corrupt the contents of the `RETURNDATA`, thus causing a consensus failure.",
"links": [ "links": [
"https://blog.ethereum.org/2020/11/12/geth_security_release/", "https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-69v6-xc2j-r2jf" "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-69v6-xc2j-r2jf"
], ],
"introduced": "v1.9.7", "introduced": "v1.9.7",
@ -49,15 +49,15 @@
"published": "2020-11-12", "published": "2020-11-12",
"severity": "Critical", "severity": "Critical",
"CVE": "CVE-2020-26241", "CVE": "CVE-2020-26241",
"check": "Geth\\/v1\\.9\\.(7|8|9|10|11|12|13|14|15|16).*$" "check": "Aiigo\\/v1\\.9\\.(7|8|9|10|11|12|13|14|15|16).*$"
}, },
{ {
"name": "Geth DoS via MULMOD", "name": "Aiigo DoS via MULMOD",
"uid": "GETH-2020-04", "uid": "GETH-2020-04",
"summary": "A denial-of-service issue can be used to crash Geth nodes during block processing", "summary": "A denial-of-service issue can be used to crash Aiigo nodes during block processing",
"description": "Affected versions suffer from a vulnerability which can be exploited through the `MULMOD` operation, by specifying a modulo of `0`: `mulmod(a,b,0)`, causing a `panic` in the underlying library. \nThe crash was in the `uint256` library, where a buffer [underflowed](https://github.com/holiman/uint256/blob/4ce82e695c10ddad57215bdbeafb68b8c5df2c30/uint256.go#L442).\n\n\tif `d == 0`, `dLen` remains `0`\n\nand https://github.com/holiman/uint256/blob/4ce82e695c10ddad57215bdbeafb68b8c5df2c30/uint256.go#L451 will try to access index `[-1]`.\n\nThe `uint256` library was first merged in this [commit](https://github.com/ethereum/go-ethereum/commit/cf6674539c589f80031f3371a71c6a80addbe454), on 2020-06-08. \nExploiting this vulnerabilty would cause all vulnerable nodes to drop off the network. \n\nThe issue was brought to our attention through a [bug report](https://github.com/ethereum/go-ethereum/issues/21367), showing a `panic` occurring on sync from genesis on the Ropsten network.\n \nIt was estimated that the least obvious way to fix this would be to merge the fix into `uint256`, make a new release of that library and then update the geth-dependency.\n", "description": "Affected versions suffer from a vulnerability which can be exploited through the `MULMOD` operation, by specifying a modulo of `0`: `mulmod(a,b,0)`, causing a `panic` in the underlying library. \nThe crash was in the `uint256` library, where a buffer [underflowed](https://github.com/holiman/uint256/blob/4ce82e695c10ddad57215bdbeafb68b8c5df2c30/uint256.go#L442).\n\n\tif `d == 0`, `dLen` remains `0`\n\nand https://github.com/holiman/uint256/blob/4ce82e695c10ddad57215bdbeafb68b8c5df2c30/uint256.go#L451 will try to access index `[-1]`.\n\nThe `uint256` library was first merged in this [commit](https://github.com/ethereum/go-ethereum/commit/cf6674539c589f80031f3371a71c6a80addbe454), on 2020-06-08. \nExploiting this vulnerabilty would cause all vulnerable nodes to drop off the network. \n\nThe issue was brought to our attention through a [bug report](https://github.com/ethereum/go-ethereum/issues/21367), showing a `panic` occurring on sync from genesis on the Ropsten network.\n \nIt was estimated that the least obvious way to fix this would be to merge the fix into `uint256`, make a new release of that library and then update the aiigo-dependency.\n",
"links": [ "links": [
"https://blog.ethereum.org/2020/11/12/geth_security_release/", "https://blog.ethereum.org/2020/11/12/aiigo_security_release/",
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-jm5c-rv3w-w83m", "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-jm5c-rv3w-w83m",
"https://github.com/holiman/uint256/releases/tag/v1.1.1", "https://github.com/holiman/uint256/releases/tag/v1.1.1",
"https://github.com/holiman/uint256/pull/80", "https://github.com/holiman/uint256/pull/80",
@ -68,13 +68,13 @@
"published": "2020-11-12", "published": "2020-11-12",
"severity": "Critical", "severity": "Critical",
"CVE": "CVE-2020-26242", "CVE": "CVE-2020-26242",
"check": "Geth\\/v1\\.9.(16|17).*$" "check": "Aiigo\\/v1\\.9.(16|17).*$"
}, },
{ {
"name": "LES Server DoS via GetProofsV2", "name": "LES Server DoS via GetProofsV2",
"uid": "GETH-2020-05", "uid": "GETH-2020-05",
"summary": "A DoS vulnerability can make a LES server crash.", "summary": "A DoS vulnerability can make a LES server crash.",
"description": "A DoS vulnerability can make a LES server crash via malicious GetProofsV2 request from a connected LES client.\n\nThe vulnerability was patched in #21896.\n\nThis vulnerability only concern users explicitly running geth as a light server", "description": "A DoS vulnerability can make a LES server crash via malicious GetProofsV2 request from a connected LES client.\n\nThe vulnerability was patched in #21896.\n\nThis vulnerability only concern users explicitly running aiigo as a light server",
"links": [ "links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-r33q-22hv-j29q", "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-r33q-22hv-j29q",
"https://github.com/ethereum/go-ethereum/pull/21896" "https://github.com/ethereum/go-ethereum/pull/21896"
@ -84,22 +84,22 @@
"published": "2020-12-10", "published": "2020-12-10",
"severity": "Medium", "severity": "Medium",
"CVE": "CVE-2020-26264", "CVE": "CVE-2020-26264",
"check": "(Geth\\/v1\\.8\\.*)|(Geth\\/v1\\.9\\.\\d-.*)|(Geth\\/v1\\.9\\.1\\d-.*)|(Geth\\/v1\\.9\\.(20|21|22|23|24)-.*)$" "check": "(Aiigo\\/v1\\.8\\.*)|(Aiigo\\/v1\\.9\\.\\d-.*)|(Aiigo\\/v1\\.9\\.1\\d-.*)|(Aiigo\\/v1\\.9\\.(20|21|22|23|24)-.*)$"
}, },
{ {
"name": "SELFDESTRUCT-recreate consensus flaw", "name": "SELFDESTRUCT-recreate consensus flaw",
"uid": "GETH-2020-06", "uid": "GETH-2020-06",
"introduced": "v1.9.4", "introduced": "v1.9.4",
"fixed": "v1.9.20", "fixed": "v1.9.20",
"summary": "A consensus-vulnerability in Geth could cause a chain split, where vulnerable versions refuse to accept the canonical chain.", "summary": "A consensus-vulnerability in Aiigo could cause a chain split, where vulnerable versions refuse to accept the canonical chain.",
"description": "A flaw was repoted at 2020-08-11 by John Youngseok Yang (Software Platform Lab), where a particular sequence of transactions could cause a consensus failure.\n\n- Tx 1:\n - `sender` invokes `caller`.\n - `caller` invokes `0xaa`. `0xaa` has 3 wei, does a self-destruct-to-self\n - `caller` does a `1 wei` -call to `0xaa`, who thereby has 1 wei (the code in `0xaa` still executed, since the tx is still ongoing, but doesn't redo the selfdestruct, it takes a different path if callvalue is non-zero)\n\n-Tx 2:\n - `sender` does a 5-wei call to 0xaa. No exec (since no code). \n\nIn geth, the result would be that `0xaa` had `6 wei`, whereas OE reported (correctly) `5` wei. Furthermore, in geth, if the second tx was not executed, the `0xaa` would be destructed, resulting in `0 wei`. Thus obviously wrong. \n\nIt was determined that the root cause was this [commit](https://github.com/ethereum/go-ethereum/commit/223b950944f494a5b4e0957fd9f92c48b09037ad) from [this PR](https://github.com/ethereum/go-ethereum/pull/19953). The semantics of `createObject` was subtly changd, into returning a non-nil object (with `deleted=true`) where it previously did not if the account had been destructed. This return value caused the new object to inherit the old `balance`.\n", "description": "A flaw was repoted at 2020-08-11 by John Youngseok Yang (Software Platform Lab), where a particular sequence of transactions could cause a consensus failure.\n\n- Tx 1:\n - `sender` invokes `caller`.\n - `caller` invokes `0xaa`. `0xaa` has 3 wei, does a self-destruct-to-self\n - `caller` does a `1 wei` -call to `0xaa`, who thereby has 1 wei (the code in `0xaa` still executed, since the tx is still ongoing, but doesn't redo the selfdestruct, it takes a different path if callvalue is non-zero)\n\n-Tx 2:\n - `sender` does a 5-wei call to 0xaa. No exec (since no code). \n\nIn aiigo, the result would be that `0xaa` had `6 wei`, whereas OE reported (correctly) `5` wei. Furthermore, in aiigo, if the second tx was not executed, the `0xaa` would be destructed, resulting in `0 wei`. Thus obviously wrong. \n\nIt was determined that the root cause was this [commit](https://github.com/ethereum/go-ethereum/commit/223b950944f494a5b4e0957fd9f92c48b09037ad) from [this PR](https://github.com/ethereum/go-ethereum/pull/19953). The semantics of `createObject` was subtly changd, into returning a non-nil object (with `deleted=true`) where it previously did not if the account had been destructed. This return value caused the new object to inherit the old `balance`.\n",
"links": [ "links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4" "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-xw37-57qp-9mm4"
], ],
"published": "2020-12-10", "published": "2020-12-10",
"severity": "High", "severity": "High",
"CVE": "CVE-2020-26265", "CVE": "CVE-2020-26265",
"check": "(Geth\\/v1\\.9\\.(4|5|6|7|8|9)-.*)|(Geth\\/v1\\.9\\.1\\d-.*)$" "check": "(Aiigo\\/v1\\.9\\.(4|5|6|7|8|9)-.*)|(Aiigo\\/v1\\.9\\.1\\d-.*)$"
}, },
{ {
"name": "Not ready for London upgrade", "name": "Not ready for London upgrade",
@ -114,13 +114,13 @@
"fixed": "v1.10.6", "fixed": "v1.10.6",
"published": "2021-07-22", "published": "2021-07-22",
"severity": "High", "severity": "High",
"check": "(Geth\\/v1\\.10\\.(1|2|3|4|5)-.*)$" "check": "(Aiigo\\/v1\\.10\\.(1|2|3|4|5)-.*)$"
}, },
{ {
"name": "RETURNDATA corruption via datacopy", "name": "RETURNDATA corruption via datacopy",
"uid": "GETH-2021-02", "uid": "GETH-2021-02",
"summary": "A consensus-flaw in the Geth EVM could cause a node to deviate from the canonical chain.", "summary": "A consensus-flaw in the Aiigo EVM could cause a node to deviate from the canonical chain.",
"description": "A memory-corruption bug within the EVM can cause a consensus error, where vulnerable nodes obtain a different `stateRoot` when processing a maliciously crafted transaction. This, in turn, would lead to the chain being split: mainnet splitting in two forks.\n\nAll Geth versions supporting the London hard fork are vulnerable (the bug is older than London), so all users should update.\n\nThis bug was exploited on Mainnet at block 13107518.\n\nCredits for the discovery go to @guidovranken (working for Sentnl during an audit of the Telos EVM) and reported via bounty@ethereum.org.", "description": "A memory-corruption bug within the EVM can cause a consensus error, where vulnerable nodes obtain a different `stateRoot` when processing a maliciously crafted transaction. This, in turn, would lead to the chain being split: mainnet splitting in two forks.\n\nAll Aiigo versions supporting the London hard fork are vulnerable (the bug is older than London), so all users should update.\n\nThis bug was exploited on Mainnet at block 13107518.\n\nCredits for the discovery go to @guidovranken (working for Sentnl during an audit of the Telos EVM) and reported via bounty@ethereum.org.",
"links": [ "links": [
"https://github.com/ethereum/go-ethereum/blob/master/docs/postmortems/2021-08-22-split-postmortem.md", "https://github.com/ethereum/go-ethereum/blob/master/docs/postmortems/2021-08-22-split-postmortem.md",
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-9856-9gg9-qcmq", "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-9856-9gg9-qcmq",
@ -131,7 +131,7 @@
"published": "2021-08-24", "published": "2021-08-24",
"severity": "High", "severity": "High",
"CVE": "CVE-2021-39137", "CVE": "CVE-2021-39137",
"check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7)-.*)$" "check": "(Aiigo\\/v1\\.10\\.(0|1|2|3|4|5|6|7)-.*)$"
}, },
{ {
"name": "DoS via malicious `snap/1` request", "name": "DoS via malicious `snap/1` request",
@ -140,7 +140,7 @@
"description": "The `snap/1` protocol handler contains two vulnerabilities related to the `GetTrieNodes` packet, which can be exploited to crash the node. Full details are available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-59hh-656j-3p7v)", "description": "The `snap/1` protocol handler contains two vulnerabilities related to the `GetTrieNodes` packet, which can be exploited to crash the node. Full details are available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-59hh-656j-3p7v)",
"links": [ "links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-59hh-656j-3p7v", "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-59hh-656j-3p7v",
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities", "https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities",
"https://github.com/ethereum/go-ethereum/pull/23657" "https://github.com/ethereum/go-ethereum/pull/23657"
], ],
"introduced": "v1.10.0", "introduced": "v1.10.0",
@ -148,7 +148,7 @@
"published": "2021-10-24", "published": "2021-10-24",
"severity": "Medium", "severity": "Medium",
"CVE": "CVE-2021-41173", "CVE": "CVE-2021-41173",
"check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8)-.*)$" "check": "(Aiigo\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8)-.*)$"
}, },
{ {
"name": "DoS via malicious p2p message", "name": "DoS via malicious p2p message",
@ -157,7 +157,7 @@
"description": "A vulnerable node, if configured to use high verbosity logging, can be made to crash when handling specially crafted p2p messages sent from an attacker node. Full details are available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-wjxw-gh3m-7pm5)", "description": "A vulnerable node, if configured to use high verbosity logging, can be made to crash when handling specially crafted p2p messages sent from an attacker node. Full details are available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-wjxw-gh3m-7pm5)",
"links": [ "links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-wjxw-gh3m-7pm5", "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-wjxw-gh3m-7pm5",
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities", "https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities",
"https://github.com/ethereum/go-ethereum/pull/24507" "https://github.com/ethereum/go-ethereum/pull/24507"
], ],
"introduced": "v1.10.0", "introduced": "v1.10.0",
@ -165,7 +165,7 @@
"published": "2022-05-11", "published": "2022-05-11",
"severity": "Low", "severity": "Low",
"CVE": "CVE-2022-29177", "CVE": "CVE-2022-29177",
"check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16)-.*)$" "check": "(Aiigo\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16)-.*)$"
}, },
{ {
"name": "DoS via malicious p2p message", "name": "DoS via malicious p2p message",
@ -174,14 +174,14 @@
"description": "The p2p handler spawned a new goroutine to respond to ping requests. By flooding a node with ping requests, an unbounded number of goroutines can be created, leading to resource exhaustion and potentially crash due to OOM.", "description": "The p2p handler spawned a new goroutine to respond to ping requests. By flooding a node with ping requests, an unbounded number of goroutines can be created, leading to resource exhaustion and potentially crash due to OOM.",
"links": [ "links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-ppjg-v974-84cm", "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-ppjg-v974-84cm",
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities" "https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities"
], ],
"introduced": "v1.10.0", "introduced": "v1.10.0",
"fixed": "v1.12.1", "fixed": "v1.12.1",
"published": "2023-09-06", "published": "2023-09-06",
"severity": "High", "severity": "High",
"CVE": "CVE-2023-40591", "CVE": "CVE-2023-40591",
"check": "(Geth\\/v1\\.(10|11)\\..*)|(Geth\\/v1\\.12\\.0-.*)$" "check": "(Aiigo\\/v1\\.(10|11)\\..*)|(Aiigo\\/v1\\.12\\.0-.*)$"
}, },
{ {
"name": "DoS via malicious p2p message", "name": "DoS via malicious p2p message",
@ -190,13 +190,13 @@
"description": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node. Full details will be available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652)", "description": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node. Full details will be available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652)",
"links": [ "links": [
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652", "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652",
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities" "https://aiigo.ethereum.org/docs/vulnerabilities/vulnerabilities"
], ],
"introduced": "v1.10.0", "introduced": "v1.10.0",
"fixed": "v1.13.15", "fixed": "v1.13.15",
"published": "2024-05-06", "published": "2024-05-06",
"severity": "High", "severity": "High",
"CVE": "CVE-2024-32972", "CVE": "CVE-2024-32972",
"check": "(Geth\\/v1\\.(10|11|12)\\..*)|(Geth\\/v1\\.13\\.\\d-.*)|(Geth\\/v1\\.13\\.1(0|1|2|3|4)-.*)$" "check": "(Aiigo\\/v1\\.(10|11|12)\\..*)|(Aiigo\\/v1\\.13\\.\\d-.*)|(Aiigo\\/v1\\.13\\.1(0|1|2|3|4)-.*)$"
} }
] ]

View file

@ -47,7 +47,7 @@ var (
Action: verifyVerkle, Action: verifyVerkle,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth verkle verify <state-root> aiigo verkle verify <state-root>
This command takes a root commitment and attempts to rebuild the tree. This command takes a root commitment and attempts to rebuild the tree.
`, `,
}, },
@ -58,7 +58,7 @@ This command takes a root commitment and attempts to rebuild the tree.
Action: expandVerkle, Action: expandVerkle,
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth verkle dump <state-root> <key 1> [<key 2> ...] aiigo verkle dump <state-root> <key 1> [<key 2> ...]
This command will produce a dot file representing the tree, rooted at <root>. This command will produce a dot file representing the tree, rooted at <root>.
in which key1, key2, ... are expanded. in which key1, key2, ... are expanded.
`, `,

View file

@ -31,7 +31,7 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
var gethPubKeys []string = []string{ var aiigoPubKeys []string = []string{
//@holiman, minisign public key FB1D084D39BAEC24 //@holiman, minisign public key FB1D084D39BAEC24
"RWQk7Lo5TQgd+wxBNZM+Zoy+7UhhMHaWKzqoes9tvSbFLJYZhNTbrIjx", "RWQk7Lo5TQgd+wxBNZM+Zoy+7UhhMHaWKzqoes9tvSbFLJYZhNTbrIjx",
//minisign public key 138B1CA303E51687 //minisign public key 138B1CA303E51687
@ -73,7 +73,7 @@ func checkCurrent(url, current string) error {
if sig, err = fetch(fmt.Sprintf("%v.minisig", url)); err != nil { if sig, err = fetch(fmt.Sprintf("%v.minisig", url)); err != nil {
return fmt.Errorf("could not retrieve signature: %w", err) return fmt.Errorf("could not retrieve signature: %w", err)
} }
if err = verifySignature(gethPubKeys, data, sig); err != nil { if err = verifySignature(aiigoPubKeys, data, sig); err != nil {
return err return err
} }
var vulns []vulnJson var vulns []vulnJson
@ -128,7 +128,7 @@ func fetch(url string) ([]byte, error) {
} }
// verifySignature checks that the sigData is a valid signature of the given // verifySignature checks that the sigData is a valid signature of the given
// data, for pubkey GethPubkey // data, for pubkey AiigoPubkey
func verifySignature(pubkeys []string, data, sigdata []byte) error { func verifySignature(pubkeys []string, data, sigdata []byte) error {
sig, err := minisign.DecodeSignature(string(sigdata)) sig, err := minisign.DecodeSignature(string(sigdata))
if err != nil { if err != nil {

View file

@ -108,7 +108,7 @@ func TestMatching(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
check := func(version string) { check := func(version string) {
vFull := fmt.Sprintf("Geth/%v-unstable-15339cf1-20201204/linux-amd64/go1.15.4", version) vFull := fmt.Sprintf("Aiigo/%v-unstable-15339cf1-20201204/linux-amd64/go1.15.4", version)
for _, vuln := range vulns { for _, vuln := range vulns {
r, err := regexp.Compile(vuln.Check) r, err := regexp.Compile(vuln.Check)
vulnIntro := versionUint(vuln.Introduced) vulnIntro := versionUint(vuln.Introduced)
@ -118,7 +118,7 @@ func TestMatching(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if vuln.Name == "Denial of service due to Go CVE-2020-28362" { if vuln.Name == "Denial of service due to Go CVE-2020-28362" {
// this one is not tied to geth-versions // this one is not tied to aiigo-versions
continue continue
} }
if vulnIntro <= current && vulnFixed > current { if vulnIntro <= current && vulnFixed > current {
@ -145,9 +145,9 @@ func TestMatching(t *testing.T) {
} }
} }
func TestGethPubKeysParseable(t *testing.T) { func TestAiigoPubKeysParseable(t *testing.T) {
t.Parallel() t.Parallel()
for _, pubkey := range gethPubKeys { for _, pubkey := range aiigoPubKeys {
_, err := minisign.NewPublicKey(pubkey) _, err := minisign.NewPublicKey(pubkey)
if err != nil { if err != nil {
t.Errorf("Should be parseable") t.Errorf("Should be parseable")
@ -165,9 +165,9 @@ func TestKeyID(t *testing.T) {
args args args args
want string want string
}{ }{
{"@holiman key", args{id: extractKeyId(gethPubKeys[0])}, "FB1D084D39BAEC24"}, {"@holiman key", args{id: extractKeyId(aiigoPubKeys[0])}, "FB1D084D39BAEC24"},
{"second key", args{id: extractKeyId(gethPubKeys[1])}, "138B1CA303E51687"}, {"second key", args{id: extractKeyId(aiigoPubKeys[1])}, "138B1CA303E51687"},
{"third key", args{id: extractKeyId(gethPubKeys[2])}, "FD9813B2D2098484"}, {"third key", args{id: extractKeyId(aiigoPubKeys[2])}, "FD9813B2D2098484"},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

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