diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 2015604e64..0000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,23 +0,0 @@ -# Lines starting with '#' are comments. -# Each line is a file pattern followed by one or more owners. - -accounts/usbwallet @karalabe -accounts/scwallet @gballet -accounts/abi @gballet @MariusVanDerWijden -cmd/clef @holiman -cmd/puppeth @karalabe -consensus @karalabe -core/ @karalabe @holiman @rjl493456442 -eth/ @karalabe @holiman @rjl493456442 -eth/catalyst/ @gballet -graphql/ @gballet -les/ @zsfelfoldi @rjl493456442 -light/ @zsfelfoldi @rjl493456442 -mobile/ @karalabe @ligi -node/ @fjl @renaynay -p2p/ @fjl @zsfelfoldi -rpc/ @fjl @holiman -p2p/simulations @fjl -p2p/protocols @fjl -p2p/testing @fjl -signer/ @holiman diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 2aa2c48a60..7d34216478 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -1,30 +1,71 @@ --- name: Report a bug -about: Something with go-ethereum is not working as expected +about: Something with bor client is not working as expected title: '' labels: 'type:bug' assignees: '' --- -#### System information +Our support team has aggregated some common issues and their solutions from past which are faced while running or interacting with a bor client. In order to prevent redundant efforts, we would encourage you to have a look at the [FAQ's section](https://docs.polygon.technology/docs/faq/technical-faqs) of our documentation mentioning the same, before filing an issue here. In case of additional support, you can also join our [discord](https://discord.com/invite/zdwkdvMNY2) server -Geth version: `geth version` -OS & Version: Windows/Linux/OSX -Commit hash : (if `develop`) + -#### Expected behaviour +#### **System information** +Bor client version: [e.g. v0.2.16] -#### Actual behaviour +Heimdall client version: [e.g. v0.2.10] +OS & Version: Windows / Linux / OSX -#### Steps to reproduce the behaviour +Environment: Polygon Mainnet / Polygon Mumbai / Devnet +Type of node: Validator / Sentry / Archive -#### Backtrace +Additional Information: -```` -[backtrace] -```` +#### **Overview of the problem** -When submitting logs: please submit them as text and not screenshots. \ No newline at end of file +Please describe the issue you experiencing. + + +#### **Reproduction Steps** + +Please mention the steps required to reproduce this issue. + + + +#### **Logs / Traces / Output / Error Messages** + +Please post any logs/traces/output/error messages (as text and not screenshots) which you believe may have caused the issue. If the log is longer than a few dozen lines, please include the URL to the [gist](https://gist.github.com/) of the log instead of posting it in the issue. + +**Additional Information** + +In order to debug the issue faster, we would stongly encourage if you can provide some of the details mentioned below (whichever seems relevant to your issue) + +1. Your `start.sh` file or `bor.service`, if you're facing some peering issue or unable to use some service (like `http` endpoint) as expected. Moreover, if possible mention the chain configuration printed while starting the node which looks something like `Initialised chain configuration config="{ChainID: 137, ..., Engine: bor}"` + +2. The result of `eth.syncing`, `admin.peers.length`, `admin.nodeInfo`, value of the `maxpeers` flag in start.sh, and bootnodes/static nodes (if any) is you're facing some syncing issue. + +3. Your `heimdall-config.toml` parameters for checking the ETH and BOR RPC url's, incase of issue with bor heimdall communication. + +4. The CURL request (for that specific error) if you're facing any issues or identify a bug while making RPC request. + diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md index aacd885f9e..17238ceb12 100644 --- a/.github/ISSUE_TEMPLATE/feature.md +++ b/.github/ISSUE_TEMPLATE/feature.md @@ -8,10 +8,11 @@ assignees: '' # Rationale -Why should this feature exist? +The motivation behind the feature and why should this feature exist? What are the use-cases? # Implementation -Do you have ideas regarding the implementation of this feature? -Are you willing to implement this feature? \ No newline at end of file +Do you have ideas regarding the implementation of this feature? (Mention reference links if any) +Any alternative solutions or features you've considered? +Are you willing to implement this feature? diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 8f460ab558..b1fad65ae0 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,9 +1,11 @@ --- -name: Ask a question -about: Something is unclear +name: Question/Support +about: Ask a question or request support title: '' labels: 'type:docs' assignees: '' --- -This should only be used in very rare cases e.g. if you are not 100% sure if something is a bug or asking a question that leads to improving the documentation. For general questions please use [discord](https://discord.gg/nthXNEv) or the Ethereum stack exchange at https://ethereum.stackexchange.com. +This should only be used in very rare cases e.g. if you are not 100% sure if something is a bug or asking a question that leads to improving the documentation. + +For general questions please join our [discord](https://discord.com/invite/zdwkdvMNY2) server. diff --git a/.github/matic-cli-config.yml b/.github/matic-cli-config.yml index c7dab39b0e..8bdfe82b3b 100644 --- a/.github/matic-cli-config.yml +++ b/.github/matic-cli-config.yml @@ -3,9 +3,13 @@ defaultFee: 2000 borChainId: "15001" heimdallChainId: heimdall-15001 contractsBranch: jc/v0.3.1-backport +sprintSize: 64 +blockNumber: '0' +blockTime: '2' numOfValidators: 3 numOfNonValidators: 0 ethURL: http://ganache:9545 +ethHostUser: ubuntu devnetType: docker borDockerBuildContext: "../../bor" -heimdallDockerBuildContext: "https://github.com/maticnetwork/heimdall.git#develop" \ No newline at end of file +heimdallDockerBuildContext: "https://github.com/maticnetwork/heimdall.git#develop" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..a369a528e3 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,44 @@ +# Description + +Please provide a detailed description of what was done in this PR + +# Changes + +- [ ] Bugfix (non-breaking change that solves an issue) +- [ ] Hotfix (change that solves an urgent issue, and requires immediate attention) +- [ ] New feature (non-breaking change that adds functionality) +- [ ] Breaking change (change that is not backwards-compatible and/or changes current functionality) + +# Breaking changes + +Please complete this section if any breaking changes have been made, otherwise delete it + +# Checklist + +- [ ] I have added at least 2 reviewer or the whole pos-v1 team +- [ ] I have added sufficient documentation in code +- [ ] I will be resolving comments - if any - by pushing each fix in a separate commit and linking the commit hash in the comment reply + +# Cross repository changes + +- [ ] This PR requires changes to heimdall + - In case link the PR here: +- [ ] This PR requires changes to matic-cli + - In case link the PR here: + +## Testing + +- [ ] I have added unit tests +- [ ] I have added tests to CI +- [ ] I have tested this code manually on local environment +- [ ] I have tested this code manually on remote devnet using express-cli +- [ ] I have tested this code manually on mumbai +- [ ] I have created new e2e tests into express-cli + +### Manual tests + +Please complete this section with the steps you performed if you ran manual tests for this functionality, otherwise delete it + +# Additional comments + +Please post additional comments in this section if you have them, otherwise delete it \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 639a68703f..b5bb62a8bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ on: pull_request: branches: - "**" - types: [opened, synchronize, edited] + types: [opened, synchronize] concurrency: group: build-${{ github.event.pull_request.number || github.ref }} @@ -19,7 +19,7 @@ jobs: if: (github.event.action != 'closed' || github.event.pull_request.merged == true) strategy: matrix: - os: [ ubuntu-20.04, macos-11 ] # list of os: https://github.com/actions/virtual-environments + os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 @@ -29,7 +29,7 @@ jobs: - uses: actions/setup-go@v3 with: - go-version: 1.18.x + go-version: 1.19.x - name: Install dependencies on Linux if: runner.os == 'Linux' @@ -63,7 +63,7 @@ jobs: - name: test-integration run: make test-integration - + - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 with: @@ -104,7 +104,7 @@ jobs: uses: actions/checkout@v3 with: repository: maticnetwork/matic-cli - ref: v0.3.0-dev + ref: arpit/pos-655-2 path: matic-cli - name: Install dependencies on Linux @@ -154,7 +154,7 @@ jobs: cd matic-cli/devnet/code/contracts npm run truffle exec scripts/deposit.js -- --network development $(jq -r .root.tokens.MaticToken contractAddresses.json) 100000000000000000000 cd - - bash bor/integration-tests/smoke_test.sh + timeout 20m bash bor/integration-tests/smoke_test.sh - name: Upload logs if: always() diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0d45f0bc98..2ceda3d2ee 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: - name: Set up Go uses: actions/setup-go@master with: - go-version: 1.17.x + go-version: 1.19.x - name: Prepare id: prepare diff --git a/.gitignore b/.gitignore index 50328c8121..cd3c25a6a8 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,5 @@ profile.cov ./bor-debug-* dist + +*.csv diff --git a/.gitmodules b/.gitmodules index 241c169c47..986a4ca0cf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,6 @@ path = tests/evm-benchmarks url = https://github.com/ipsilon/evm-benchmarks shallow = true +[submodule "tests/testdata"] + path = tests/testdata + url = https://github.com/ethereum/tests.git diff --git a/.golangci.yml b/.golangci.yml index 89a9e328b8..89eebfe9fe 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -50,6 +50,7 @@ linters: - unconvert - unparam - wsl + - asasalint #- errorlint causes stack overflow. TODO: recheck after each golangci update linters-settings: diff --git a/Makefile b/Makefile index a8e14cf06a..242435df76 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,10 @@ bor: protoc: protoc --go_out=. --go-grpc_out=. ./internal/cli/server/proto/*.proto +generate-mocks: + go generate mockgen -destination=./tests/bor/mocks/IHeimdallClient.go -package=mocks ./consensus/bor IHeimdallClient + go generate mockgen -destination=./eth/filters/IBackend.go -package=filters ./eth/filters Backend + geth: $(GORUN) build/ci.go install ./cmd/geth @echo "Done building." @@ -61,7 +65,7 @@ test-race: $(GOTEST) --timeout 15m -race -shuffle=on $(TESTALL) test-integration: - $(GOTEST) --timeout 30m -tags integration $(TESTE2E) + $(GOTEST) --timeout 60m -tags integration $(TESTE2E) escape: cd $(path) && go test -gcflags "-m -m" -run none -bench=BenchmarkJumpdest* -benchmem -memprofile mem.out @@ -71,7 +75,7 @@ lint: lintci-deps: rm -f ./build/bin/golangci-lint - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./build/bin v1.46.0 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./build/bin v1.48.0 goimports: goimports -local "$(PACKAGE)" -w . @@ -93,7 +97,7 @@ devtools: $(GOBUILD) -o $(GOBIN)/codecgen github.com/ugorji/go/codec/codecgen $(GOBUILD) -o $(GOBIN)/abigen ./cmd/abigen $(GOBUILD) -o $(GOBIN)/mockgen github.com/golang/mock/mockgen - $(GOBUILD) -o $(GOBIN)/protoc-gen-go github.com/golang/protobuf/protoc-gen-go + $(GOBUILD) -o $(GOBIN)/protoc-gen-go google.golang.org/protobuf/cmd/protoc-gen-go PATH=$(GOBIN):$(PATH) go generate ./common PATH=$(GOBIN):$(PATH) go generate ./core/types PATH=$(GOBIN):$(PATH) go generate ./consensus/bor @@ -192,7 +196,7 @@ geth-windows-amd64: @ls -ld $(GOBIN)/geth-windows-* | grep amd64 PACKAGE_NAME := github.com/maticnetwork/bor -GOLANG_CROSS_VERSION ?= v1.18.1 +GOLANG_CROSS_VERSION ?= v1.19.1 .PHONY: release-dry-run release-dry-run: @@ -220,6 +224,7 @@ release: -e DOCKER_PASSWORD \ -e SLACK_WEBHOOK \ -v /var/run/docker.sock:/var/run/docker.sock \ + -v $(HOME)/.docker/config.json:/root/.docker/config.json \ -v `pwd`:/go/src/$(PACKAGE_NAME) \ -w /go/src/$(PACKAGE_NAME) \ goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \ diff --git a/README.md b/README.md index 4e33a551d0..9f2c7e6732 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Bor Overview -Bor is the Official Golang implementation of the Matic protocol. It is a fork of Go Ethereum - https://github.com/ethereum/go-ethereum and EVM compabile. +Bor is the Official Golang implementation of the Matic protocol. It is a fork of Go Ethereum - https://github.com/ethereum/go-ethereum and EVM compatible. ![Forks](https://img.shields.io/github/forks/maticnetwork/bor?style=social) ![Stars](https://img.shields.io/github/stars/maticnetwork/bor?style=social) diff --git a/RETESTBOR.md b/RETESTBOR.md new file mode 100644 index 0000000000..efb5211011 --- /dev/null +++ b/RETESTBOR.md @@ -0,0 +1,103 @@ + +# Retesteth - bor + +These integration tests are included in the bor repo via using the git submodule + +``` +[submodule "tests/testdata"] + path = tests/testdata + url = https://github.com/ethereum/tests.git +``` + +The version used is the last stable release, tagged as v10.4 from branch develop in ethereum/tests +Details on release code can be found here https://github.com/ethereum/tests/commit/a380655e5ffab1a5ea0f4d860224bdb19013f06a + +To run the tests, we hava a `make` command: +``` +make test-integration +``` +which is also integrated into the CI pipeline on GitHub + + +## Retesteth - bor on remote machine + +To explore and test the `retesteth` package, the following steps were executed. +This is only for educational purposes. +For future usage, there is no need to go through this section, the only thing needed is to have 'green' integration tests. + +- `ssh` into a VM running bor +- Change configs by replacing geth with bor inside the docker container +``` +mkdir ~/retestethBuild +cd ~/retestethBuild +wget https://raw.githubusercontent.com/ethereum/retesteth/develop/dretesteth.sh +chmod +x dretesteth.sh +wget https://raw.githubusercontent.com/ethereum/retesteth/develop/Dockerfile +``` + +Modify the RUN git clone line in the Dockerfile for repo “retesteth” to change branch -b from master to develop. Do not modify repo branches for “winsvega/solidity” [LLLC opcode support] and “go-ethereum”. +Modify the Dockerfile so that the eth client points to bor +e.g. : `https://github.com/ethereum/retesteth/blob/master/Dockerfile#L41` +from `RUN git clone --depth 1 -b master https://github.com/ethereum/go-ethereum.git /geth` +to: `RUN git clone --depth 1 -b master https://github.com/maticnetwork/bor.git /geth` + +- build docker image +`sudo ./dretesteth.sh build` + +- clone repo +``` +git clone --branch develop https://github.com/ethereum/tests.git +``` +this step is eventually replaced by adding the git submodule directly into bor repo with +``` +git submodule add --depth 1 https://github.com/ethereum/tests.git tests/testdata +``` +- Let's move to the restestethBuild folder +``` +cd /home/ubuntu/retestethBuild +``` +Now we have the tests repo here +``` +ls +> Dockerfile dretesteth.sh tests +``` +- Run test example +``` +./dretesteth.sh -t GeneralStateTests/stExample -- --testpath /home/ubuntu/retestethBuild/tests --datadir /tests/config +``` +This will create the config files for the different clients in ~/tests/config +Eventually. these config needs to be adapted according to the following doc +https://ethereum-tests.readthedocs.io/en/latest/retesteth-tutorial.html +Specifically: +``` +f you look inside ~/tests/config, you’ll see a directory for each configured client. Typically this directory has these files: + +config, which contains the configuration for the client: +The communication protocol to use with the client (typically TCP) +The address(es) to use with that protocol +The forks the client supports +The exceptions the client can throw, and how retesteth should interpret them. This is particularly important when testing the client’s behavior when given invalid blocks. +start.sh, which starts the client inside the docker image +stop.sh, which stops the client instance(s) +genesis, a directory which includes the genesis blocks for various forks the client supports. If this directory does not exist for a client, it uses the genesis blocks for the default client. +``` + +We replaced geth inside docker by using https://ethereum-tests.readthedocs.io/en/latest/retesteth-tutorial.html#replace-geth-inside-the-docker +Theoretically, we would not need any additional config change + +- Run test suites +``` +./dretesteth.sh -t -- --testpath /home/ubuntu/retestethBuild/tests --datadir /tests/config +``` +Where `TestSuiteName` is one of the maintained test suites, reported here https://github.com/ethereum/tests +``` +BasicTests +BlockchainTests +GeneralStateTests +TransactionTests +RLPTest +src +``` + +If you want to run retestheth against a bor client on localhost:8545 (using 8 threads), instead of isolating it into a docker image, run +`sudo ./dretesteth.sh -t GeneralStateTests -- --testpath ~/tests --datadir /tests/config --clients t8ntool --nodes 127.0.0.1:8545 -j 8` diff --git a/accounts/abi/bind/auth.go b/accounts/abi/bind/auth.go index a4307a9529..63e6f62451 100644 --- a/accounts/abi/bind/auth.go +++ b/accounts/abi/bind/auth.go @@ -21,7 +21,6 @@ import ( "crypto/ecdsa" "errors" "io" - "io/ioutil" "math/big" "github.com/ethereum/go-ethereum/accounts" @@ -45,14 +44,17 @@ var ErrNotAuthorized = errors.New("not authorized to sign this account") // Deprecated: Use NewTransactorWithChainID instead. func NewTransactor(keyin io.Reader, passphrase string) (*TransactOpts, error) { log.Warn("WARNING: NewTransactor has been deprecated in favour of NewTransactorWithChainID") - json, err := ioutil.ReadAll(keyin) + + json, err := io.ReadAll(keyin) if err != nil { return nil, err } + key, err := keystore.DecryptKey(json, passphrase) if err != nil { return nil, err } + return NewKeyedTransactor(key.PrivateKey), nil } @@ -106,7 +108,7 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts { // NewTransactorWithChainID is a utility method to easily create a transaction signer from // an encrypted json key stream and the associated passphrase. func NewTransactorWithChainID(keyin io.Reader, passphrase string, chainID *big.Int) (*TransactOpts, error) { - json, err := ioutil.ReadAll(keyin) + json, err := io.ReadAll(keyin) if err != nil { return nil, err } diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index ac696f446b..2431b5644a 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -78,7 +78,7 @@ type SimulatedBackend struct { func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc} genesis.MustCommit(database) - blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) backend := &SimulatedBackend{ database: database, diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 992497993a..644c111f08 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -18,7 +18,6 @@ package bind import ( "fmt" - "io/ioutil" "os" "os/exec" "path/filepath" @@ -1966,7 +1965,7 @@ func TestGolangBindings(t *testing.T) { t.Skip("go sdk not found for testing") } // Create a temporary workspace for the test suite - ws, err := ioutil.TempDir("", "binding-test") + ws, err := os.MkdirTemp("", "binding-test") if err != nil { t.Fatalf("failed to create temporary workspace: %v", err) } @@ -1990,7 +1989,7 @@ func TestGolangBindings(t *testing.T) { if err != nil { t.Fatalf("test %d: failed to generate binding: %v", i, err) } - if err = ioutil.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+".go"), []byte(bind), 0600); err != nil { + if err = os.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+".go"), []byte(bind), 0600); err != nil { t.Fatalf("test %d: failed to write binding: %v", i, err) } // Generate the test file with the injected test code @@ -2006,7 +2005,7 @@ func TestGolangBindings(t *testing.T) { %s } `, tt.imports, tt.name, tt.tester) - if err := ioutil.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+"_test.go"), []byte(code), 0600); err != nil { + if err := os.WriteFile(filepath.Join(pkg, strings.ToLower(tt.name)+"_test.go"), []byte(code), 0600); err != nil { t.Fatalf("test %d: failed to write tests: %v", i, err) } }) diff --git a/builder/files/config.toml b/builder/files/config.toml index fc95cd1a64..0f2919807f 100644 --- a/builder/files/config.toml +++ b/builder/files/config.toml @@ -126,6 +126,7 @@ syncmode = "full" # noprefetch = false # preimages = false # txlookuplimit = 2350000 + # triesinmemory = 128 # timeout = "1h0m0s" [accounts] diff --git a/builder/files/genesis-mainnet-v1.json b/builder/files/genesis-mainnet-v1.json index 647529735a..d3f0d02206 100644 --- a/builder/files/genesis-mainnet-v1.json +++ b/builder/files/genesis-mainnet-v1.json @@ -18,8 +18,12 @@ "period": { "0": 2 }, - "producerDelay": 6, - "sprint": 64, + "producerDelay": { + "0": 6 + }, + "sprint": { + "0": 64 + }, "backupMultiplier": { "0": 2 }, diff --git a/builder/files/genesis-testnet-v4.json b/builder/files/genesis-testnet-v4.json index 0215aee246..fe066411a3 100644 --- a/builder/files/genesis-testnet-v4.json +++ b/builder/files/genesis-testnet-v4.json @@ -15,15 +15,24 @@ "londonBlock": 22640000, "bor": { "jaipurBlock": 22770000, + "delhiBlock": 29638656, "period": { "0": 2, - "25275000": 5 + "25275000": 5, + "29638656": 2 + }, + "producerDelay": { + "0": 6, + "29638656": 4 + }, + "sprint": { + "0": 64, + "29638656": 16 }, - "producerDelay": 6, - "sprint": 64, "backupMultiplier": { "0": 2, - "25275000": 5 + "25275000": 5, + "29638656": 2 }, "validatorContract": "0x0000000000000000000000000000000000001000", "stateReceiverContract": "0x0000000000000000000000000000000000001001", diff --git a/cmd/evm/internal/t8ntool/block.go b/cmd/evm/internal/t8ntool/block.go index d4edd33bde..4d75a30d4b 100644 --- a/cmd/evm/internal/t8ntool/block.go +++ b/cmd/evm/internal/t8ntool/block.go @@ -17,6 +17,7 @@ package t8ntool import ( + "context" "crypto/ecdsa" "encoding/json" "errors" @@ -188,7 +189,7 @@ func (i *bbInput) sealEthash(block *types.Block) (*types.Block, error) { // If the testmode is used, the sealer will return quickly, and complain // "Sealing result is not read by miner" if it cannot write the result. results := make(chan *types.Block, 1) - if err := engine.Seal(nil, block, results, nil); err != nil { + if err := engine.Seal(context.Background(), nil, block, results, nil); err != nil { panic(fmt.Sprintf("failed to seal block: %v", err)) } found := <-results diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 874685f15e..c848b953f8 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -223,6 +223,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txIndex++ } + statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)) // Add mining reward? if miningReward > 0 { diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index a178f6c751..fc2309d2db 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -108,6 +108,7 @@ The dumpgenesis command dumps the genesis block configuration in JSON format to // bor related flags utils.HeimdallURLFlag, utils.WithoutHeimdallFlag, + utils.HeimdallgRPCAddressFlag, }, Category: "BLOCKCHAIN COMMANDS", Description: ` diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 101f4b2de6..80bf95b1ac 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -18,14 +18,12 @@ package main import ( "fmt" - "io/ioutil" "math/big" "os" "time" - "gopkg.in/urfave/cli.v1" - "github.com/BurntSushi/toml" + "gopkg.in/urfave/cli.v1" "github.com/ethereum/go-ethereum/accounts/external" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -71,7 +69,7 @@ type gethConfig struct { } func loadConfig(file string, cfg *gethConfig) error { - data, err := ioutil.ReadFile(file) + data, err := os.ReadFile(file) if err != nil { return err } diff --git a/cmd/utils/bor_flags.go b/cmd/utils/bor_flags.go index 22e1b33d3e..256df31e97 100644 --- a/cmd/utils/bor_flags.go +++ b/cmd/utils/bor_flags.go @@ -5,11 +5,12 @@ import ( "io/ioutil" "os" + "gopkg.in/urfave/cli.v1" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" - "gopkg.in/urfave/cli.v1" ) var ( @@ -30,10 +31,18 @@ var ( Usage: "Run without Heimdall service (for testing purpose)", } + // HeimdallgRPCAddressFlag flag for heimdall gRPC address + HeimdallgRPCAddressFlag = cli.StringFlag{ + Name: "bor.heimdallgRPC", + Usage: "Address of Heimdall gRPC service", + Value: "", + } + // BorFlags all bor related flags BorFlags = []cli.Flag{ HeimdallURLFlag, WithoutHeimdallFlag, + HeimdallgRPCAddressFlag, } ) @@ -56,6 +65,7 @@ func getGenesis(genesisPath string) (*core.Genesis, error) { func SetBorConfig(ctx *cli.Context, cfg *eth.Config) { cfg.HeimdallURL = ctx.GlobalString(HeimdallURLFlag.Name) cfg.WithoutHeimdall = ctx.GlobalBool(WithoutHeimdallFlag.Name) + cfg.HeimdallgRPCAddress = ctx.GlobalString(HeimdallgRPCAddressFlag.Name) } // CreateBorEthereum Creates bor ethereum object from eth.Config diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 79c73903fb..81ce27ef4c 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -33,6 +33,10 @@ import ( "text/template" "time" + pcsclite "github.com/gballet/go-libpcsclite" + gopsutil "github.com/shirou/gopsutil/mem" + "gopkg.in/urfave/cli.v1" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" @@ -68,9 +72,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/params" - pcsclite "github.com/gballet/go-libpcsclite" - gopsutil "github.com/shirou/gopsutil/mem" - "gopkg.in/urfave/cli.v1" ) func init() { @@ -1503,7 +1504,7 @@ func setPeerRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) { if peerRequiredBlocks == "" { if ctx.GlobalIsSet(LegacyWhitelistFlag.Name) { - log.Warn("The flag --rpc is deprecated and will be removed, please use --peer.requiredblocks") + log.Warn("The flag --whitelist is deprecated and will be removed, please use --eth.requiredblocks") peerRequiredBlocks = ctx.GlobalString(LegacyWhitelistFlag.Name) } else { return @@ -2030,9 +2031,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai engine = clique.New(config.Clique, chainDb) } else if config.Bor != nil { ethereum = CreateBorEthereum(ð.Config{ - Genesis: genesis, - HeimdallURL: ctx.GlobalString(HeimdallURLFlag.Name), - WithoutHeimdall: ctx.GlobalBool(WithoutHeimdallFlag.Name), + Genesis: genesis, + HeimdallURL: ctx.GlobalString(HeimdallURLFlag.Name), + WithoutHeimdall: ctx.GlobalBool(WithoutHeimdallFlag.Name), + HeimdallgRPCAddress: ctx.GlobalString(HeimdallgRPCAddressFlag.Name), }) engine = ethereum.Engine() } else { @@ -2079,7 +2081,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai // TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only. // Disable transaction indexing/unindexing by default. - chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil) + chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil, nil) if err != nil { Fatalf("Can't create BlockChain: %v", err) } diff --git a/common/network/port.go b/common/network/port.go new file mode 100644 index 0000000000..f92b59ac11 --- /dev/null +++ b/common/network/port.go @@ -0,0 +1,36 @@ +package network + +import ( + "errors" + "fmt" + "net" +) + +const ( + maxPortCheck = 100 + + emptyPort = "127.0.0.1:0" +) + +var ( + ErrCantFindAPort = errors.New("no available port found") +) + +// FindAvailablePort returns the an available port +func FindAvailablePort() (int, net.Listener, error) { + var ( + listener net.Listener + err error + ) + + for i := uint(0); i < maxPortCheck; i++ { + listener, err = net.Listen("tcp", emptyPort) + if err != nil { + continue + } + + return listener.Addr().(*net.TCPAddr).Port, listener, nil + } + + return 0, nil, fmt.Errorf("%w: %s", ErrCantFindAPort, err) +} diff --git a/common/tracing/context.go b/common/tracing/context.go new file mode 100644 index 0000000000..510e45d775 --- /dev/null +++ b/common/tracing/context.go @@ -0,0 +1,96 @@ +package tracing + +import ( + "context" + "time" + + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +type tracerKey struct{} + +type Option func(context.Context, trace.Span) + +func WithTracer(ctx context.Context, tr trace.Tracer) context.Context { + return context.WithValue(ctx, tracerKey{}, tr) +} + +func FromContext(ctx context.Context) trace.Tracer { + tr, _ := ctx.Value(tracerKey{}).(trace.Tracer) + + return tr +} + +func StartSpan(ctx context.Context, snapName string) (context.Context, trace.Span) { + tr := FromContext(ctx) + + if tr == nil { + return ctx, nil + } + + ctx, span := tr.Start(ctx, snapName) + ctx = WithTracer(ctx, tr) + + return ctx, span +} + +func EndSpan(span trace.Span) { + if span != nil { + span.End() + } +} + +func Trace(ctx context.Context, spanName string) (context.Context, trace.Span) { + tr := FromContext(ctx) + + if tr == nil { + return ctx, nil + } + + return tr.Start(ctx, spanName) +} + +func Exec(ctx context.Context, spanName string, opts ...Option) { + var span trace.Span + + tr := FromContext(ctx) + + if tr != nil { + ctx, span = tr.Start(ctx, spanName) + } + + for _, optFn := range opts { + optFn(ctx, span) + } + + if tr != nil { + span.End() + } +} + +func WithTime(fn func(context.Context, trace.Span)) Option { + return func(ctx context.Context, span trace.Span) { + ElapsedTime(ctx, span, "elapsed", fn) + } +} + +func ElapsedTime(ctx context.Context, span trace.Span, msg string, fn func(context.Context, trace.Span)) { + var now time.Time + + if span != nil { + now = time.Now() + } + + fn(ctx, span) + + if span != nil { + span.SetAttributes(attribute.Int(msg, int(time.Since(now).Milliseconds()))) + } +} + +func SetAttributes(span trace.Span, kvs ...attribute.KeyValue) { + if span != nil { + span.SetAttributes(kvs...) + } +} diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 1fd7deb872..b7102c1e67 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -17,6 +17,7 @@ package beacon import ( + "context" "errors" "fmt" "math/big" @@ -170,10 +171,11 @@ func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Blo // verifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum consensus engine. The difference between the beacon and classic is // (a) The following fields are expected to be constants: -// - difficulty is expected to be 0 -// - nonce is expected to be 0 -// - unclehash is expected to be Hash(emptyHeader) +// - difficulty is expected to be 0 +// - nonce is expected to be 0 +// - unclehash is expected to be Hash(emptyHeader) // to be the desired constants +// // (b) the timestamp is not verified anymore // (c) the extradata is limited to 32 bytes func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error { @@ -278,11 +280,11 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. // FinalizeAndAssemble implements consensus.Engine, setting the final state and // assembling the block. -func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { +func (beacon *Beacon) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { // FinalizeAndAssemble is different with Prepare, it can be used in both block // generation and verification. So determine the consensus rules by header type. if !beacon.IsPoSHeader(header) { - return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts) + return beacon.ethone.FinalizeAndAssemble(ctx, chain, header, state, txs, uncles, receipts) } // Finalize and assemble the block beacon.Finalize(chain, header, state, txs, uncles) @@ -294,9 +296,9 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea // // Note, the method returns immediately and will send the result async. More // than one result may also be returned depending on the consensus algorithm. -func (beacon *Beacon) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { +func (beacon *Beacon) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { if !beacon.IsPoSHeader(block.Header()) { - return beacon.ethone.Seal(chain, block, results, stop) + return beacon.ethone.Seal(ctx, chain, block, results, stop) } // The seal verification is done by the external consensus engine, // return directly without pushing any block back. In another word diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index f140146976..1b4ddec45d 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -2,6 +2,7 @@ package bor import ( "bytes" + "context" "encoding/hex" "encoding/json" "errors" @@ -11,13 +12,17 @@ import ( "sort" "strconv" "sync" + "sync/atomic" "time" lru "github.com/hashicorp/golang-lru" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "golang.org/x/crypto/sha3" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/tracing" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/bor/api" "github.com/ethereum/go-ethereum/consensus/bor/clerk" @@ -45,7 +50,9 @@ const ( // Bor protocol constants. var ( - defaultSprintLength = uint64(64) // Default number of blocks after which to checkpoint and reset the pending votes + defaultSprintLength = map[string]uint64{ + "0": 64, + } // Default number of blocks after which to checkpoint and reset the pending votes extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal @@ -96,6 +103,9 @@ var ( // errOutOfRangeChain is returned if an authorization list is attempted to // be modified via out-of-range or non-contiguous headers. errOutOfRangeChain = errors.New("out of range or non-contiguous chain") + + errUncleDetected = errors.New("uncles not allowed") + errUnknownValidators = errors.New("unknown validators") ) // SignerFn is a signer callback function to request a header to be signed by a @@ -159,7 +169,7 @@ func encodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig) { header.Nonce, } - if c.IsJaipur(header.Number.Uint64()) { + if c.IsJaipur(header.Number) { if header.BaseFee != nil { enc = append(enc, header.BaseFee) } @@ -175,8 +185,8 @@ func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint6 // When the block is the first block of the sprint, it is expected to be delayed by `producerDelay`. // That is to allow time for block propagation in the last sprint delay := c.CalculatePeriod(number) - if number%c.Sprint == 0 { - delay = c.ProducerDelay + if number%c.CalculateSprint(number) == 0 { + delay = c.CalculateProducerDelay(number) } if succession > 0 { @@ -209,9 +219,7 @@ type Bor struct { recents *lru.ARCCache // Snapshots for recent block to speed up reorgs signatures *lru.ARCCache // Signatures of recent blocks to speed up mining - signer common.Address // Ethereum address of the signing key - signFn SignerFn // Signer function to authorize hashes with - lock sync.RWMutex // Protects the signer fields + authorizedSigner atomic.Pointer[signer] // Ethereum address and sign function of the signing key ethAPI api.Caller spanner Spanner @@ -224,6 +232,11 @@ type Bor struct { closeOnce sync.Once } +type signer struct { + signer common.Address // Ethereum address of the signing key + signFn SignerFn // Signer function to authorize hashes with +} + // New creates a Matic Bor consensus engine. func New( chainConfig *params.ChainConfig, @@ -237,7 +250,7 @@ func New( borConfig := chainConfig.Bor // Set any missing consensus parameters to their defaults - if borConfig != nil && borConfig.Sprint == 0 { + if borConfig != nil && borConfig.CalculateSprint(0) == 0 { borConfig.Sprint = defaultSprintLength } // Allocate the snapshot caches and create the engine @@ -256,6 +269,14 @@ func New( HeimdallClient: heimdallClient, } + c.authorizedSigner.Store(&signer{ + common.Address{}, + func(_ accounts.Account, _ string, i []byte) ([]byte, error) { + // return an error to prevent panics + return nil, &UnauthorizedSignerError{0, common.Address{}.Bytes()} + }, + }) + // make sure we can decode all the GenesisAlloc in the BorConfig. for key, genesisAlloc := range c.config.BlockAlloc { if _, err := decodeGenesisAlloc(genesisAlloc); err != nil { @@ -273,14 +294,14 @@ func (c *Bor) Author(header *types.Header) (common.Address, error) { } // VerifyHeader checks whether a header conforms to the consensus rules. -func (c *Bor) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error { +func (c *Bor) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, _ bool) error { return c.verifyHeader(chain, header, nil) } // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The // method returns a quit channel to abort the operations and a results channel to // retrieve the async verifications (the order is that of the input slice). -func (c *Bor) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { +func (c *Bor) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, _ []bool) (chan<- struct{}, <-chan error) { abort := make(chan struct{}) results := make(chan error, len(headers)) @@ -320,7 +341,7 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head } // check extr adata - isSprintEnd := IsSprintStart(number+1, c.config.Sprint) + isSprintEnd := IsSprintStart(number+1, c.config.CalculateSprint(number)) // Ensure that the extra-data contains a signer list on checkpoint, but none otherwise signersBytes := len(header.Extra) - extraVanity - extraSeal @@ -434,7 +455,7 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t } // verify the validator list in the last sprint block - if IsSprintStart(number, c.config.Sprint) { + if IsSprintStart(number, c.config.CalculateSprint(number)) { parentValidatorBytes := parent.Extra[extraVanity : len(parent.Extra)-extraSeal] validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength) @@ -487,6 +508,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co // at a checkpoint block without a parent (light client CHT), or we have piled // up more headers than allowed to be reorged (chain reinit from a freezer), // consider the checkpoint trusted and snapshot it. + // TODO fix this // nolint:nestif if number == 0 { @@ -496,7 +518,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co hash := checkpoint.Hash() // get validators and current span - validators, err := c.spanner.GetCurrentValidators(hash, number+1) + validators, err := c.spanner.GetCurrentValidators(context.Background(), hash, number+1) if err != nil { return nil, err } @@ -537,7 +559,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co // check if snapshot is nil if snap == nil { - return nil, fmt.Errorf("Unknown error while retrieving snapshot at block number %v", number) + return nil, fmt.Errorf("unknown error while retrieving snapshot at block number %v", number) } // Previous snapshot found, apply any pending headers on top of it @@ -566,9 +588,9 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co // VerifyUncles implements consensus.Engine, always returning an error for any // uncles as this consensus mechanism doesn't permit uncles. -func (c *Bor) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { +func (c *Bor) VerifyUncles(_ consensus.ChainReader, block *types.Block) error { if len(block.Uncles()) > 0 { - return errors.New("uncles not allowed") + return errUncleDetected } return nil @@ -602,7 +624,7 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header return err } - if !snap.ValidatorSet.HasAddress(signer.Bytes()) { + if !snap.ValidatorSet.HasAddress(signer) { // Check the UnauthorizedSignerError.Error() msg to see why we pass number-1 return &UnauthorizedSignerError{number - 1, signer.Bytes()} } @@ -619,13 +641,13 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header parent = chain.GetHeader(header.ParentHash, number-1) } - if parent != nil && header.Time < parent.Time+CalcProducerDelay(number, succession, c.config) { + if IsBlockOnTime(parent, header, number, succession, c.config) { return &BlockTooSoonError{number, succession} } // Ensure that the difficulty corresponds to the turn-ness of the signer if !c.fakeDiff { - difficulty := snap.Difficulty(signer) + difficulty := Difficulty(snap.ValidatorSet, signer) if header.Difficulty.Uint64() != difficulty { return &WrongDifficultyError{number, difficulty, header.Difficulty.Uint64(), signer.Bytes()} } @@ -634,6 +656,10 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header return nil } +func IsBlockOnTime(parent *types.Header, header *types.Header, number uint64, succession int, cfg *params.BorConfig) bool { + return parent != nil && header.Time < parent.Time+CalcProducerDelay(number, succession, cfg) +} + // Prepare implements consensus.Engine, preparing all the consensus fields of the // header for running the transactions on top. func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { @@ -648,8 +674,10 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e return err } + currentSigner := *c.authorizedSigner.Load() + // Set the correct difficulty - header.Difficulty = new(big.Int).SetUint64(snap.Difficulty(c.signer)) + header.Difficulty = new(big.Int).SetUint64(Difficulty(snap.ValidatorSet, currentSigner.signer)) // Ensure the extra data has all it's components if len(header.Extra) < extraVanity { @@ -659,10 +687,10 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e header.Extra = header.Extra[:extraVanity] // get validator set if number - if IsSprintStart(number+1, c.config.Sprint) { - newValidators, err := c.spanner.GetCurrentValidators(header.ParentHash, number+1) + if IsSprintStart(number+1, c.config.CalculateSprint(number)) { + newValidators, err := c.spanner.GetCurrentValidators(context.Background(), header.ParentHash, number+1) if err != nil { - return errors.New("unknown validators") + return errUnknownValidators } // sort validator by address @@ -687,8 +715,8 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e var succession int // if signer is not empty - if c.signer != (common.Address{}) { - succession, err = snap.GetSignerSuccessionNumber(c.signer) + if currentSigner.signer != (common.Address{}) { + succession, err = snap.GetSignerSuccessionNumber(currentSigner.signer) if err != nil { return err } @@ -704,24 +732,26 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e // Finalize implements consensus.Engine, ensuring no uncles are set, nor block // rewards given. -func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { - stateSyncData := []*types.StateSyncData{} - - var err error +func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, _ []*types.Transaction, _ []*types.Header) { + var ( + stateSyncData []*types.StateSyncData + err error + ) headerNumber := header.Number.Uint64() - if headerNumber%c.config.Sprint == 0 { + if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) { + ctx := context.Background() cx := statefull.ChainContext{Chain: chain, Bor: c} // check and commit span - if err := c.checkAndCommitSpan(state, header, cx); err != nil { + if err := c.checkAndCommitSpan(ctx, state, header, cx); err != nil { log.Error("Error while committing span", "error", err) return } if c.HeimdallClient != nil { - // commit statees - stateSyncData, err = c.CommitStates(state, header, cx) + // commit states + stateSyncData, err = c.CommitStates(ctx, state, header, cx) if err != nil { log.Error("Error while committing states", "error", err) return @@ -763,7 +793,7 @@ func (c *Bor) changeContractCodeIfNeeded(headerNumber uint64, state *state.State if blockNumber == strconv.FormatUint(headerNumber, 10) { allocs, err := decodeGenesisAlloc(genesisAlloc) if err != nil { - return fmt.Errorf("failed to decode genesis alloc: %v", err) + return fmt.Errorf("failed to decode genesis alloc: %w", err) } for addr, account := range allocs { @@ -778,24 +808,35 @@ func (c *Bor) changeContractCodeIfNeeded(headerNumber uint64, state *state.State // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, // nor block rewards given, and returns the final block. -func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { +func (c *Bor) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { + finalizeCtx, finalizeSpan := tracing.StartSpan(ctx, "bor.FinalizeAndAssemble") + defer tracing.EndSpan(finalizeSpan) + stateSyncData := []*types.StateSyncData{} headerNumber := header.Number.Uint64() - if headerNumber%c.config.Sprint == 0 { + var err error + + if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) { cx := statefull.ChainContext{Chain: chain, Bor: c} - // check and commit span - err := c.checkAndCommitSpan(state, header, cx) + tracing.Exec(finalizeCtx, "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) { + // check and commit span + err = c.checkAndCommitSpan(finalizeCtx, state, header, cx) + }) + if err != nil { log.Error("Error while committing span", "error", err) return nil, err } if c.HeimdallClient != nil { - // commit states - stateSyncData, err = c.CommitStates(state, header, cx) + tracing.Exec(finalizeCtx, "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) { + // commit states + stateSyncData, err = c.CommitStates(finalizeCtx, state, header, cx) + }) + if err != nil { log.Error("Error while committing states", "error", err) return nil, err @@ -803,13 +844,21 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ } } - if err := c.changeContractCodeIfNeeded(headerNumber, state); err != nil { + tracing.Exec(finalizeCtx, "bor.changeContractCodeIfNeeded", func(ctx context.Context, span trace.Span) { + err = c.changeContractCodeIfNeeded(headerNumber, state) + }) + + if err != nil { log.Error("Error changing contract code", "error", err) return nil, err } - // No block rewards in PoA, so the state remains as is and uncles are dropped - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + // No block rewards in PoA, so the state remains as it is + tracing.Exec(finalizeCtx, "bor.IntermediateRoot", func(ctx context.Context, span trace.Span) { + header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + }) + + // Uncles are dropped header.UncleHash = types.CalcUncleHash(nil) // Assemble block @@ -819,23 +868,41 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ bc := chain.(core.BorStateSyncer) bc.SetStateSync(stateSyncData) + tracing.SetAttributes( + finalizeSpan, + attribute.Int("number", int(header.Number.Int64())), + attribute.String("hash", header.Hash().String()), + attribute.Int("number of txs", len(txs)), + attribute.Int("gas used", int(block.GasUsed())), + ) + // return the final block for sealing return block, nil } // Authorize injects a private key into the consensus engine to mint new blocks // with. -func (c *Bor) Authorize(signer common.Address, signFn SignerFn) { - c.lock.Lock() - defer c.lock.Unlock() - - c.signer = signer - c.signFn = signFn +func (c *Bor) Authorize(currentSigner common.Address, signFn SignerFn) { + c.authorizedSigner.Store(&signer{ + signer: currentSigner, + signFn: signFn, + }) } // Seal implements consensus.Engine, attempting to create a sealed block using // the local signing credentials. -func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { +func (c *Bor) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { + _, sealSpan := tracing.StartSpan(ctx, "bor.Seal") + + var endSpan bool = true + + defer func() { + // Only end span in case of early-returns/errors + if endSpan { + tracing.EndSpan(sealSpan) + } + }() + header := block.Header() // Sealing the genesis block is not supported number := header.Number.Uint64() @@ -847,10 +914,9 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result log.Info("Sealing paused, waiting for transactions") return nil } + // Don't hold the signer fields for the entire sealing procedure - c.lock.RLock() - signer, signFn := c.signer, c.signFn - c.lock.RUnlock() + currentSigner := *c.authorizedSigner.Load() snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) if err != nil { @@ -858,12 +924,12 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result } // Bail out if we're unauthorized to sign a block - if !snap.ValidatorSet.HasAddress(signer.Bytes()) { + if !snap.ValidatorSet.HasAddress(currentSigner.signer) { // Check the UnauthorizedSignerError.Error() msg to see why we pass number-1 - return &UnauthorizedSignerError{number - 1, signer.Bytes()} + return &UnauthorizedSignerError{number - 1, currentSigner.signer.Bytes()} } - successionNumber, err := snap.GetSignerSuccessionNumber(signer) + successionNumber, err := snap.GetSignerSuccessionNumber(currentSigner.signer) if err != nil { return err } @@ -874,7 +940,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result wiggle := time.Duration(successionNumber) * time.Duration(c.config.CalculateBackupMultiplier(number)) * time.Second // Sign all the things! - err = Sign(signFn, signer, header, c.config) + err = Sign(currentSigner.signFn, currentSigner.signer, header, c.config) if err != nil { return err } @@ -882,7 +948,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result // Wait until sealing is terminated or delay timeout. log.Info("Waiting for slot to sign and propagate", "number", number, "hash", header.Hash, "delay-in-sec", uint(delay), "delay", common.PrettyDuration(delay)) - go func() { + go func(sealSpan trace.Span) { select { case <-stop: log.Debug("Discarding sealing operation for block", "number", number) @@ -905,13 +971,27 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result "delay", delay, "headerDifficulty", header.Difficulty, ) + + tracing.SetAttributes( + sealSpan, + attribute.Int("number", int(number)), + attribute.String("hash", header.Hash().String()), + attribute.Int("delay", int(delay.Milliseconds())), + attribute.Int("wiggle", int(wiggle.Milliseconds())), + attribute.Bool("out-of-turn", wiggle > 0), + ) + + tracing.EndSpan(sealSpan) } select { case results <- block.WithSeal(header): default: log.Warn("Sealing result was not read by miner", "number", number, "sealhash", SealHash(header, c.config)) } - }() + }(sealSpan) + + // Set the endSpan flag to false, as the go routine will handle it + endSpan = false return nil } @@ -930,13 +1010,13 @@ func Sign(signFn SignerFn, signer common.Address, header *types.Header, c *param // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty // that a new block should have based on the previous blocks in the chain and the // current signer. -func (c *Bor) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { +func (c *Bor) CalcDifficulty(chain consensus.ChainHeaderReader, _ uint64, parent *types.Header) *big.Int { snap, err := c.snapshot(chain, parent.Number.Uint64(), parent.Hash(), nil) if err != nil { return nil } - return new(big.Int).SetUint64(snap.Difficulty(c.signer)) + return new(big.Int).SetUint64(Difficulty(snap.ValidatorSet, c.authorizedSigner.Load().signer)) } // SealHash returns the hash of a block prior to it being sealed. @@ -967,37 +1047,38 @@ func (c *Bor) Close() error { } func (c *Bor) checkAndCommitSpan( + ctx context.Context, state *state.StateDB, header *types.Header, chain core.ChainContext, ) error { headerNumber := header.Number.Uint64() - span, err := c.spanner.GetCurrentSpan(header.ParentHash) + span, err := c.spanner.GetCurrentSpan(ctx, header.ParentHash) if err != nil { return err } if c.needToCommitSpan(span, headerNumber) { - return c.FetchAndCommitSpan(span.ID+1, state, header, chain) + return c.FetchAndCommitSpan(ctx, span.ID+1, state, header, chain) } return nil } -func (c *Bor) needToCommitSpan(span *span.Span, headerNumber uint64) bool { +func (c *Bor) needToCommitSpan(currentSpan *span.Span, headerNumber uint64) bool { // if span is nil - if span == nil { + if currentSpan == nil { return false } // check span is not set initially - if span.EndBlock == 0 { + if currentSpan.EndBlock == 0 { return true } // if current block is first block of last sprint in current span - if span.EndBlock > c.config.Sprint && span.EndBlock-c.config.Sprint+1 == headerNumber { + if currentSpan.EndBlock > c.config.CalculateSprint(headerNumber) && currentSpan.EndBlock-c.config.CalculateSprint(headerNumber)+1 == headerNumber { return true } @@ -1005,6 +1086,7 @@ func (c *Bor) needToCommitSpan(span *span.Span, headerNumber uint64) bool { } func (c *Bor) FetchAndCommitSpan( + ctx context.Context, newSpanID uint64, state *state.StateDB, header *types.Header, @@ -1014,14 +1096,14 @@ func (c *Bor) FetchAndCommitSpan( if c.HeimdallClient == nil { // fixme: move to a new mock or fake and remove c.HeimdallClient completely - s, err := c.getNextHeimdallSpanForTest(newSpanID, header, chain) + s, err := c.getNextHeimdallSpanForTest(ctx, newSpanID, header, chain) if err != nil { return err } heimdallSpan = *s } else { - response, err := c.HeimdallClient.Span(newSpanID) + response, err := c.HeimdallClient.Span(ctx, newSpanID) if err != nil { return err } @@ -1038,16 +1120,17 @@ func (c *Bor) FetchAndCommitSpan( ) } - return c.spanner.CommitSpan(heimdallSpan, state, header, chain) + return c.spanner.CommitSpan(ctx, heimdallSpan, state, header, chain) } // CommitStates commit states func (c *Bor) CommitStates( + ctx context.Context, state *state.StateDB, header *types.Header, chain statefull.ChainContext, ) ([]*types.StateSyncData, error) { - stateSyncs := make([]*types.StateSyncData, 0) + fetchStart := time.Now() number := header.Number.Uint64() _lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1) @@ -1055,7 +1138,7 @@ func (c *Bor) CommitStates( return nil, err } - to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.Sprint).Time), 0) + to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.CalculateSprint(number)).Time), 0) lastStateID := _lastStateID.Uint64() log.Info( @@ -1063,7 +1146,7 @@ func (c *Bor) CommitStates( "fromID", lastStateID+1, "to", to.Format(time.RFC3339)) - eventRecords, err := c.HeimdallClient.StateSyncEvents(lastStateID+1, to.Unix()) + eventRecords, err := c.HeimdallClient.StateSyncEvents(ctx, lastStateID+1, to.Unix()) if err != nil { log.Error("Error occurred when fetching state sync events", "stateID", lastStateID+1, "error", err) } @@ -1074,16 +1157,20 @@ func (c *Bor) CommitStates( } } + fetchTime := time.Since(fetchStart) + processStart := time.Now() totalGas := 0 /// limit on gas for state sync per block - chainID := c.chainConfig.ChainID.String() + stateSyncs := make([]*types.StateSyncData, len(eventRecords)) + + var gasUsed uint64 for _, eventRecord := range eventRecords { if eventRecord.ID <= lastStateID { continue } - if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil { + if err = validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil { log.Error("while validating event record", "block", number, "to", to, "stateID", lastStateID, "error", err.Error()) break } @@ -1097,7 +1184,10 @@ func (c *Bor) CommitStates( stateSyncs = append(stateSyncs, &stateData) - gasUsed, err := c.GenesisContractsClient.CommitState(eventRecord, state, header, chain) + // we expect that this call MUST emit an event, otherwise we wouldn't make a receipt + // if the receiver address is not a contract then we'll skip the most of the execution and emitting an event as well + // https://github.com/maticnetwork/genesis-contracts/blob/master/contracts/StateReceiver.sol#L27 + gasUsed, err = c.GenesisContractsClient.CommitState(eventRecord, state, header, chain) if err != nil { return nil, err } @@ -1107,7 +1197,9 @@ func (c *Bor) CommitStates( lastStateID++ } - log.Info("StateSyncData", "Gas", totalGas, "Block-number", number, "LastStateID", lastStateID, "TotalRecords", len(eventRecords)) + processTime := time.Since(processStart) + + log.Info("StateSyncData", "gas", totalGas, "number", number, "lastStateID", lastStateID, "total records", len(eventRecords), "fetch time", int(fetchTime.Milliseconds()), "process time", int(processTime.Milliseconds())) return stateSyncs, nil } @@ -1125,8 +1217,8 @@ func (c *Bor) SetHeimdallClient(h IHeimdallClient) { c.HeimdallClient = h } -func (c *Bor) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) { - return c.spanner.GetCurrentValidators(headerHash, blockNumber) +func (c *Bor) GetCurrentValidators(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) { + return c.spanner.GetCurrentValidators(ctx, headerHash, blockNumber) } // @@ -1134,13 +1226,14 @@ func (c *Bor) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ( // func (c *Bor) getNextHeimdallSpanForTest( + ctx context.Context, newSpanID uint64, header *types.Header, chain core.ChainContext, ) (*span.HeimdallSpan, error) { headerNumber := header.Number.Uint64() - spanBor, err := c.spanner.GetCurrentSpan(header.ParentHash) + spanBor, err := c.spanner.GetCurrentSpan(ctx, header.ParentHash) if err != nil { return nil, err } @@ -1161,7 +1254,7 @@ func (c *Bor) getNextHeimdallSpanForTest( spanBor.StartBlock = spanBor.EndBlock + 1 } - spanBor.EndBlock = spanBor.StartBlock + (100 * c.config.Sprint) - 1 + spanBor.EndBlock = spanBor.StartBlock + (100 * c.config.CalculateSprint(headerNumber)) - 1 selectedProducers := make([]valset.Validator, len(snap.ValidatorSet.Validators)) for i, v := range snap.ValidatorSet.Validators { diff --git a/consensus/bor/bor_test.go b/consensus/bor/bor_test.go index 6225532ca9..9ca361a18d 100644 --- a/consensus/bor/bor_test.go +++ b/consensus/bor/bor_test.go @@ -4,10 +4,10 @@ import ( "math/big" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/hexutil" //nolint:typecheck "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" @@ -23,7 +23,9 @@ func TestGenesisContractChange(t *testing.T) { b := &Bor{ config: ¶ms.BorConfig{ - Sprint: 10, // skip sprint transactions in sprint + Sprint: map[string]uint64{ + "0": 10, + }, // skip sprint transactions in sprint BlockAlloc: map[string]interface{}{ // write as interface since that is how it is decoded in genesis "2": map[string]interface{}{ @@ -55,11 +57,11 @@ func TestGenesisContractChange(t *testing.T) { genesis := genspec.MustCommit(db) statedb, err := state.New(genesis.Root(), state.NewDatabase(db), nil) - assert.NoError(t, err) + require.NoError(t, err) config := params.ChainConfig{} - chain, err := core.NewBlockChain(db, nil, &config, b, vm.Config{}, nil, nil) - assert.NoError(t, err) + chain, err := core.NewBlockChain(db, nil, &config, b, vm.Config{}, nil, nil, nil) + require.NoError(t, err) addBlock := func(root common.Hash, num int64) (common.Hash, *state.StateDB) { h := &types.Header{ @@ -70,37 +72,37 @@ func TestGenesisContractChange(t *testing.T) { // write state to database root, err := statedb.Commit(false) - assert.NoError(t, err) - assert.NoError(t, statedb.Database().TrieDB().Commit(root, true, nil)) + require.NoError(t, err) + require.NoError(t, statedb.Database().TrieDB().Commit(root, true, nil)) statedb, err := state.New(h.Root, state.NewDatabase(db), nil) - assert.NoError(t, err) + require.NoError(t, err) return root, statedb } - assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1}) + require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1}) root := genesis.Root() // code does not change root, statedb = addBlock(root, 1) - assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1}) + require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x1}) // code changes 1st time root, statedb = addBlock(root, 2) - assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2}) + require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2}) // code same as 1st change root, statedb = addBlock(root, 3) - assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2}) + require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x2}) // code changes 2nd time _, statedb = addBlock(root, 4) - assert.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x3}) + require.Equal(t, statedb.GetCode(addr0), []byte{0x1, 0x3}) // make sure balance change DOES NOT take effect - assert.Equal(t, statedb.GetBalance(addr0), big.NewInt(0)) + require.Equal(t, statedb.GetBalance(addr0), big.NewInt(0)) } func TestEncodeSigHeaderJaipur(t *testing.T) { @@ -123,20 +125,20 @@ func TestEncodeSigHeaderJaipur(t *testing.T) { ) // Jaipur NOT enabled and BaseFee not set - hash := SealHash(h, ¶ms.BorConfig{JaipurBlock: 10}) - assert.Equal(t, hash, hashWithoutBaseFee) + hash := SealHash(h, ¶ms.BorConfig{JaipurBlock: big.NewInt(10)}) + require.Equal(t, hash, hashWithoutBaseFee) // Jaipur enabled (Jaipur=0) and BaseFee not set - hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 0}) - assert.Equal(t, hash, hashWithoutBaseFee) + hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: common.Big0}) + require.Equal(t, hash, hashWithoutBaseFee) h.BaseFee = big.NewInt(2) // Jaipur enabled (Jaipur=Header block) and BaseFee set - hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 1}) - assert.Equal(t, hash, hashWithBaseFee) + hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: common.Big1}) + require.Equal(t, hash, hashWithBaseFee) // Jaipur NOT enabled and BaseFee set - hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 10}) - assert.Equal(t, hash, hashWithoutBaseFee) + hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: big.NewInt(10)}) + require.Equal(t, hash, hashWithoutBaseFee) } diff --git a/consensus/bor/contract/client.go b/consensus/bor/contract/client.go index d65fb5bb15..9e9e1392dd 100644 --- a/consensus/bor/contract/client.go +++ b/consensus/bor/contract/client.go @@ -88,7 +88,7 @@ func (gc *GenesisContractsClient) CommitState( } msg := statefull.GetSystemMessage(common.HexToAddress(gc.StateReceiverContract), data) - gasUsed, err := statefull.ApplyMessage(msg, state, header, gc.chainConfig, chCtx) + gasUsed, err := statefull.ApplyMessage(context.Background(), msg, state, header, gc.chainConfig, chCtx) // Logging event log with time and individual gasUsed log.Info("→ committing new state", "eventRecord", event.String(gasUsed)) @@ -102,7 +102,8 @@ func (gc *GenesisContractsClient) CommitState( func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) { blockNr := rpc.BlockNumber(snapshotNumber) - method := "lastStateId" + + const method = "lastStateId" data, err := gc.stateReceiverABI.Pack(method) if err != nil { diff --git a/consensus/bor/heimdall.go b/consensus/bor/heimdall.go index 217de13fe9..8934e07cb4 100644 --- a/consensus/bor/heimdall.go +++ b/consensus/bor/heimdall.go @@ -1,6 +1,8 @@ package bor import ( + "context" + "github.com/ethereum/go-ethereum/consensus/bor/clerk" "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint" "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" @@ -8,8 +10,9 @@ import ( //go:generate mockgen -destination=../../tests/bor/mocks/IHeimdallClient.go -package=mocks . IHeimdallClient type IHeimdallClient interface { - StateSyncEvents(fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) - Span(spanID uint64) (*span.HeimdallSpan, error) - FetchLatestCheckpoint() (*checkpoint.Checkpoint, error) + StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) + Span(ctx context.Context, spanID uint64) (*span.HeimdallSpan, error) + FetchCheckpoint(ctx context.Context, number int64) (*checkpoint.Checkpoint, error) + FetchCheckpointCount(ctx context.Context) (int64, error) Close() } diff --git a/consensus/bor/heimdall/checkpoint/checkpoint.go b/consensus/bor/heimdall/checkpoint/checkpoint.go index 77569293ad..3f85f2a233 100644 --- a/consensus/bor/heimdall/checkpoint/checkpoint.go +++ b/consensus/bor/heimdall/checkpoint/checkpoint.go @@ -20,3 +20,12 @@ type CheckpointResponse struct { Height string `json:"height"` Result Checkpoint `json:"result"` } + +type CheckpointCount struct { + Result int64 `json:"result"` +} + +type CheckpointCountResponse struct { + Height string `json:"height"` + Result CheckpointCount `json:"result"` +} diff --git a/consensus/bor/heimdall/client.go b/consensus/bor/heimdall/client.go index 2d42cfc31b..b6daa7e8d8 100644 --- a/consensus/bor/heimdall/client.go +++ b/consensus/bor/heimdall/client.go @@ -5,7 +5,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "sort" @@ -15,14 +15,20 @@ import ( "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint" "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" ) -// errShutdownDetected is returned if a shutdown was detected -var errShutdownDetected = errors.New("shutdown detected") +var ( + // ErrShutdownDetected is returned if a shutdown was detected + ErrShutdownDetected = errors.New("shutdown detected") + ErrNoResponse = errors.New("got a nil response") + ErrNotSuccessfulResponse = errors.New("error while fetching data from Heimdall") +) const ( stateFetchLimit = 50 apiHeimdallTimeout = 5 * time.Second + retryCall = 5 * time.Second ) type StateSyncEventsResponse struct { @@ -41,6 +47,12 @@ type HeimdallClient struct { closeCh chan struct{} } +type Request struct { + client http.Client + url *url.URL + start time.Time +} + func NewHeimdallClient(urlString string) *HeimdallClient { return &HeimdallClient{ urlString: urlString, @@ -54,12 +66,13 @@ func NewHeimdallClient(urlString string) *HeimdallClient { const ( fetchStateSyncEventsFormat = "from-id=%d&to-time=%d&limit=%d" fetchStateSyncEventsPath = "clerk/event-record/list" - fetchLatestCheckpoint = "/checkpoints/latest" + fetchCheckpoint = "/checkpoints/%s" + fetchCheckpointCount = "/checkpoints/count" fetchSpanFormat = "bor/span/%d" ) -func (h *HeimdallClient) StateSyncEvents(fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) { +func (h *HeimdallClient) StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) { eventRecords := make([]*clerk.EventRecordWithTime, 0) for { @@ -70,7 +83,9 @@ func (h *HeimdallClient) StateSyncEvents(fromID uint64, to int64) ([]*clerk.Even log.Info("Fetching state sync events", "queryParams", url.RawQuery) - response, err := FetchWithRetry[StateSyncEventsResponse](h.client, url, h.closeCh) + ctx = withRequestType(ctx, stateSyncRequest) + + response, err := FetchWithRetry[StateSyncEventsResponse](ctx, h.client, url, h.closeCh) if err != nil { return nil, err } @@ -96,13 +111,15 @@ func (h *HeimdallClient) StateSyncEvents(fromID uint64, to int64) ([]*clerk.Even return eventRecords, nil } -func (h *HeimdallClient) Span(spanID uint64) (*span.HeimdallSpan, error) { +func (h *HeimdallClient) Span(ctx context.Context, spanID uint64) (*span.HeimdallSpan, error) { url, err := spanURL(h.urlString, spanID) if err != nil { return nil, err } - response, err := FetchWithRetry[SpanResponse](h.client, url, h.closeCh) + ctx = withRequestType(ctx, spanRequest) + + response, err := FetchWithRetry[SpanResponse](ctx, h.client, url, h.closeCh) if err != nil { return nil, err } @@ -110,14 +127,16 @@ func (h *HeimdallClient) Span(spanID uint64) (*span.HeimdallSpan, error) { return &response.Result, nil } -// FetchLatestCheckpoint fetches the latest bor submitted checkpoint from heimdall -func (h *HeimdallClient) FetchLatestCheckpoint() (*checkpoint.Checkpoint, error) { - url, err := latestCheckpointURL(h.urlString) +// FetchCheckpoint fetches the checkpoint from heimdall +func (h *HeimdallClient) FetchCheckpoint(ctx context.Context, number int64) (*checkpoint.Checkpoint, error) { + url, err := checkpointURL(h.urlString, number) if err != nil { return nil, err } - response, err := FetchWithRetry[checkpoint.CheckpointResponse](h.client, url, h.closeCh) + ctx = withRequestType(ctx, checkpointRequest) + + response, err := FetchWithRetry[checkpoint.CheckpointResponse](ctx, h.client, url, h.closeCh) if err != nil { return nil, err } @@ -125,59 +144,107 @@ func (h *HeimdallClient) FetchLatestCheckpoint() (*checkpoint.Checkpoint, error) return &response.Result, nil } +// FetchCheckpointCount fetches the checkpoint count from heimdall +func (h *HeimdallClient) FetchCheckpointCount(ctx context.Context) (int64, error) { + url, err := checkpointCountURL(h.urlString) + if err != nil { + return 0, err + } + + ctx = withRequestType(ctx, checkpointCountRequest) + + response, err := FetchWithRetry[checkpoint.CheckpointCountResponse](ctx, h.client, url, h.closeCh) + if err != nil { + return 0, err + } + + return response.Result.Result, nil +} + // FetchWithRetry returns data from heimdall with retry -func FetchWithRetry[T any](client http.Client, url *url.URL, closeCh chan struct{}) (*T, error) { - // attempt counter - attempt := 1 - result := new(T) - - ctx, cancel := context.WithTimeout(context.Background(), apiHeimdallTimeout) - +func FetchWithRetry[T any](ctx context.Context, client http.Client, url *url.URL, closeCh chan struct{}) (*T, error) { // request data once - body, err := internalFetch(ctx, client, url) - - cancel() - - if err == nil && body != nil { - err = json.Unmarshal(body, result) - if err != nil { - return nil, err - } + request := &Request{client: client, url: url, start: time.Now()} + result, err := Fetch[T](ctx, request) + if err == nil { return result, nil } + // attempt counter + attempt := 1 + + log.Warn("an error while trying fetching from Heimdall", "attempt", attempt, "error", err) + // create a new ticker for retrying the request - ticker := time.NewTicker(5 * time.Second) + ticker := time.NewTicker(retryCall) defer ticker.Stop() + const logEach = 5 + +retryLoop: for { log.Info("Retrying again in 5 seconds to fetch data from Heimdall", "path", url.Path, "attempt", attempt) + attempt++ + select { + case <-ctx.Done(): + log.Debug("Shutdown detected, terminating request by context.Done") + + return nil, ctx.Err() case <-closeCh: - log.Debug("Shutdown detected, terminating request") + log.Debug("Shutdown detected, terminating request by closing") - return nil, errShutdownDetected + return nil, ErrShutdownDetected case <-ticker.C: - ctx, cancel = context.WithTimeout(context.Background(), apiHeimdallTimeout) + request = &Request{client: client, url: url, start: time.Now()} + result, err = Fetch[T](ctx, request) - body, err = internalFetch(ctx, client, url) - - cancel() - - if err == nil && body != nil { - err = json.Unmarshal(body, result) - if err != nil { - return nil, err + if err != nil { + if attempt%logEach == 0 { + log.Warn("an error while trying fetching from Heimdall", "attempt", attempt, "error", err) } - return result, nil + continue retryLoop } + + return result, nil } } } +// Fetch returns data from heimdall +func Fetch[T any](ctx context.Context, request *Request) (*T, error) { + isSuccessful := false + + defer func() { + if metrics.EnabledExpensive { + sendMetrics(ctx, request.start, isSuccessful) + } + }() + + result := new(T) + + body, err := internalFetchWithTimeout(ctx, request.client, request.url) + if err != nil { + return nil, err + } + + if body == nil { + return nil, ErrNoResponse + } + + err = json.Unmarshal(body, result) + if err != nil { + return nil, err + } + + isSuccessful = true + + return result, nil +} + func spanURL(urlString string, spanID uint64) (*url.URL, error) { return makeURL(urlString, fmt.Sprintf(fetchSpanFormat, spanID), "") } @@ -188,8 +255,19 @@ func stateSyncURL(urlString string, fromID uint64, to int64) (*url.URL, error) { return makeURL(urlString, fetchStateSyncEventsPath, queryParams) } -func latestCheckpointURL(urlString string) (*url.URL, error) { - return makeURL(urlString, fetchLatestCheckpoint, "") +func checkpointURL(urlString string, number int64) (*url.URL, error) { + url := "" + if number == -1 { + url = fmt.Sprintf(fetchCheckpoint, "latest") + } else { + url = fmt.Sprintf(fetchCheckpoint, fmt.Sprint(number)) + } + + return makeURL(urlString, url, "") +} + +func checkpointCountURL(urlString string) (*url.URL, error) { + return makeURL(urlString, fetchCheckpointCount, "") } func makeURL(urlString, rawPath, rawQuery string) (*url.URL, error) { @@ -215,11 +293,12 @@ func internalFetch(ctx context.Context, client http.Client, u *url.URL) ([]byte, if err != nil { return nil, err } + defer res.Body.Close() // check status code if res.StatusCode != 200 && res.StatusCode != 204 { - return nil, fmt.Errorf("Error while fetching data from Heimdall") + return nil, fmt.Errorf("%w: response code %d", ErrNotSuccessfulResponse, res.StatusCode) } // unmarshall data from buffer @@ -228,7 +307,7 @@ func internalFetch(ctx context.Context, client http.Client, u *url.URL) ([]byte, } // get response - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return nil, err } @@ -236,6 +315,14 @@ func internalFetch(ctx context.Context, client http.Client, u *url.URL) ([]byte, return body, nil } +func internalFetchWithTimeout(ctx context.Context, client http.Client, url *url.URL) ([]byte, error) { + ctx, cancel := context.WithTimeout(ctx, apiHeimdallTimeout) + defer cancel() + + // request data once + return internalFetch(ctx, client, url) +} + // Close sends a signal to stop the running process func (h *HeimdallClient) Close() { close(h.closeCh) diff --git a/consensus/bor/heimdall/client_test.go b/consensus/bor/heimdall/client_test.go index c423a6f659..22265c1975 100644 --- a/consensus/bor/heimdall/client_test.go +++ b/consensus/bor/heimdall/client_test.go @@ -1,9 +1,306 @@ package heimdall import ( + "context" + "encoding/json" + "errors" + "fmt" + "math/big" + "net" + "net/http" + "sync" "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/network" + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint" + + "github.com/stretchr/testify/require" ) +// HttpHandlerFake defines the handler functions required to serve +// requests to the mock heimdal server for specific functions. Add more handlers +// according to requirements. +type HttpHandlerFake struct { + handleFetchCheckpoint http.HandlerFunc +} + +func (h *HttpHandlerFake) GetCheckpointHandler() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + h.handleFetchCheckpoint.ServeHTTP(w, r) + } +} + +func CreateMockHeimdallServer(wg *sync.WaitGroup, port int, listener net.Listener, handler *HttpHandlerFake) (*http.Server, error) { + // Create a new server mux + mux := http.NewServeMux() + + // Create a route for fetching latest checkpoint + mux.HandleFunc("/checkpoints/latest", func(w http.ResponseWriter, r *http.Request) { + handler.GetCheckpointHandler()(w, r) + }) + + // Add other routes as per requirement + + // Create the server with given port and mux + srv := &http.Server{ + Addr: fmt.Sprintf("localhost:%d", port), + Handler: mux, + } + + // Close the listener using the port and immediately consume it below + err := listener.Close() + if err != nil { + return nil, err + } + + go func() { + defer wg.Done() + + // always returns error. ErrServerClosed on graceful close + if err := srv.ListenAndServe(); err != http.ErrServerClosed { + fmt.Printf("error in server.ListenAndServe(): %v", err) + } + }() + + return srv, nil +} + +// TestFetchCheckpointFromMockHeimdall tests the heimdall client side logic +// to fetch checkpoints (latest for the scope of test) from a mock heimdall server. +// It can be used for debugging purpose (like response fields, marshalling/unmarshalling, etc). +func TestFetchCheckpointFromMockHeimdall(t *testing.T) { + t.Parallel() + + // Create a wait group for sending across the mock server + wg := &sync.WaitGroup{} + wg.Add(1) + + // Initialize the fake handler and add a fake checkpoint handler function + handler := &HttpHandlerFake{} + handler.handleFetchCheckpoint = func(w http.ResponseWriter, _ *http.Request) { + err := json.NewEncoder(w).Encode(checkpoint.CheckpointResponse{ + Height: "0", + Result: checkpoint.Checkpoint{ + Proposer: common.Address{}, + StartBlock: big.NewInt(0), + EndBlock: big.NewInt(512), + RootHash: common.Hash{}, + BorChainID: "15001", + Timestamp: 0, + }, + }) + + if err != nil { + w.WriteHeader(500) // Return 500 Internal Server Error. + } + } + + // Fetch available port + port, listener, err := network.FindAvailablePort() + require.NoError(t, err, "expect no error in finding available port") + + // Create mock heimdall server and pass handler instance for setting up the routes + srv, err := CreateMockHeimdallServer(wg, port, listener, handler) + require.NoError(t, err, "expect no error in starting mock heimdall server") + + // Create a new heimdall client and use same port for connection + client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port)) + _, err = client.FetchCheckpoint(context.Background(), -1) + require.NoError(t, err, "expect no error in fetching checkpoint") + + // Shutdown the server + err = srv.Shutdown(context.TODO()) + require.NoError(t, err, "expect no error in shutting down mock heimdall server") + + // Wait for `wg.Done()` to be called in the mock server's routine. + wg.Wait() +} + +// TestFetchShutdown tests the heimdall client side logic for context timeout and +// interrupt handling while fetching checkpoints (latest for the scope of test) +// from a mock heimdall server. +func TestFetchShutdown(t *testing.T) { + t.Parallel() + + // Create a wait group for sending across the mock server + wg := &sync.WaitGroup{} + wg.Add(1) + + // Initialize the fake handler and add a fake checkpoint handler function + handler := &HttpHandlerFake{} + + // Case1 - Testing context timeout: Create delay in serving requests for simulating timeout. Add delay slightly + // greater than `retryDelay`. This should cause the request to timeout and trigger shutdown + // due to `ctx.Done()`. Expect context timeout error. + handler.handleFetchCheckpoint = func(w http.ResponseWriter, _ *http.Request) { + time.Sleep(6 * time.Second) + + err := json.NewEncoder(w).Encode(checkpoint.CheckpointResponse{ + Height: "0", + Result: checkpoint.Checkpoint{ + Proposer: common.Address{}, + StartBlock: big.NewInt(0), + EndBlock: big.NewInt(512), + RootHash: common.Hash{}, + BorChainID: "15001", + Timestamp: 0, + }, + }) + + if err != nil { + w.WriteHeader(500) // Return 500 Internal Server Error. + } + } + + // Fetch available port + port, listener, err := network.FindAvailablePort() + require.NoError(t, err, "expect no error in finding available port") + + // Create mock heimdall server and pass handler instance for setting up the routes + srv, err := CreateMockHeimdallServer(wg, port, listener, handler) + require.NoError(t, err, "expect no error in starting mock heimdall server") + + // Create a new heimdall client and use same port for connection + client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port)) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + + // Expect this to fail due to timeout + _, err = client.FetchCheckpoint(ctx, -1) + require.Equal(t, "context deadline exceeded", err.Error(), "expect the function error to be a context deadline exeeded error") + require.Equal(t, "context deadline exceeded", ctx.Err().Error(), "expect the ctx error to be a context deadline exeeded error") + + cancel() + + // Case2 - Testing context cancellation. Pass a context with timeout to the request and + // cancel it before timeout. This should cause the request to timeout and trigger shutdown + // due to `ctx.Done()`. Expect context cancellation error. + handler.handleFetchCheckpoint = func(w http.ResponseWriter, _ *http.Request) { + time.Sleep(10 * time.Millisecond) + w.WriteHeader(500) // Return 500 Internal Server Error. + } + + ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second) // Use some high value for timeout + + // Cancel the context after a delay until we make request + go func(cancel context.CancelFunc) { + time.Sleep(10 * time.Millisecond) + cancel() + }(cancel) + + // Expect this to fail due to cancellation + _, err = client.FetchCheckpoint(ctx, -1) + require.Equal(t, "context canceled", err.Error(), "expect the function error to be a context cancelled error") + require.Equal(t, "context canceled", ctx.Err().Error(), "expect the ctx error to be a context cancelled error") + + // Case3 - Testing interrupt: Closing the `closeCh` in heimdall client simulating interrupt. This + // should cause the request to fail and throw an error due to `<-closeCh` in fetchWithRetry. + // Expect shutdown detected error. + handler.handleFetchCheckpoint = func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(500) // Return 500 Internal Server Error. + } + + // Close the channel after a delay until we make request + go func() { + time.Sleep(1 * time.Second) + close(client.closeCh) + }() + + // Expect this to fail due to shutdown + _, err = client.FetchCheckpoint(context.Background(), -1) + require.Equal(t, ErrShutdownDetected.Error(), err.Error(), "expect the function error to be a shutdown detected error") + + // Shutdown the server + err = srv.Shutdown(context.TODO()) + require.NoError(t, err, "expect no error in shutting down mock heimdall server") + + // Wait for `wg.Done()` to be called in the mock server's routine. + wg.Wait() +} + +// TestContext includes bunch of simple tests to verify the working of timeout +// based context and cancellation. +func TestContext(t *testing.T) { + t.Parallel() + + ctx, cancel1 := context.WithTimeout(context.Background(), 1*time.Second) + + // Case1: Done is not yet closed, so Err returns nil. + require.NoError(t, ctx.Err(), "expect nil error") + + wg := &sync.WaitGroup{} + + // Case2: Check if timeout is being handled + wg.Add(1) + + go func(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + select { + case <-ctx.Done(): + // Expect context deadline exceeded error + require.Equal(t, "context deadline exceeded", ctx.Err().Error(), "expect the ctx error to be a context deadline exceeded error") + case <-time.After(2 * time.Second): + // Case for safely exiting the tests + return + } + }(ctx, wg) + + // Case3: Check normal case + ctx, cancel2 := context.WithTimeout(context.Background(), 3*time.Second) + + wg.Add(1) + + errCh := make(chan error, 1) + + go func(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + select { + case <-ctx.Done(): + // Expect this to never occur, throw explicit error + errCh <- errors.New("unexpectecd call to `ctx.Done()`") + case <-time.After(2 * time.Second): + // Case for safely exiting the tests + errCh <- nil + return + } + }(ctx, wg) + + if err := <-errCh; err != nil { + t.Fatalf("err: %v", err) + } + + // Case4: Check if cancellation is being handled + ctx, cancel3 := context.WithTimeout(context.Background(), 1*time.Second) + + wg.Add(1) + + go func(cancel context.CancelFunc) { + time.Sleep(500 * time.Millisecond) + cancel() + }(cancel3) + + go func(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + select { + case <-ctx.Done(): + // Expect context canceled error + require.Equal(t, "context canceled", ctx.Err().Error(), "expect the ctx error to be a context canceled error") + case <-time.After(2 * time.Second): + // Case for safely exiting the tests + return + } + }(ctx, wg) + + // Wait for all tests to pass + wg.Wait() + + // Cancel all remaining contexts + cancel1() + cancel2() +} + func TestSpanURL(t *testing.T) { t.Parallel() diff --git a/consensus/bor/heimdall/metrics.go b/consensus/bor/heimdall/metrics.go new file mode 100644 index 0000000000..99d7ca65ac --- /dev/null +++ b/consensus/bor/heimdall/metrics.go @@ -0,0 +1,82 @@ +package heimdall + +import ( + "context" + "time" + + "github.com/ethereum/go-ethereum/metrics" +) + +type ( + requestTypeKey struct{} + requestType string + + meter struct { + request map[bool]metrics.Meter // map[isSuccessful]metrics.Meter + timer metrics.Timer + } +) + +const ( + stateSyncRequest requestType = "state-sync" + spanRequest requestType = "span" + checkpointRequest requestType = "checkpoint" + checkpointCountRequest requestType = "checkpoint-count" +) + +func withRequestType(ctx context.Context, reqType requestType) context.Context { + return context.WithValue(ctx, requestTypeKey{}, reqType) +} + +func getRequestType(ctx context.Context) (requestType, bool) { + reqType, ok := ctx.Value(requestTypeKey{}).(requestType) + return reqType, ok +} + +var ( + requestMeters = map[requestType]meter{ + stateSyncRequest: { + request: map[bool]metrics.Meter{ + true: metrics.NewRegisteredMeter("client/requests/statesync/valid", nil), + false: metrics.NewRegisteredMeter("client/requests/statesync/invalid", nil), + }, + timer: metrics.NewRegisteredTimer("client/requests/statesync/duration", nil), + }, + spanRequest: { + request: map[bool]metrics.Meter{ + true: metrics.NewRegisteredMeter("client/requests/span/valid", nil), + false: metrics.NewRegisteredMeter("client/requests/span/invalid", nil), + }, + timer: metrics.NewRegisteredTimer("client/requests/span/duration", nil), + }, + checkpointRequest: { + request: map[bool]metrics.Meter{ + true: metrics.NewRegisteredMeter("client/requests/checkpoint/valid", nil), + false: metrics.NewRegisteredMeter("client/requests/checkpoint/invalid", nil), + }, + timer: metrics.NewRegisteredTimer("client/requests/checkpoint/duration", nil), + }, + checkpointCountRequest: { + request: map[bool]metrics.Meter{ + true: metrics.NewRegisteredMeter("client/requests/checkpointcount/valid", nil), + false: metrics.NewRegisteredMeter("client/requests/checkpointcount/invalid", nil), + }, + timer: metrics.NewRegisteredTimer("client/requests/checkpointcount/duration", nil), + }, + } +) + +func sendMetrics(ctx context.Context, start time.Time, isSuccessful bool) { + reqType, ok := getRequestType(ctx) + if !ok { + return + } + + meters, ok := requestMeters[reqType] + if !ok { + return + } + + meters.request[isSuccessful].Mark(1) + meters.timer.Update(time.Since(start)) +} diff --git a/consensus/bor/heimdall/span/spanner.go b/consensus/bor/heimdall/span/spanner.go index 7bf6e350ee..e0f2d66c6b 100644 --- a/consensus/bor/heimdall/span/spanner.go +++ b/consensus/bor/heimdall/span/spanner.go @@ -39,12 +39,12 @@ func NewChainSpanner(ethAPI api.Caller, validatorSet abi.ABI, chainConfig *param } // GetCurrentSpan get current span from contract -func (c *ChainSpanner) GetCurrentSpan(headerHash common.Hash) (*Span, error) { +func (c *ChainSpanner) GetCurrentSpan(ctx context.Context, headerHash common.Hash) (*Span, error) { // block blockNr := rpc.BlockNumberOrHashWithHash(headerHash, false) // method - method := "getCurrentSpan" + const method = "getCurrentSpan" data, err := c.validatorSet.Pack(method) if err != nil { @@ -58,7 +58,7 @@ func (c *ChainSpanner) GetCurrentSpan(headerHash common.Hash) (*Span, error) { gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) // todo: would we like to have a timeout here? - result, err := c.ethAPI.Call(context.Background(), ethapi.TransactionArgs{ + result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{ Gas: &gas, To: &toAddress, Data: &msgData, @@ -89,8 +89,8 @@ func (c *ChainSpanner) GetCurrentSpan(headerHash common.Hash) (*Span, error) { } // GetCurrentValidators get current validators -func (c *ChainSpanner) GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) { - ctx, cancel := context.WithCancel(context.Background()) +func (c *ChainSpanner) GetCurrentValidators(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) { + ctx, cancel := context.WithCancel(ctx) defer cancel() // method @@ -146,7 +146,7 @@ func (c *ChainSpanner) GetCurrentValidators(headerHash common.Hash, blockNumber const method = "commitSpan" -func (c *ChainSpanner) CommitSpan(heimdallSpan HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error { +func (c *ChainSpanner) CommitSpan(ctx context.Context, heimdallSpan HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error { // get validators bytes validators := make([]valset.MinimalVal, 0, len(heimdallSpan.ValidatorSet.Validators)) for _, val := range heimdallSpan.ValidatorSet.Validators { @@ -194,7 +194,7 @@ func (c *ChainSpanner) CommitSpan(heimdallSpan HeimdallSpan, state *state.StateD msg := statefull.GetSystemMessage(c.validatorContractAddress, data) // apply message - _, err = statefull.ApplyMessage(msg, state, header, c.chainConfig, chainContext) + _, err = statefull.ApplyMessage(ctx, msg, state, header, c.chainConfig, chainContext) return err } diff --git a/consensus/bor/heimdallgrpc/checkpoint.go b/consensus/bor/heimdallgrpc/checkpoint.go new file mode 100644 index 0000000000..2c51efe736 --- /dev/null +++ b/consensus/bor/heimdallgrpc/checkpoint.go @@ -0,0 +1,51 @@ +package heimdallgrpc + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint" + "github.com/ethereum/go-ethereum/log" + + proto "github.com/maticnetwork/polyproto/heimdall" + protoutils "github.com/maticnetwork/polyproto/utils" +) + +func (h *HeimdallGRPCClient) FetchCheckpointCount(ctx context.Context) (int64, error) { + log.Info("Fetching checkpoint count") + + res, err := h.client.FetchCheckpointCount(ctx, nil) + if err != nil { + return 0, err + } + + log.Info("Fetched checkpoint count") + + return res.Result.Result, nil +} + +func (h *HeimdallGRPCClient) FetchCheckpoint(ctx context.Context, number int64) (*checkpoint.Checkpoint, error) { + req := &proto.FetchCheckpointRequest{ + ID: number, + } + + log.Info("Fetching checkpoint", "number", number) + + res, err := h.client.FetchCheckpoint(ctx, req) + if err != nil { + return nil, err + } + + log.Info("Fetched checkpoint", "number", number) + + checkpoint := &checkpoint.Checkpoint{ + StartBlock: new(big.Int).SetUint64(res.Result.StartBlock), + EndBlock: new(big.Int).SetUint64(res.Result.EndBlock), + RootHash: protoutils.ConvertH256ToHash(res.Result.RootHash), + Proposer: protoutils.ConvertH160toAddress(res.Result.Proposer), + BorChainID: res.Result.BorChainID, + Timestamp: uint64(res.Result.Timestamp.GetSeconds()), + } + + return checkpoint, nil +} diff --git a/consensus/bor/heimdallgrpc/client.go b/consensus/bor/heimdallgrpc/client.go new file mode 100644 index 0000000000..7687b7f1c7 --- /dev/null +++ b/consensus/bor/heimdallgrpc/client.go @@ -0,0 +1,52 @@ +package heimdallgrpc + +import ( + "time" + + "github.com/ethereum/go-ethereum/log" + + grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" + proto "github.com/maticnetwork/polyproto/heimdall" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials/insecure" +) + +const ( + stateFetchLimit = 50 +) + +type HeimdallGRPCClient struct { + conn *grpc.ClientConn + client proto.HeimdallClient +} + +func NewHeimdallGRPCClient(address string) *HeimdallGRPCClient { + opts := []grpc_retry.CallOption{ + grpc_retry.WithMax(10000), + grpc_retry.WithBackoff(grpc_retry.BackoffLinear(5 * time.Second)), + grpc_retry.WithCodes(codes.Internal, codes.Unavailable, codes.Aborted, codes.NotFound), + } + + conn, err := grpc.Dial(address, + grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(opts...)), + grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor(opts...)), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + if err != nil { + log.Crit("Failed to connect to Heimdall gRPC", "error", err) + } + + log.Info("Connected to Heimdall gRPC server", "address", address) + + return &HeimdallGRPCClient{ + conn: conn, + client: proto.NewHeimdallClient(conn), + } +} + +func (h *HeimdallGRPCClient) Close() { + log.Debug("Shutdown detected, Closing Heimdall gRPC client") + h.conn.Close() +} diff --git a/consensus/bor/heimdallgrpc/span.go b/consensus/bor/heimdallgrpc/span.go new file mode 100644 index 0000000000..b5c9ddf695 --- /dev/null +++ b/consensus/bor/heimdallgrpc/span.go @@ -0,0 +1,63 @@ +package heimdallgrpc + +import ( + "context" + + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" + "github.com/ethereum/go-ethereum/consensus/bor/valset" + "github.com/ethereum/go-ethereum/log" + + proto "github.com/maticnetwork/polyproto/heimdall" + protoutils "github.com/maticnetwork/polyproto/utils" +) + +func (h *HeimdallGRPCClient) Span(ctx context.Context, spanID uint64) (*span.HeimdallSpan, error) { + req := &proto.SpanRequest{ + ID: spanID, + } + + log.Info("Fetching span", "spanID", spanID) + + res, err := h.client.Span(ctx, req) + if err != nil { + return nil, err + } + + log.Info("Fetched span", "spanID", spanID) + + return parseSpan(res.Result), nil +} + +func parseSpan(protoSpan *proto.Span) *span.HeimdallSpan { + resp := &span.HeimdallSpan{ + Span: span.Span{ + ID: protoSpan.ID, + StartBlock: protoSpan.StartBlock, + EndBlock: protoSpan.EndBlock, + }, + ValidatorSet: valset.ValidatorSet{}, + SelectedProducers: []valset.Validator{}, + ChainID: protoSpan.ChainID, + } + + for _, validator := range protoSpan.ValidatorSet.Validators { + resp.ValidatorSet.Validators = append(resp.ValidatorSet.Validators, parseValidator(validator)) + } + + resp.ValidatorSet.Proposer = parseValidator(protoSpan.ValidatorSet.Proposer) + + for _, validator := range protoSpan.SelectedProducers { + resp.SelectedProducers = append(resp.SelectedProducers, *parseValidator(validator)) + } + + return resp +} + +func parseValidator(validator *proto.Validator) *valset.Validator { + return &valset.Validator{ + ID: validator.ID, + Address: protoutils.ConvertH160toAddress(validator.Address), + VotingPower: validator.VotingPower, + ProposerPriority: validator.ProposerPriority, + } +} diff --git a/consensus/bor/heimdallgrpc/state_sync.go b/consensus/bor/heimdallgrpc/state_sync.go new file mode 100644 index 0000000000..a3bbb80aae --- /dev/null +++ b/consensus/bor/heimdallgrpc/state_sync.go @@ -0,0 +1,59 @@ +package heimdallgrpc + +import ( + "context" + "errors" + "io" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/bor/clerk" + + proto "github.com/maticnetwork/polyproto/heimdall" +) + +func (h *HeimdallGRPCClient) StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) { + eventRecords := make([]*clerk.EventRecordWithTime, 0) + + req := &proto.StateSyncEventsRequest{ + FromID: fromID, + ToTime: uint64(to), + Limit: uint64(stateFetchLimit), + } + + var ( + res proto.Heimdall_StateSyncEventsClient + events *proto.StateSyncEventsResponse + err error + ) + + res, err = h.client.StateSyncEvents(ctx, req) + if err != nil { + return nil, err + } + + for { + events, err = res.Recv() + if errors.Is(err, io.EOF) { + return eventRecords, nil + } + + if err != nil { + return nil, err + } + + for _, event := range events.Result { + eventRecord := &clerk.EventRecordWithTime{ + EventRecord: clerk.EventRecord{ + ID: event.ID, + Contract: common.HexToAddress(event.Contract), + Data: common.Hex2Bytes(event.Data[2:]), + TxHash: common.HexToHash(event.TxHash), + LogIndex: event.LogIndex, + ChainID: event.ChainID, + }, + Time: event.Time.AsTime(), + } + eventRecords = append(eventRecords, eventRecord) + } + } +} diff --git a/consensus/bor/merkle.go b/consensus/bor/merkle.go index ef1b4eb87e..a2ce1d4023 100644 --- a/consensus/bor/merkle.go +++ b/consensus/bor/merkle.go @@ -39,7 +39,7 @@ func convertTo32(input []byte) (output [32]byte) { return } -func convert(input []([32]byte)) [][]byte { +func convert(input [][32]byte) [][]byte { output := make([][]byte, 0, len(input)) for _, in := range input { diff --git a/consensus/bor/snapshot.go b/consensus/bor/snapshot.go index f71ceae0ad..b61851262e 100644 --- a/consensus/bor/snapshot.go +++ b/consensus/bor/snapshot.go @@ -59,6 +59,8 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat return nil, err } + snap.ValidatorSet.UpdateValidatorMap() + snap.config = config snap.sigcache = sigcache @@ -120,8 +122,8 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { number := header.Number.Uint64() // Delete the oldest signer from the recent list to allow it signing again - if number >= s.config.Sprint { - delete(snap.Recents, number-s.config.Sprint) + if number >= s.config.CalculateSprint(number) { + delete(snap.Recents, number-s.config.CalculateSprint(number)) } // Resolve the authorization key and check against signers @@ -131,7 +133,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { } // check if signer is in validator set - if !snap.ValidatorSet.HasAddress(signer.Bytes()) { + if !snap.ValidatorSet.HasAddress(signer) { return nil, &UnauthorizedSignerError{number, signer.Bytes()} } @@ -143,7 +145,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { snap.Recents[number] = signer // change validator set and change proposer - if number > 0 && (number+1)%s.config.Sprint == 0 { + if number > 0 && (number+1)%s.config.CalculateSprint(number) == 0 { if err := validateHeaderExtraField(header.Extra); err != nil { return nil, err } @@ -201,18 +203,18 @@ func (s *Snapshot) signers() []common.Address { } // Difficulty returns the difficulty for a particular signer at the current snapshot number -func (s *Snapshot) Difficulty(signer common.Address) uint64 { +func Difficulty(validatorSet *valset.ValidatorSet, signer common.Address) uint64 { // if signer is empty if signer == (common.Address{}) { return 1 } - validators := s.ValidatorSet.Validators - proposer := s.ValidatorSet.GetProposer().Address + validators := validatorSet.Validators + proposer := validatorSet.GetProposer().Address totalValidators := len(validators) - proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer) - signerIndex, _ := s.ValidatorSet.GetByAddress(signer) + proposerIndex, _ := validatorSet.GetByAddress(proposer) + signerIndex, _ := validatorSet.GetByAddress(signer) // temp index tempIndex := signerIndex diff --git a/consensus/bor/snapshot_test.go b/consensus/bor/snapshot_test.go index 1a3e967613..68a9ba042f 100644 --- a/consensus/bor/snapshot_test.go +++ b/consensus/bor/snapshot_test.go @@ -1,12 +1,12 @@ package bor import ( - "math/rand" + "math/big" "sort" "testing" - "time" - "github.com/stretchr/testify/assert" + "github.com/maticnetwork/crand" + "github.com/stretchr/testify/require" "pgregory.net/rapid" "github.com/ethereum/go-ethereum/common" @@ -28,13 +28,13 @@ func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) { } // proposer is signer - signer := validatorSet.Proposer.Address - successionNumber, err := snap.GetSignerSuccessionNumber(signer) + signerTest := validatorSet.Proposer.Address + successionNumber, err := snap.GetSignerSuccessionNumber(signerTest) if err != nil { t.Fatalf("%s", err) } - assert.Equal(t, 0, successionNumber) + require.Equal(t, 0, successionNumber) } func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) { @@ -54,13 +54,13 @@ func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) { } // choose a signer at an index greater than proposer index - signer := snap.ValidatorSet.Validators[signerIndex].Address - successionNumber, err := snap.GetSignerSuccessionNumber(signer) + signerTest := snap.ValidatorSet.Validators[signerIndex].Address + successionNumber, err := snap.GetSignerSuccessionNumber(signerTest) if err != nil { t.Fatalf("%s", err) } - assert.Equal(t, signerIndex-proposerIndex, successionNumber) + require.Equal(t, signerIndex-proposerIndex, successionNumber) } func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) { @@ -76,13 +76,13 @@ func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) { } // choose a signer at an index greater than proposer index - signer := snap.ValidatorSet.Validators[signerIndex].Address - successionNumber, err := snap.GetSignerSuccessionNumber(signer) + signerTest := snap.ValidatorSet.Validators[signerIndex].Address + successionNumber, err := snap.GetSignerSuccessionNumber(signerTest) if err != nil { t.Fatalf("%s", err) } - assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber) + require.Equal(t, signerIndex+numVals-proposerIndex, successionNumber) } func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) { @@ -93,18 +93,20 @@ func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) { ValidatorSet: valset.NewValidatorSet(validators), } - dummyProposerAddress := randomAddress() + require.Len(t, snap.ValidatorSet.Validators, numVals) + + dummyProposerAddress := randomAddress(toAddresses(validators)...) snap.ValidatorSet.Proposer = &valset.Validator{Address: dummyProposerAddress} // choose any signer - signer := snap.ValidatorSet.Validators[3].Address + signerTest := snap.ValidatorSet.Validators[3].Address - _, err := snap.GetSignerSuccessionNumber(signer) - assert.NotNil(t, err) + _, err := snap.GetSignerSuccessionNumber(signerTest) + require.NotNil(t, err) e, ok := err.(*UnauthorizedProposerError) - assert.True(t, ok) - assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer) + require.True(t, ok) + require.Equal(t, dummyProposerAddress.Bytes(), e.Proposer) } func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) { @@ -114,26 +116,30 @@ func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) { snap := Snapshot{ ValidatorSet: valset.NewValidatorSet(validators), } - dummySignerAddress := randomAddress() + + dummySignerAddress := randomAddress(toAddresses(validators)...) _, err := snap.GetSignerSuccessionNumber(dummySignerAddress) - assert.NotNil(t, err) + require.NotNil(t, err) + e, ok := err.(*UnauthorizedSignerError) - assert.True(t, ok) - assert.Equal(t, dummySignerAddress.Bytes(), e.Signer) + require.True(t, ok) + + require.Equal(t, dummySignerAddress.Bytes(), e.Signer) } // nolint: unparam func buildRandomValidatorSet(numVals int) []*valset.Validator { - rand.Seed(time.Now().Unix()) - validators := make([]*valset.Validator, numVals) valAddrs := randomAddresses(numVals) for i := 0; i < numVals; i++ { + power := crand.BigInt(big.NewInt(99)) + powerN := power.Int64() + 1 + validators[i] = &valset.Validator{ Address: valAddrs[i], // cannot process validators with voting power 0, hence +1 - VotingPower: int64(rand.Intn(99) + 1), + VotingPower: powerN, } } @@ -143,11 +149,23 @@ func buildRandomValidatorSet(numVals int) []*valset.Validator { return validators } -func randomAddress() common.Address { - bytes := make([]byte, 32) - rand.Read(bytes) +func randomAddress(exclude ...common.Address) common.Address { + excl := make(map[common.Address]struct{}, len(exclude)) - return common.BytesToAddress(bytes) + for _, addr := range exclude { + excl[addr] = struct{}{} + } + + r := crand.NewRand() + + for { + addr := r.Address() + if _, ok := excl[addr]; ok { + continue + } + + return addr + } } func randomAddresses(n int) []common.Address { @@ -158,17 +176,12 @@ func randomAddresses(n int) []common.Address { addrs := make([]common.Address, 0, n) addrsSet := make(map[common.Address]struct{}, n) - var ( - addr common.Address - exist bool - ) + var exist bool - bytes := make([]byte, 32) + r := crand.NewRand() for { - rand.Read(bytes) - - addr = common.BytesToAddress(bytes) + addr := r.Address() _, exist = addrsSet[addr] if !exist { @@ -187,7 +200,7 @@ func TestRandomAddresses(t *testing.T) { t.Parallel() rapid.Check(t, func(t *rapid.T) { - length := rapid.IntMax(100).Draw(t, "length").(int) + length := rapid.IntMax(300).Draw(t, "length").(int) addrs := randomAddresses(length) addressSet := unique.New(addrs) @@ -197,3 +210,13 @@ func TestRandomAddresses(t *testing.T) { } }) } + +func toAddresses(vals []*valset.Validator) []common.Address { + addrs := make([]common.Address, len(vals)) + + for i, val := range vals { + addrs[i] = val.Address + } + + return addrs +} diff --git a/consensus/bor/span.go b/consensus/bor/span.go index 4867635b8e..86a58fa42e 100644 --- a/consensus/bor/span.go +++ b/consensus/bor/span.go @@ -1,6 +1,8 @@ package bor import ( + "context" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" "github.com/ethereum/go-ethereum/consensus/bor/valset" @@ -11,7 +13,7 @@ import ( //go:generate mockgen -destination=./span_mock.go -package=bor . Spanner type Spanner interface { - GetCurrentSpan(headerHash common.Hash) (*span.Span, error) - GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) - CommitSpan(heimdallSpan span.HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error + GetCurrentSpan(ctx context.Context, headerHash common.Hash) (*span.Span, error) + GetCurrentValidators(ctx context.Context, headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) + CommitSpan(ctx context.Context, heimdallSpan span.HeimdallSpan, state *state.StateDB, header *types.Header, chainContext core.ChainContext) error } diff --git a/consensus/bor/span_mock.go b/consensus/bor/span_mock.go index 12ed945234..6d5f62e25d 100644 --- a/consensus/bor/span_mock.go +++ b/consensus/bor/span_mock.go @@ -5,6 +5,7 @@ package bor import ( + context "context" reflect "reflect" common "github.com/ethereum/go-ethereum/common" @@ -40,45 +41,45 @@ func (m *MockSpanner) EXPECT() *MockSpannerMockRecorder { } // CommitSpan mocks base method. -func (m *MockSpanner) CommitSpan(arg0 span.HeimdallSpan, arg1 *state.StateDB, arg2 *types.Header, arg3 core.ChainContext) error { +func (m *MockSpanner) CommitSpan(arg0 context.Context, arg1 span.HeimdallSpan, arg2 *state.StateDB, arg3 *types.Header, arg4 core.ChainContext) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CommitSpan", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "CommitSpan", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(error) return ret0 } // CommitSpan indicates an expected call of CommitSpan. -func (mr *MockSpannerMockRecorder) CommitSpan(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockSpannerMockRecorder) CommitSpan(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitSpan", reflect.TypeOf((*MockSpanner)(nil).CommitSpan), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CommitSpan", reflect.TypeOf((*MockSpanner)(nil).CommitSpan), arg0, arg1, arg2, arg3, arg4) } // GetCurrentSpan mocks base method. -func (m *MockSpanner) GetCurrentSpan(arg0 common.Hash) (*span.Span, error) { +func (m *MockSpanner) GetCurrentSpan(arg0 context.Context, arg1 common.Hash) (*span.Span, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCurrentSpan", arg0) + ret := m.ctrl.Call(m, "GetCurrentSpan", arg0, arg1) ret0, _ := ret[0].(*span.Span) ret1, _ := ret[1].(error) return ret0, ret1 } // GetCurrentSpan indicates an expected call of GetCurrentSpan. -func (mr *MockSpannerMockRecorder) GetCurrentSpan(arg0 interface{}) *gomock.Call { +func (mr *MockSpannerMockRecorder) GetCurrentSpan(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSpan", reflect.TypeOf((*MockSpanner)(nil).GetCurrentSpan), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentSpan", reflect.TypeOf((*MockSpanner)(nil).GetCurrentSpan), arg0, arg1) } // GetCurrentValidators mocks base method. -func (m *MockSpanner) GetCurrentValidators(arg0 common.Hash, arg1 uint64) ([]*valset.Validator, error) { +func (m *MockSpanner) GetCurrentValidators(arg0 context.Context, arg1 common.Hash, arg2 uint64) ([]*valset.Validator, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCurrentValidators", arg0, arg1) + ret := m.ctrl.Call(m, "GetCurrentValidators", arg0, arg1, arg2) ret0, _ := ret[0].([]*valset.Validator) ret1, _ := ret[1].(error) return ret0, ret1 } // GetCurrentValidators indicates an expected call of GetCurrentValidators. -func (mr *MockSpannerMockRecorder) GetCurrentValidators(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockSpannerMockRecorder) GetCurrentValidators(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidators", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidators), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidators", reflect.TypeOf((*MockSpanner)(nil).GetCurrentValidators), arg0, arg1, arg2) } diff --git a/consensus/bor/statefull/processor.go b/consensus/bor/statefull/processor.go index 98ed41ed92..0fe9baeeba 100644 --- a/consensus/bor/statefull/processor.go +++ b/consensus/bor/statefull/processor.go @@ -1,6 +1,7 @@ package statefull import ( + "context" "math" "math/big" @@ -59,6 +60,7 @@ func GetSystemMessage(toAddress common.Address, data []byte) Callmsg { // apply message func ApplyMessage( + _ context.Context, msg Callmsg, state *state.StateDB, header *types.Header, diff --git a/consensus/bor/validators_getter.go b/consensus/bor/validators_getter.go deleted file mode 100644 index 90d1fccf6e..0000000000 --- a/consensus/bor/validators_getter.go +++ /dev/null @@ -1,11 +0,0 @@ -package bor - -import ( - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus/bor/valset" -) - -//go:generate mockgen -destination=./validators_getter_mock.go -package=bor . ValidatorsGetter -type ValidatorsGetter interface { - GetCurrentValidators(headerHash common.Hash, blockNumber uint64) ([]*valset.Validator, error) -} diff --git a/consensus/bor/validators_getter_mock.go b/consensus/bor/validators_getter_mock.go deleted file mode 100644 index ad99489d8e..0000000000 --- a/consensus/bor/validators_getter_mock.go +++ /dev/null @@ -1,51 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/ethereum/go-ethereum/consensus/bor (interfaces: ValidatorsGetter) - -// Package bor is a generated GoMock package. -package bor - -import ( - reflect "reflect" - - common "github.com/ethereum/go-ethereum/common" - valset "github.com/ethereum/go-ethereum/consensus/bor/valset" - gomock "github.com/golang/mock/gomock" -) - -// MockValidatorsGetter is a mock of ValidatorsGetter interface. -type MockValidatorsGetter struct { - ctrl *gomock.Controller - recorder *MockValidatorsGetterMockRecorder -} - -// MockValidatorsGetterMockRecorder is the mock recorder for MockValidatorsGetter. -type MockValidatorsGetterMockRecorder struct { - mock *MockValidatorsGetter -} - -// NewMockValidatorsGetter creates a new mock instance. -func NewMockValidatorsGetter(ctrl *gomock.Controller) *MockValidatorsGetter { - mock := &MockValidatorsGetter{ctrl: ctrl} - mock.recorder = &MockValidatorsGetterMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockValidatorsGetter) EXPECT() *MockValidatorsGetterMockRecorder { - return m.recorder -} - -// GetCurrentValidators mocks base method. -func (m *MockValidatorsGetter) GetCurrentValidators(arg0 common.Hash, arg1 uint64) ([]*valset.Validator, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCurrentValidators", arg0, arg1) - ret0, _ := ret[0].([]*valset.Validator) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetCurrentValidators indicates an expected call of GetCurrentValidators. -func (mr *MockValidatorsGetterMockRecorder) GetCurrentValidators(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentValidators", reflect.TypeOf((*MockValidatorsGetter)(nil).GetCurrentValidators), arg0, arg1) -} diff --git a/consensus/bor/valset/validator.go b/consensus/bor/valset/validator.go index 250206c1f3..be3f46c830 100644 --- a/consensus/bor/valset/validator.go +++ b/consensus/bor/valset/validator.go @@ -47,21 +47,26 @@ func (v *Validator) Cmp(other *Validator) *Validator { return v } - // nolint:nestif if v.ProposerPriority > other.ProposerPriority { return v - } else if v.ProposerPriority < other.ProposerPriority { - return other - } else { - result := bytes.Compare(v.Address.Bytes(), other.Address.Bytes()) - if result < 0 { - return v - } else if result > 0 { - return other - } else { - panic("Cannot compare identical validators") - } } + + if v.ProposerPriority < other.ProposerPriority { + return other + } + + result := bytes.Compare(v.Address.Bytes(), other.Address.Bytes()) + + if result == 0 { + panic("Cannot compare identical validators") + } + + if result < 0 { + return v + } + + // result > 0 + return other } func (v *Validator) String() string { diff --git a/consensus/bor/valset/validator_set.go b/consensus/bor/valset/validator_set.go index 19e6c681fe..0a6f7c4487 100644 --- a/consensus/bor/valset/validator_set.go +++ b/consensus/bor/valset/validator_set.go @@ -46,6 +46,7 @@ type ValidatorSet struct { // cached (unexported) totalVotingPower int64 + validatorsMap map[common.Address]int // address -> index } // NewValidatorSet initializes a ValidatorSet by copying over the @@ -54,7 +55,7 @@ type ValidatorSet struct { // The addresses of validators in `valz` must be unique otherwise the // function panics. func NewValidatorSet(valz []*Validator) *ValidatorSet { - vals := &ValidatorSet{} + vals := &ValidatorSet{validatorsMap: make(map[common.Address]int)} err := vals.updateWithChangeSet(valz, false) if err != nil { @@ -232,30 +233,34 @@ func validatorListCopy(valsList []*Validator) []*Validator { // Copy each validator into a new ValidatorSet. func (vals *ValidatorSet) Copy() *ValidatorSet { + valCopy := validatorListCopy(vals.Validators) + validatorsMap := make(map[common.Address]int, len(vals.Validators)) + + for i, val := range valCopy { + validatorsMap[val.Address] = i + } + return &ValidatorSet{ Validators: validatorListCopy(vals.Validators), Proposer: vals.Proposer, totalVotingPower: vals.totalVotingPower, + validatorsMap: validatorsMap, } } // HasAddress returns true if address given is in the validator set, false - // otherwise. -func (vals *ValidatorSet) HasAddress(address []byte) bool { - idx := sort.Search(len(vals.Validators), func(i int) bool { - return bytes.Compare(address, vals.Validators[i].Address.Bytes()) <= 0 - }) +func (vals *ValidatorSet) HasAddress(address common.Address) bool { + _, ok := vals.validatorsMap[address] - return idx < len(vals.Validators) && bytes.Equal(vals.Validators[idx].Address.Bytes(), address) + return ok } // GetByAddress returns an index of the validator with address and validator // itself if found. Otherwise, -1 and nil are returned. func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val *Validator) { - idx := sort.Search(len(vals.Validators), func(i int) bool { - return bytes.Compare(address.Bytes(), vals.Validators[i].Address.Bytes()) <= 0 - }) - if idx < len(vals.Validators) && vals.Validators[idx].Address == address { + idx, ok := vals.validatorsMap[address] + if ok { return idx, vals.Validators[idx].Copy() } @@ -265,14 +270,14 @@ func (vals *ValidatorSet) GetByAddress(address common.Address) (index int, val * // GetByIndex returns the validator's address and validator itself by index. // It returns nil values if index is less than 0 or greater or equal to // len(ValidatorSet.Validators). -func (vals *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) { +func (vals *ValidatorSet) GetByIndex(index int) (address common.Address, val *Validator) { if index < 0 || index >= len(vals.Validators) { - return nil, nil + return common.Address{}, nil } val = vals.Validators[index] - return val.Address.Bytes(), val.Copy() + return val.Address, val.Copy() } // Size returns the length of the validator set. @@ -328,7 +333,7 @@ func (vals *ValidatorSet) GetProposer() (proposer *Validator) { func (vals *ValidatorSet) findProposer() *Validator { var proposer *Validator for _, val := range vals.Validators { - if proposer == nil || !bytes.Equal(val.Address.Bytes(), proposer.Address.Bytes()) { + if proposer == nil || val.Address != proposer.Address { proposer = proposer.Cmp(val) } } @@ -371,14 +376,19 @@ func processChanges(origChanges []*Validator) (updates, removals []*Validator, e changes := validatorListCopy(origChanges) sort.Sort(ValidatorsByAddress(changes)) - removals = make([]*Validator, 0, len(changes)) - updates = make([]*Validator, 0, len(changes)) + sliceCap := len(changes) / 2 + if sliceCap == 0 { + sliceCap = 1 + } + + removals = make([]*Validator, 0, sliceCap) + updates = make([]*Validator, 0, sliceCap) var prevAddr common.Address // Scan changes by address and append valid validators to updates or removals lists. for _, valUpdate := range changes { - if bytes.Equal(valUpdate.Address.Bytes(), prevAddr.Bytes()) { + if valUpdate.Address == prevAddr { err = fmt.Errorf("duplicate entry %v in %v", valUpdate, changes) return nil, nil, err } @@ -489,10 +499,11 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) { } else { // Apply add or update. merged[i] = updates[0] - if bytes.Equal(existing[0].Address.Bytes(), updates[0].Address.Bytes()) { + if existing[0].Address == updates[0].Address { // Validator is present in both, advance existing. existing = existing[1:] } + updates = updates[1:] } i++ @@ -503,6 +514,7 @@ func (vals *ValidatorSet) applyUpdates(updates []*Validator) { merged[i] = existing[j] i++ } + // OR add updates which are left. for j := 0; j < len(updates); j++ { merged[i] = updates[j] @@ -541,7 +553,7 @@ func (vals *ValidatorSet) applyRemovals(deletes []*Validator) { // Loop over deletes until we removed all of them. for len(deletes) > 0 { - if bytes.Equal(existing[0].Address.Bytes(), deletes[0].Address.Bytes()) { + if existing[0].Address == deletes[0].Address { deletes = deletes[1:] } else { // Leave it in the resulting slice. merged[i] = existing[0] @@ -599,8 +611,7 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes computeNewPriorities(updates, vals, updatedTotalVotingPower) // Apply updates and removals. - vals.applyUpdates(updates) - vals.applyRemovals(deletes) + vals.updateValidators(updates, deletes) if err := vals.UpdateTotalVotingPower(); err != nil { return err @@ -613,6 +624,21 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes return nil } +func (vals *ValidatorSet) updateValidators(updates []*Validator, deletes []*Validator) { + vals.applyUpdates(updates) + vals.applyRemovals(deletes) + + vals.UpdateValidatorMap() +} + +func (vals *ValidatorSet) UpdateValidatorMap() { + vals.validatorsMap = make(map[common.Address]int, len(vals.Validators)) + + for i, val := range vals.Validators { + vals.validatorsMap[val.Address] = i + } +} + // UpdateWithChangeSet attempts to update the validator set with 'changes'. // It performs the following steps: // - validates the changes making sure there are no duplicates and splits them in updates and deletes @@ -661,7 +687,7 @@ func (vals *ValidatorSet) StringIndented(indent string) string { return "nil-ValidatorSet" } - var valStrings []string + valStrings := make([]string, 0, len(vals.Validators)) vals.Iterate(func(index int, val *Validator) bool { valStrings = append(valStrings, val.String()) diff --git a/consensus/bor/valset/validator_set_test.go b/consensus/bor/valset/validator_set_test.go new file mode 100644 index 0000000000..9397ca3e92 --- /dev/null +++ b/consensus/bor/valset/validator_set_test.go @@ -0,0 +1,199 @@ +package valset + +import ( + "testing" + + "github.com/stretchr/testify/require" + "gotest.tools/assert" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +func NewValidatorFromKey(key string, votingPower int64) *Validator { + privKey, _ := crypto.HexToECDSA(key) + + return NewValidator(crypto.PubkeyToAddress(privKey.PublicKey), votingPower) +} + +func GetValidators() [4]*Validator { + const ( + // addr0 = 0x96C42C56fdb78294F96B0cFa33c92bed7D75F96a + signer0 = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9" + + // addr1 = 0x98925BE497f6dFF6A5a33dDA8B5933cA35262d69 + signer1 = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd8" + + //addr2 = 0x648Cf2A5b119E2c04061021834F8f75735B1D36b + signer2 = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd7" + + //addr3 = 0x168f220B3b313D456eD4797520eFdFA9c57E6C45 + signer3 = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd6" + ) + + return [4]*Validator{ + NewValidatorFromKey(signer0, 100), + NewValidatorFromKey(signer1, 200), + NewValidatorFromKey(signer2, 300), + NewValidatorFromKey(signer3, 400), + } +} + +func TestIncrementProposerPriority(t *testing.T) { + t.Parallel() + + vals := GetValidators() + + // Validator set length = 1 + valSet := NewValidatorSet(vals[:1]) + + expectedPropsers := []*Validator{vals[0], vals[0], vals[0], vals[0], vals[0], vals[0], vals[0], vals[0], vals[0], vals[0]} + + for i := 0; i < 10; i++ { + valSet.IncrementProposerPriority(1) + + require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address) + } + + // Validator set length = 2 + valSet = NewValidatorSet(vals[:2]) + + expectedPropsers = []*Validator{vals[0], vals[1], vals[1], vals[0], vals[1], vals[1], vals[0], vals[1], vals[1], vals[0]} + + for i := 0; i < 10; i++ { + valSet.IncrementProposerPriority(1) + + require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address) + } + + // Validator set length = 3 + valSet = NewValidatorSet(vals[:3]) + + expectedPropsers = []*Validator{vals[1], vals[2], vals[0], vals[1], vals[2], vals[2], vals[1], vals[2], vals[0], vals[1]} + + for i := 0; i < 10; i++ { + valSet.IncrementProposerPriority(1) + + require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address) + } + + // Validator set length = 4 + valSet = NewValidatorSet(vals[:4]) + + expectedPropsers = []*Validator{vals[2], vals[1], vals[3], vals[2], vals[0], vals[3], vals[1], vals[2], vals[3], vals[3]} + + for i := 0; i < 10; i++ { + valSet.IncrementProposerPriority(1) + + require.Equal(t, expectedPropsers[i].Address, valSet.GetProposer().Address) + } +} + +func TestRescalePriorities(t *testing.T) { + t.Parallel() + + vals := GetValidators() + + // Validator set length = 1 + valSet := NewValidatorSet(vals[:1]) + + valSet.RescalePriorities(10) + + expectedPriorities := []int64{0} + for i, val := range valSet.Validators { + require.Equal(t, expectedPriorities[i], val.ProposerPriority) + } + + // Validator set length = 2 + + valSet = NewValidatorSet(vals[:2]) + + valSet.RescalePriorities(100) + + expectedPriorities = []int64{50, -50} + for i, val := range valSet.Validators { + require.Equal(t, expectedPriorities[i], val.ProposerPriority) + } + + // Validator set length = 3 + + valSet = NewValidatorSet(vals[:3]) + + valSet.RescalePriorities(30) + + expectedPriorities = []int64{-17, 5, 11} + for i, val := range valSet.Validators { + require.Equal(t, expectedPriorities[i], val.ProposerPriority) + } + + // Validator set length = 4 + + valSet = NewValidatorSet(vals[:4]) + + valSet.RescalePriorities(10) + + expectedPriorities = []int64{-6, 3, 1, 2} + for i, val := range valSet.Validators { + require.Equal(t, expectedPriorities[i], val.ProposerPriority) + } +} + +func TestGetValidatorByAddressAndIndex(t *testing.T) { + t.Parallel() + + vals := GetValidators() + valSet := NewValidatorSet(vals[:4]) + + for _, val := range valSet.Validators { + idx, valByAddress := valSet.GetByAddress(val.Address) + addr, valByIndex := valSet.GetByIndex(idx) + + assert.DeepEqual(t, val, valByIndex) + assert.DeepEqual(t, val, valByAddress) + assert.DeepEqual(t, val.Address, addr) + } + + tempAddress := common.HexToAddress("0x12345") + + // Negative Testcase + idx, _ := valSet.GetByAddress(tempAddress) + require.Equal(t, idx, -1) + + // checking for validator index out of range + addr, _ := valSet.GetByIndex(100) + require.Equal(t, addr, common.Address{}) +} + +func TestUpdateWithChangeSet(t *testing.T) { + t.Parallel() + + vals := GetValidators() + valSet := NewValidatorSet(vals[:4]) + + // halved the power of vals[2] and doubled the power of vals[3] + vals[2].VotingPower = 150 + vals[3].VotingPower = 800 + + // Adding new temp validator in the set + const tempSigner = "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd5" + + tempVal := NewValidatorFromKey(tempSigner, 250) + + // check totalVotingPower before updating validator set + require.Equal(t, int64(1000), valSet.TotalVotingPower()) + + err := valSet.UpdateWithChangeSet([]*Validator{vals[2], vals[3], tempVal}) + require.NoError(t, err) + + // check totalVotingPower after updating validator set + require.Equal(t, int64(1500), valSet.TotalVotingPower()) + + _, updatedVal2 := valSet.GetByAddress(vals[2].Address) + require.Equal(t, int64(150), updatedVal2.VotingPower) + + _, updatedVal3 := valSet.GetByAddress(vals[3].Address) + require.Equal(t, int64(800), updatedVal3.VotingPower) + + _, updatedTempVal := valSet.GetByAddress(tempVal.Address) + require.Equal(t, int64(250), updatedTempVal.VotingPower) +} diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 685186817d..ad09552469 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -19,6 +19,7 @@ package clique import ( "bytes" + "context" "errors" "fmt" "io" @@ -569,7 +570,7 @@ func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Heade // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, // nor block rewards given, and returns the final block. -func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { +func (c *Clique) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { // Finalize block c.Finalize(chain, header, state, txs, uncles) @@ -589,7 +590,7 @@ func (c *Clique) Authorize(signer common.Address, signFn SignerFn) { // Seal implements consensus.Engine, attempting to create a sealed block using // the local signing credentials. -func (c *Clique) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { +func (c *Clique) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { header := block.Header() // Sealing the genesis block is not supported diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index 1bd32acd37..b2850587ea 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -55,7 +55,7 @@ func TestReimportMirroredState(t *testing.T) { genesis := genspec.MustCommit(db) // Generate a batch of blocks, each properly signed - chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, nil) defer chain.Stop() blocks, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, 3, func(i int, block *core.BlockGen) { @@ -89,7 +89,7 @@ func TestReimportMirroredState(t *testing.T) { db = rawdb.NewMemoryDatabase() genspec.MustCommit(db) - chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) + chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, nil) defer chain.Stop() if _, err := chain.InsertChain(blocks[:2]); err != nil { @@ -102,7 +102,7 @@ func TestReimportMirroredState(t *testing.T) { // Simulate a crash by creating a new chain on top of the database, without // flushing the dirty states out. Insert the last block, triggering a sidechain // reimport. - chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) + chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, nil) defer chain.Stop() if _, err := chain.InsertChain(blocks[2:]); err != nil { diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 094868ca74..54621718e0 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -450,7 +450,7 @@ func TestClique(t *testing.T) { batches[len(batches)-1] = append(batches[len(batches)-1], block) } // Pass all the headers through clique and ensure tallying succeeds - chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Errorf("test %d: failed to create test chain: %v", i, err) continue diff --git a/consensus/consensus.go b/consensus/consensus.go index af8ce98ff3..c287972beb 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -18,6 +18,7 @@ package consensus import ( + "context" "math/big" "github.com/ethereum/go-ethereum/common" @@ -97,7 +98,7 @@ type Engine interface { // // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). - FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, + FinalizeAndAssemble(ctx context.Context, chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) // Seal generates a new sealing request for the given input block and pushes @@ -105,7 +106,7 @@ type Engine interface { // // Note, the method returns immediately and will send the result async. More // than one result may also be returned depending on the consensus algorithm. - Seal(chain ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error + Seal(ctx context.Context, chain ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error // SealHash returns the hash of a block prior to it being sealed. SealHash(header *types.Header) common.Hash diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 7dec436a26..761442f44e 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -18,6 +18,7 @@ package ethash import ( "bytes" + "context" "errors" "fmt" "math/big" @@ -598,7 +599,7 @@ func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types. // FinalizeAndAssemble implements consensus.Engine, accumulating the block and // uncle rewards, setting the final state and assembling the block. -func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { +func (ethash *Ethash) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { // Finalize block ethash.Finalize(chain, header, state, txs, uncles) diff --git a/consensus/ethash/ethash_test.go b/consensus/ethash/ethash_test.go index 382eefeecf..ef8cd3e8fa 100644 --- a/consensus/ethash/ethash_test.go +++ b/consensus/ethash/ethash_test.go @@ -17,6 +17,7 @@ package ethash import ( + "context" "io/ioutil" "math/big" "math/rand" @@ -38,7 +39,7 @@ func TestTestMode(t *testing.T) { defer ethash.Close() results := make(chan *types.Block) - err := ethash.Seal(nil, types.NewBlockWithHeader(header), results, nil) + err := ethash.Seal(context.Background(), nil, types.NewBlockWithHeader(header), results, nil) if err != nil { t.Fatalf("failed to seal block: %v", err) } @@ -111,12 +112,13 @@ func TestRemoteSealer(t *testing.T) { // Push new work. results := make(chan *types.Block) - ethash.Seal(nil, block, results, nil) + err := ethash.Seal(context.Background(), nil, block, results, nil) - var ( - work [4]string - err error - ) + if err != nil { + t.Error("error in sealing block") + } + + var work [4]string if work, err = api.GetWork(); err != nil || work[0] != sealhash.Hex() { t.Error("expect to return a mining work has same hash") } @@ -128,7 +130,11 @@ func TestRemoteSealer(t *testing.T) { header = &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(1000)} block = types.NewBlockWithHeader(header) sealhash = ethash.SealHash(header) - ethash.Seal(nil, block, results, nil) + err = ethash.Seal(context.Background(), nil, block, results, nil) + + if err != nil { + t.Error("error in sealing block") + } if work, err = api.GetWork(); err != nil || work[0] != sealhash.Hex() { t.Error("expect to return the latest pushed work") diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index 6fa60ef6a8..d851a065f2 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -48,7 +48,7 @@ var ( // Seal implements consensus.Engine, attempting to find a nonce that satisfies // the block's difficulty requirements. -func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { +func (ethash *Ethash) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { // If we're running a fake PoW, simply return a 0 nonce immediately if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake { header := block.Header() @@ -62,7 +62,7 @@ func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block } // If we're running a shared PoW, delegate sealing to it if ethash.shared != nil { - return ethash.shared.Seal(chain, block, results, stop) + return ethash.shared.Seal(ctx, chain, block, results, stop) } // Create a runner and the multiple search threads it directs abort := make(chan struct{}) @@ -117,7 +117,8 @@ func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block case <-ethash.update: // Thread count was changed on user request, restart close(abort) - if err := ethash.Seal(chain, block, results, stop); err != nil { + + if err := ethash.Seal(ctx, chain, block, results, stop); err != nil { ethash.config.Log.Error("Failed to restart sealing after update", "err", err) } } diff --git a/consensus/ethash/sealer_test.go b/consensus/ethash/sealer_test.go index a9e96af866..c46077f561 100644 --- a/consensus/ethash/sealer_test.go +++ b/consensus/ethash/sealer_test.go @@ -17,6 +17,7 @@ package ethash import ( + "context" "encoding/json" "io/ioutil" "math/big" @@ -57,7 +58,11 @@ func TestRemoteNotify(t *testing.T) { header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} block := types.NewBlockWithHeader(header) - ethash.Seal(nil, block, nil, nil) + err := ethash.Seal(context.Background(), nil, block, nil, nil) + + if err != nil { + t.Error("error in sealing block") + } select { case work := <-sink: if want := ethash.SealHash(header).Hex(); work[0] != want { @@ -105,7 +110,11 @@ func TestRemoteNotifyFull(t *testing.T) { header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)} block := types.NewBlockWithHeader(header) - ethash.Seal(nil, block, nil, nil) + err := ethash.Seal(context.Background(), nil, block, nil, nil) + + if err != nil { + t.Error("error in sealing block") + } select { case work := <-sink: if want := "0x" + strconv.FormatUint(header.Number.Uint64(), 16); work["number"] != want { @@ -151,7 +160,11 @@ func TestRemoteMultiNotify(t *testing.T) { for i := 0; i < cap(sink); i++ { header := &types.Header{Number: big.NewInt(int64(i)), Difficulty: big.NewInt(100)} block := types.NewBlockWithHeader(header) - ethash.Seal(nil, block, results, nil) + err := ethash.Seal(context.Background(), nil, block, results, nil) + + if err != nil { + t.Error("error in sealing block") + } } for i := 0; i < cap(sink); i++ { @@ -180,6 +193,9 @@ func TestRemoteMultiNotifyFull(t *testing.T) { } sink <- work })) + + // Allowing the server to start listening. + time.Sleep(2 * time.Second) defer server.Close() // Create the custom ethash engine. @@ -200,7 +216,11 @@ func TestRemoteMultiNotifyFull(t *testing.T) { for i := 0; i < cap(sink); i++ { header := &types.Header{Number: big.NewInt(int64(i)), Difficulty: big.NewInt(100)} block := types.NewBlockWithHeader(header) - ethash.Seal(nil, block, results, nil) + err := ethash.Seal(context.Background(), nil, block, results, nil) + + if err != nil { + t.Error("error in sealing block") + } } for i := 0; i < cap(sink); i++ { @@ -266,7 +286,11 @@ func TestStaleSubmission(t *testing.T) { for id, c := range testcases { for _, h := range c.headers { - ethash.Seal(nil, types.NewBlockWithHeader(h), results, nil) + err := ethash.Seal(context.Background(), nil, types.NewBlockWithHeader(h), results, nil) + + if err != nil { + t.Error("error in sealing block") + } } if res := api.SubmitWork(fakeNonce, ethash.SealHash(c.headers[c.submitIndex]), fakeDigest); res != c.submitRes { t.Errorf("case %d submit result mismatch, want %t, get %t", id+1, c.submitRes, res) diff --git a/consensus/misc/eip1559.go b/consensus/misc/eip1559.go index 8fca0fdc70..193a5b84e2 100644 --- a/consensus/misc/eip1559.go +++ b/consensus/misc/eip1559.go @@ -59,9 +59,10 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { } var ( - parentGasTarget = parent.GasLimit / params.ElasticityMultiplier - parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget) - baseFeeChangeDenominator = new(big.Int).SetUint64(params.BaseFeeChangeDenominator) + parentGasTarget = parent.GasLimit / params.ElasticityMultiplier + parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget) + baseFeeChangeDenominatorUint64 = params.BaseFeeChangeDenominator(config.Bor, parent.Number) + baseFeeChangeDenominator = new(big.Int).SetUint64(baseFeeChangeDenominatorUint64) ) // If the parent gasUsed is the same as the target, the baseFee remains unchanged. if parent.GasUsed == parentGasTarget { diff --git a/consensus/misc/eip1559_test.go b/consensus/misc/eip1559_test.go index 23cd9023de..aba95d8005 100644 --- a/consensus/misc/eip1559_test.go +++ b/consensus/misc/eip1559_test.go @@ -20,7 +20,6 @@ import ( "math/big" "testing" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) @@ -47,12 +46,14 @@ func copyConfig(original *params.ChainConfig) *params.ChainConfig { TerminalTotalDifficulty: original.TerminalTotalDifficulty, Ethash: original.Ethash, Clique: original.Clique, + Bor: original.Bor, } } func config() *params.ChainConfig { config := copyConfig(params.TestChainConfig) config.LondonBlock = big.NewInt(5) + config.Bor.DelhiBlock = big.NewInt(8) return config } @@ -108,6 +109,8 @@ func TestBlockGasLimits(t *testing.T) { // TestCalcBaseFee assumes all blocks are 1559-blocks func TestCalcBaseFee(t *testing.T) { + t.Parallel() + tests := []struct { parentBaseFee int64 parentGasLimit uint64 @@ -117,10 +120,12 @@ func TestCalcBaseFee(t *testing.T) { {params.InitialBaseFee, 20000000, 10000000, params.InitialBaseFee}, // usage == target {params.InitialBaseFee, 20000000, 9000000, 987500000}, // usage below target {params.InitialBaseFee, 20000000, 11000000, 1012500000}, // usage above target + {params.InitialBaseFee, 20000000, 20000000, 1125000000}, // usage full + {params.InitialBaseFee, 20000000, 0, 875000000}, // usage 0 } for i, test := range tests { parent := &types.Header{ - Number: common.Big32, + Number: big.NewInt(6), GasLimit: test.parentGasLimit, GasUsed: test.parentGasUsed, BaseFee: big.NewInt(test.parentBaseFee), @@ -130,3 +135,38 @@ func TestCalcBaseFee(t *testing.T) { } } } + +// TestCalcBaseFee assumes all blocks are 1559-blocks post Delhi Hard Fork +func TestCalcBaseFeeDelhi(t *testing.T) { + t.Parallel() + + testConfig := copyConfig(config()) + + // Test Delhi Hard Fork + // Hard fork kicks in at block 8 + + tests := []struct { + parentBaseFee int64 + parentGasLimit uint64 + parentGasUsed uint64 + expectedBaseFee int64 + }{ + {params.InitialBaseFee, 20000000, 10000000, params.InitialBaseFee}, // usage == target + {params.InitialBaseFee, 20000000, 9000000, 993750000}, // usage below target + {params.InitialBaseFee, 20000000, 11000000, 1006250000}, // usage above target + {params.InitialBaseFee, 20000000, 20000000, 1062500000}, // usage full + {params.InitialBaseFee, 20000000, 0, 937500000}, // usage 0 + + } + for i, test := range tests { + parent := &types.Header{ + Number: big.NewInt(8), + GasLimit: test.parentGasLimit, + GasUsed: test.parentGasUsed, + BaseFee: big.NewInt(test.parentBaseFee), + } + if have, want := CalcBaseFee(testConfig, parent), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 { + t.Errorf("test %d: have %d want %d, ", i, have, want) + } + } +} diff --git a/core/bench_test.go b/core/bench_test.go index ad6179d0a8..7a02b11eb7 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -162,7 +162,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) { // genUncles generates blocks with two uncle headers. func genUncles(i int, gen *BlockGen) { - if i >= 6 { + if i >= 7 { b2 := gen.PrevBlock(i - 6).Header() b2.Extra = []byte("foo") gen.AddUncle(b2) @@ -201,7 +201,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Time the insertion of the new chain. // State and blocks are stored in the same DB. - chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() @@ -317,7 +317,8 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } - chain, err := NewBlockChain(db, &cacheConfig, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + + chain, err := NewBlockChain(db, &cacheConfig, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if err != nil { b.Fatalf("error creating chain: %v", err) } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 0f183ba527..c777d31c4a 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -49,7 +49,7 @@ func TestHeaderVerification(t *testing.T) { headers[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer chain.Stop() for i := 0; i < len(blocks); i++ { @@ -168,7 +168,7 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) { t.Logf("Log header after the merging %d: %v", block.NumberU64(), string(blob)) } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, _ := NewBlockChain(testdb, nil, chainConfig, runEngine, vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, chainConfig, runEngine, vm.Config{}, nil, nil, nil) defer chain.Stop() // Verify the blocks before the merging @@ -279,11 +279,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { var results <-chan error if valid { - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } else { - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil, nil) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } @@ -346,7 +346,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { defer runtime.GOMAXPROCS(old) // Start the verifications and immediately abort - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil, nil) defer chain.Stop() abort, results := chain.engine.VerifyHeaders(chain, headers, seals) diff --git a/core/blockchain.go b/core/blockchain.go index 8a4c581f66..8103e4a05e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -29,6 +29,7 @@ import ( lru "github.com/hashicorp/golang-lru" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/prque" @@ -38,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/downloader/whitelist" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/internal/syncx" @@ -90,7 +92,6 @@ const ( txLookupCacheLimit = 1024 maxFutureBlocks = 256 maxTimeFutureBlocks = 30 - TriesInMemory = 128 // BlockChainVersion ensures that an incompatible database forces a resync from scratch. // @@ -130,6 +131,7 @@ type CacheConfig struct { TrieTimeLimit time.Duration // Time limit after which to flush the current in-memory trie to disk SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory Preimages bool // Whether to store preimage of trie key to the disk + TriesInMemory uint64 // Number of recent tries to keep in memory SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it } @@ -142,6 +144,7 @@ var DefaultCacheConfig = &CacheConfig{ TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 256, SnapshotWait: true, + TriesInMemory: 128, } // BlockChain represents the canonical chain given a database with a genesis @@ -221,10 +224,16 @@ type BlockChain struct { // NewBlockChain returns a fully initialised block chain using information // available in the database. It initialises the default Ethereum Validator // and Processor. -func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64) (*BlockChain, error) { +// +//nolint:gocognit +func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(header *types.Header) bool, txLookupLimit *uint64, checker ethereum.ChainValidator) (*BlockChain, error) { if cacheConfig == nil { cacheConfig = DefaultCacheConfig } + + if cacheConfig.TriesInMemory <= 0 { + cacheConfig.TriesInMemory = DefaultCacheConfig.TriesInMemory + } bodyCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit) receiptsCache, _ := lru.New(receiptsCacheLimit) @@ -257,7 +266,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par borReceiptsCache: borReceiptsCache, } - bc.forker = NewForkChoice(bc, shouldPreserve) + bc.forker = NewForkChoice(bc, shouldPreserve, checker) bc.validator = NewBlockValidator(chainConfig, bc, engine) bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine) bc.processor = NewStateProcessor(chainConfig, bc, engine) @@ -825,7 +834,7 @@ func (bc *BlockChain) Stop() { if !bc.cacheConfig.TrieDirtyDisabled { triedb := bc.stateCache.TrieDB() - for _, offset := range []uint64{0, 1, TriesInMemory - 1} { + for _, offset := range []uint64{0, 1, bc.cacheConfig.TriesInMemory - 1} { if number := bc.CurrentBlock().NumberU64(); number > offset { recent := bc.GetBlockByNumber(number - offset) @@ -908,6 +917,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ ancientBlocks, liveBlocks types.Blocks ancientReceipts, liveReceipts []types.Receipts ) + // Do a sanity check that the provided chain is actually ordered and linked for i := 0; i < len(blockChain); i++ { if i != 0 { @@ -933,7 +943,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ // updateHead updates the head fast sync block if the inserted blocks are better // and returns an indicator whether the inserted blocks are canonical. - updateHead := func(head *types.Block) bool { + updateHead := func(head *types.Block, headers []*types.Header) bool { if !bc.chainmu.TryLock() { return false } @@ -948,6 +958,14 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } else if !reorg { return false } + + isValid, err := bc.forker.ValidateReorg(bc.CurrentFastBlock().Header(), headers) + if err != nil { + log.Warn("Reorg failed", "err", err) + return false + } else if !isValid { + return false + } rawdb.WriteHeadFastBlockHash(bc.db, head.Hash()) bc.currentFastBlock.Store(head) headFastBlockGauge.Update(int64(head.NumberU64())) @@ -985,10 +1003,14 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ return 0, fmt.Errorf("containing header #%d [%x..] unknown", last.Number(), last.Hash().Bytes()[:4]) } - // BOR: Retrieve all the bor receipts. + // BOR: Retrieve all the bor receipts and also maintain the array of headers + // for bor specific reorg check. borReceipts := []types.Receipts{} + + var headers []*types.Header for _, block := range blockChain { borReceipts = append(borReceipts, []*types.Receipt{bc.GetBorReceiptByHash(block.Hash())}) + headers = append(headers, block.Header()) } // Write all chain data to ancients. @@ -1039,7 +1061,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ } // Update the current fast block because all block data is now present in DB. previousFastBlock := bc.CurrentFastBlock().NumberU64() - if !updateHead(blockChain[len(blockChain)-1]) { + if !updateHead(blockChain[len(blockChain)-1], headers) { // We end up here if the header chain has reorg'ed, and the blocks/receipts // don't match the canonical chain. if err := bc.db.TruncateHead(previousFastBlock + 1); err != nil { @@ -1075,7 +1097,11 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ writeLive := func(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) { skipPresenceCheck := false batch := bc.db.NewBatch() + headers := make([]*types.Header, 0, len(blockChain)) for i, block := range blockChain { + // Update the headers for bor specific reorg check + headers = append(headers, block.Header()) + // Short circuit insertion if shutting down or processing failed if bc.insertStopped() { return 0, errInsertionInterrupted @@ -1122,7 +1148,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ return 0, err } } - updateHead(blockChain[len(blockChain)-1]) + + updateHead(blockChain[len(blockChain)-1], headers) return 0, nil } @@ -1275,7 +1302,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive bc.triegc.Push(root, -int64(block.NumberU64())) - if current := block.NumberU64(); current > TriesInMemory { + if current := block.NumberU64(); current > bc.cacheConfig.TriesInMemory { // If we exceeded our memory allowance, flush matured singleton nodes to disk var ( nodes, imgs = triedb.Size() @@ -1285,7 +1312,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. triedb.Cap(limit - ethdb.IdealBatchSize) } // Find the next state trie we need to commit - chosen := current - TriesInMemory + chosen := current - bc.cacheConfig.TriesInMemory // If we exceeded out time allowance, flush an entire trie to disk if bc.gcproc > bc.cacheConfig.TrieTimeLimit { @@ -1297,8 +1324,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. } else { // If we're exceeding limits but haven't reached a large enough memory gap, // warn the user that the system is becoming unstable. - if chosen < lastWrite+TriesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit { - log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TrieTimeLimit, "optimum", float64(chosen-lastWrite)/TriesInMemory) + if chosen < lastWrite+bc.cacheConfig.TriesInMemory && bc.gcproc >= 2*bc.cacheConfig.TrieTimeLimit { + log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", bc.cacheConfig.TriesInMemory, "optimum", float64(chosen-lastWrite)/float64((bc.cacheConfig.TriesInMemory))) } // Flush an entire trie and restart the counters triedb.Commit(header.Root, true, nil) @@ -1491,6 +1518,18 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) it := newInsertIterator(chain, results, bc.validator) block, err := it.next() + // Check the validity of incoming chain + isValid, err1 := bc.forker.ValidateReorg(bc.CurrentBlock().Header(), headers) + if err1 != nil { + return it.index, err1 + } + + if !isValid { + // The chain to be imported is invalid as the blocks doesn't match with + // the whitelisted checkpoints. + return it.index, whitelist.ErrCheckpointMismatch + } + // Left-trim all the known blocks that don't need to build snapshot if bc.skipBlock(err, it) { // First block (and state) is known @@ -1833,6 +1872,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i externTd *big.Int lastBlock = block current = bc.CurrentBlock() + headers []*types.Header ) // The first sidechain block error is already verified to be ErrPrunedAncestor. // Since we don't import them here, we expect ErrUnknownAncestor for the remaining @@ -1840,6 +1880,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i // to disk. err := consensus.ErrPrunedAncestor for ; block != nil && errors.Is(err, consensus.ErrPrunedAncestor); block, err = it.next() { + headers = append(headers, block.Header()) // Check the canonical state root for that number if number := block.NumberU64(); current.NumberU64() >= number { canonical := bc.GetBlockByNumber(number) @@ -1895,7 +1936,13 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i if err != nil { return it.index, err } - if !reorg { + + isValid, err := bc.forker.ValidateReorg(current.Header(), headers) + if err != nil { + return it.index, err + } + + if !reorg || !isValid { localTd := bc.GetTd(current.Hash(), current.NumberU64()) log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd) return it.index, err diff --git a/core/blockchain_bor_test.go b/core/blockchain_bor_test.go index 1b0373c41a..6bc38ec4ab 100644 --- a/core/blockchain_bor_test.go +++ b/core/blockchain_bor_test.go @@ -27,7 +27,7 @@ func TestChain2HeadEvent(t *testing.T) { signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer blockchain.Stop() chain2HeadCh := make(chan Chain2HeadEvent, 64) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index de97000918..fa6b61225e 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -59,7 +59,7 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *B ) // Initialize a fresh chain with only a genesis block - blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) // Create and inject the requested chain if n == 0 { return db, blockchain, nil @@ -655,7 +655,7 @@ func testReorgBadHashes(t *testing.T, full bool) { blockchain.Stop() // Create a new BlockChain and check that it rolled back the state. - ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } @@ -768,7 +768,7 @@ func TestFastVsFullChains(t *testing.T) { // Import the chain as an archive node for the comparison baseline archiveDb := rawdb.NewMemoryDatabase() gspec.MustCommit(archiveDb) - archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { @@ -777,7 +777,7 @@ func TestFastVsFullChains(t *testing.T) { // Fast import the chain as a non-archive node to test fastDb := rawdb.NewMemoryDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -801,7 +801,7 @@ func TestFastVsFullChains(t *testing.T) { t.Fatalf("failed to create temp freezer db: %v", err) } gspec.MustCommit(ancientDb) - ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { @@ -923,7 +923,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { archiveCaching := *DefaultCacheConfig archiveCaching.TrieDirtyDisabled = true - archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } @@ -936,7 +936,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb, delfn := makeDb() defer delfn() - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + + fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -956,7 +957,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a ancient-first node and ensure all pointers are updated ancientDb, delfn := makeDb() defer delfn() - ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + + ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { @@ -975,7 +977,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a light node and ensure all pointers are updated lightDb, delfn := makeDb() defer delfn() - light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + + light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -1044,7 +1047,7 @@ func TestChainTxReorgs(t *testing.T) { } }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -1114,7 +1117,7 @@ func TestLogReorgs(t *testing.T) { signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) @@ -1167,7 +1170,7 @@ func TestLogRebirth(t *testing.T) { genesis = gspec.MustCommit(db) signer = types.LatestSigner(gspec.Config) engine = ethash.NewFaker() - blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) ) defer blockchain.Stop() @@ -1230,7 +1233,7 @@ func TestSideLogRebirth(t *testing.T) { gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}} genesis = gspec.MustCommit(db) signer = types.LatestSigner(gspec.Config) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ) defer blockchain.Stop() @@ -1305,7 +1308,7 @@ func TestReorgSideEvent(t *testing.T) { signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer blockchain.Stop() chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {}) @@ -1437,7 +1440,7 @@ func TestEIP155Transition(t *testing.T) { genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { @@ -1545,7 +1548,8 @@ func TestEIP161AccountRemoval(t *testing.T) { } genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) { @@ -1620,7 +1624,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1648,7 +1652,7 @@ func TestTrieForkGC(t *testing.T) { db := rawdb.NewMemoryDatabase() genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) // Generate a bunch of fork blocks, each side forking from the canonical chain forks := make([]*types.Block, len(blocks)) @@ -1664,7 +1668,7 @@ func TestTrieForkGC(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1677,7 +1681,7 @@ func TestTrieForkGC(t *testing.T) { } } // Dereference all the recent tries and ensure no past trie is left in - for i := 0; i < TriesInMemory; i++ { + for i := 0; i < int(chain.cacheConfig.TriesInMemory); i++ { chain.stateCache.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) chain.stateCache.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) } @@ -1696,14 +1700,14 @@ func TestLargeReorgTrieGC(t *testing.T) { genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) - original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) - competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) + original, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) + competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*int(DefaultCacheConfig.TriesInMemory)+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) // Import the shared chain and the original canonical one diskdb := rawdb.NewMemoryDatabase() (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1732,7 +1736,8 @@ func TestLargeReorgTrieGC(t *testing.T) { if _, err := chain.InsertChain(competitor[len(competitor)-2:]); err != nil { t.Fatalf("failed to finalize competitor chain: %v", err) } - for i, block := range competitor[:len(competitor)-TriesInMemory] { + + for i, block := range competitor[:len(competitor)-int(chain.cacheConfig.TriesInMemory)] { if node, _ := chain.stateCache.TrieDB().Node(block.Root()); node != nil { t.Fatalf("competitor %d: competing chain state missing", i) } @@ -1764,7 +1769,7 @@ func TestBlockchainRecovery(t *testing.T) { t.Fatalf("failed to create temp freezer db: %v", err) } gspec.MustCommit(ancientDb) - ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -1784,7 +1789,7 @@ func TestBlockchainRecovery(t *testing.T) { rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash()) // Reopen broken blockchain again - ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer ancient.Stop() if num := ancient.CurrentBlock().NumberU64(); num != 0 { t.Errorf("head block mismatch: have #%v, want #%v", num, 0) @@ -1836,7 +1841,7 @@ func TestInsertReceiptChainRollback(t *testing.T) { } gspec := Genesis{Config: params.AllEthashProtocolChanges} gspec.MustCommit(ancientDb) - ancientChain, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancientChain, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer ancientChain.Stop() // Import the canonical header chain. @@ -1878,8 +1883,8 @@ func TestInsertReceiptChainRollback(t *testing.T) { // overtake the 'canon' chain until after it's passed canon by about 200 blocks. // // Details at: -// - https://github.com/ethereum/go-ethereum/issues/18977 -// - https://github.com/ethereum/go-ethereum/pull/18988 +// - https://github.com/ethereum/go-ethereum/issues/18977 +// - https://github.com/ethereum/go-ethereum/pull/18988 func TestLowDiffLongChain(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() @@ -1888,7 +1893,7 @@ func TestLowDiffLongChain(t *testing.T) { // We must use a pretty long chain to ensure that the fork doesn't overtake us // until after at least 128 blocks post tip - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 6*TriesInMemory, func(i int, b *BlockGen) { + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 6*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) b.OffsetTime(-9) }) @@ -1897,7 +1902,7 @@ func TestLowDiffLongChain(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1906,7 +1911,7 @@ func TestLowDiffLongChain(t *testing.T) { } // Generate fork chain, starting from an early block parent := blocks[10] - fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 8*TriesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(params.TestChainConfig, parent, engine, db, 8*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) @@ -1963,7 +1968,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Generate and import the canonical chain diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, &chainConfig, runEngine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, &chainConfig, runEngine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1975,7 +1980,8 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Set the terminal total difficulty in the config gspec.Config.TerminalTotalDifficulty = big.NewInt(0) } - blocks, _ := GenerateChain(&chainConfig, genesis, genEngine, db, 2*TriesInMemory, func(i int, gen *BlockGen) { + + blocks, _ := GenerateChain(&chainConfig, genesis, genEngine, db, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, gen *BlockGen) { tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key) if err != nil { t.Fatalf("failed to create tx: %v", err) @@ -1987,9 +1993,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon t.Fatalf("block %d: failed to insert into chain: %v", n, err) } - lastPrunedIndex := len(blocks) - TriesInMemory - 1 + lastPrunedIndex := len(blocks) - int(chain.cacheConfig.TriesInMemory) - 1 lastPrunedBlock := blocks[lastPrunedIndex] - firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] + firstNonPrunedBlock := blocks[len(blocks)-int(chain.cacheConfig.TriesInMemory)] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { @@ -2015,7 +2021,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // Generate fork chain, make it longer than canon parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock parent := blocks[parentIndex] - fork, _ := GenerateChain(&chainConfig, parent, genEngine, db, 2*TriesInMemory, func(i int, b *BlockGen) { + fork, _ := GenerateChain(&chainConfig, parent, genEngine, db, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) // Prepend the parent(s) @@ -2042,7 +2048,8 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon // That is: the sidechain for import contains some blocks already present in canon chain. // So the blocks are // [ Cn, Cn+1, Cc, Sn+3 ... Sm] -// ^ ^ ^ pruned +// +// ^ ^ ^ pruned func TestPrunedImportSide(t *testing.T) { //glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))) //glogger.Verbosity(3) @@ -2102,7 +2109,7 @@ func testInsertKnownChainData(t *testing.T, typ string) { (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb) defer os.RemoveAll(dir) - chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2266,7 +2273,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb) defer os.RemoveAll(dir) - chain, err := NewBlockChain(chaindb, nil, &chainConfig, runEngine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, nil, &chainConfig, runEngine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2384,7 +2391,7 @@ func getLongAndShortChains() (bc *BlockChain, longChain []*types.Block, heavyCha diskdb := rawdb.NewMemoryDatabase() (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) } @@ -2577,7 +2584,7 @@ func TestTransactionIndices(t *testing.T) { // Import all blocks into ancient db l := uint64(0) - chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2602,7 +2609,7 @@ func TestTransactionIndices(t *testing.T) { t.Fatalf("failed to create temp freezer db: %v", err) } gspec.MustCommit(ancientDb) - chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2626,7 +2633,7 @@ func TestTransactionIndices(t *testing.T) { limit = []uint64{0, 64 /* drop stale */, 32 /* shorten history */, 64 /* extend history */, 0 /* restore all */} tails := []uint64{0, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */, 69 /* 132 - 64 + 1 */, 0} for i, l := range limit { - chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2704,7 +2711,7 @@ func TestSkipStaleTxIndicesInSnapSync(t *testing.T) { // Import all blocks into ancient db, only HEAD-32 indices are kept. l := uint64(32) - chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l) + chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2768,7 +2775,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { b.Fatalf("failed to create tester chain: %v", err) } @@ -2837,9 +2844,9 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { // This internally leads to a sidechain import, since the blocks trigger an // ErrPrunedAncestor error. // This may e.g. happen if -// 1. Downloader rollbacks a batch of inserted blocks and exits -// 2. Downloader starts to sync again -// 3. The blocks fetched are all known and canonical blocks +// 1. Downloader rollbacks a batch of inserted blocks and exits +// 2. Downloader starts to sync again +// 3. The blocks fetched are all known and canonical blocks func TestSideImportPrunedBlocks(t *testing.T) { // Generate a canonical chain to act as the main dataset engine := ethash.NewFaker() @@ -2847,11 +2854,11 @@ func TestSideImportPrunedBlocks(t *testing.T) { genesis := (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) // Generate and import the canonical chain - blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil) + blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*int(DefaultCacheConfig.TriesInMemory), nil) diskdb := rawdb.NewMemoryDatabase() (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2859,14 +2866,15 @@ func TestSideImportPrunedBlocks(t *testing.T) { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } - lastPrunedIndex := len(blocks) - TriesInMemory - 1 + lastPrunedIndex := len(blocks) - int(chain.cacheConfig.TriesInMemory) - 1 lastPrunedBlock := blocks[lastPrunedIndex] // Verify pruning of lastPrunedBlock if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64()) } - firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] + + firstNonPrunedBlock := blocks[len(blocks)-int(chain.cacheConfig.TriesInMemory)] // Verify firstNonPrunedBlock is not pruned if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) { t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64()) @@ -2945,7 +2953,7 @@ func TestDeleteCreateRevert(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3059,7 +3067,7 @@ func TestDeleteRecreateSlots(t *testing.T) { chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ Debug: true, Tracer: logger.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3139,7 +3147,7 @@ func TestDeleteRecreateAccount(t *testing.T) { chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ Debug: true, Tracer: logger.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3312,7 +3320,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3352,20 +3360,19 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { // TestInitThenFailCreateContract tests a pretty notorious case that happened // on mainnet over blocks 7338108, 7338110 and 7338115. -// - Block 7338108: address e771789f5cccac282f23bb7add5690e1f6ca467c is initiated -// with 0.001 ether (thus created but no code) -// - Block 7338110: a CREATE2 is attempted. The CREATE2 would deploy code on -// the same address e771789f5cccac282f23bb7add5690e1f6ca467c. However, the -// deployment fails due to OOG during initcode execution -// - Block 7338115: another tx checks the balance of -// e771789f5cccac282f23bb7add5690e1f6ca467c, and the snapshotter returned it as -// zero. +// - Block 7338108: address e771789f5cccac282f23bb7add5690e1f6ca467c is initiated +// with 0.001 ether (thus created but no code) +// - Block 7338110: a CREATE2 is attempted. The CREATE2 would deploy code on +// the same address e771789f5cccac282f23bb7add5690e1f6ca467c. However, the +// deployment fails due to OOG during initcode execution +// - Block 7338115: another tx checks the balance of +// e771789f5cccac282f23bb7add5690e1f6ca467c, and the snapshotter returned it as +// zero. // // The problem being that the snapshotter maintains a destructset, and adds items // to the destructset in case something is created "onto" an existing item. // We need to either roll back the snapDestructs, or not place it into snapDestructs // in the first place. -// func TestInitThenFailCreateContract(t *testing.T) { var ( // Generate a canonical chain to act as the main dataset @@ -3446,7 +3453,7 @@ func TestInitThenFailCreateContract(t *testing.T) { chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3533,7 +3540,7 @@ func TestEIP2718Transition(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3554,13 +3561,13 @@ func TestEIP2718Transition(t *testing.T) { // TestEIP1559Transition tests the following: // -// 1. A transaction whose gasFeeCap is greater than the baseFee is valid. -// 2. Gas accounting for access lists on EIP-1559 transactions is correct. -// 3. Only the transaction's tip will be received by the coinbase. -// 4. The transaction sender pays for both the tip and baseFee. -// 5. The coinbase receives only the partially realized tip when -// gasFeeCap - gasTipCap < baseFee. -// 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap). +// 1. A transaction whose gasFeeCap is greater than the baseFee is valid. +// 2. Gas accounting for access lists on EIP-1559 transactions is correct. +// 3. Only the transaction's tip will be received by the coinbase. +// 4. The transaction sender pays for both the tip and baseFee. +// 5. The coinbase receives only the partially realized tip when +// gasFeeCap - gasTipCap < baseFee. +// 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap). func TestEIP1559Transition(t *testing.T) { var ( aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") @@ -3628,7 +3635,7 @@ func TestEIP1559Transition(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/chain_makers.go b/core/chain_makers.go index 4b2d2082df..e9944e4744 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -17,6 +17,7 @@ package core import ( + "context" "fmt" "math/big" @@ -258,7 +259,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } if b.engine != nil { // Finalize and seal the block - block, _ := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts) + block, _ := b.engine.FinalizeAndAssemble(context.Background(), chainreader, b.header, statedb, b.txs, b.uncles, b.receipts) // Write state changes to db root, err := statedb.Commit(config.IsEIP158(b.header.Number)) diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 85a029f7c7..d3024cf90a 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -79,7 +79,7 @@ func ExampleGenerateChain() { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/dao_test.go b/core/dao_test.go index c9c765a383..b43589ff51 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -45,7 +45,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { proConf.DAOForkBlock = forkBlock proConf.DAOForkSupport = true - proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil) + proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer proBc.Stop() conDb := rawdb.NewMemoryDatabase() @@ -55,7 +55,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { conConf.DAOForkBlock = forkBlock conConf.DAOForkSupport = false - conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil) + conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer conBc.Stop() if _, err := proBc.InsertChain(prefix); err != nil { @@ -69,7 +69,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a pro-fork block, and try to feed into the no-fork chain db = rawdb.NewMemoryDatabase() gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -94,7 +94,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Create a no-fork block, and try to feed into the pro-fork chain db = rawdb.NewMemoryDatabase() gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) @@ -120,7 +120,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Verify that contra-forkers accept pro-fork extra-datas after forking finishes db = rawdb.NewMemoryDatabase() gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64())) @@ -140,7 +140,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Verify that pro-forkers accept contra-fork extra-datas after forking finishes db = rawdb.NewMemoryDatabase() gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64())) diff --git a/core/forkchoice.go b/core/forkchoice.go index b0dbb200ec..018afdfac9 100644 --- a/core/forkchoice.go +++ b/core/forkchoice.go @@ -17,15 +17,14 @@ package core import ( - crand "crypto/rand" "errors" "math/big" - mrand "math/rand" + "github.com/maticnetwork/crand" + + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -47,25 +46,29 @@ type ChainReader interface { // for all other proof-of-work networks. type ForkChoice struct { chain ChainReader - rand *mrand.Rand + rand Floater // preserve is a helper function used in td fork choice. // Miners will prefer to choose the local mined block if the // local td is equal to the extern one. It can be nil for light // client preserve func(header *types.Header) bool + + validator ethereum.ChainValidator } -func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) bool) *ForkChoice { +type Floater interface { + Float64() float64 +} + +func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) bool, validator ethereum.ChainValidator) *ForkChoice { // Seed a fast but crypto originating random generator - seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) - if err != nil { - log.Crit("Failed to initialize random seed", "err", err) - } + r := crand.NewRand() return &ForkChoice{ - chain: chainReader, - rand: mrand.New(mrand.NewSource(seed.Int64())), - preserve: preserve, + chain: chainReader, + rand: r, + preserve: preserve, + validator: validator, } } @@ -106,3 +109,15 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, header *types.Header) (b } return reorg, nil } + +// ValidateReorg calls the chain validator service to check if the reorg is valid or not +func (f *ForkChoice) ValidateReorg(current *types.Header, chain []*types.Header) (bool, error) { + // Call the bor chain validator service + if f.validator != nil { + if isValid := f.validator.IsValidChain(current, chain); !isValid { + return false, nil + } + } + + return true, nil +} diff --git a/core/forkchoice_test.go b/core/forkchoice_test.go new file mode 100644 index 0000000000..2e7b40d8ff --- /dev/null +++ b/core/forkchoice_test.go @@ -0,0 +1,240 @@ +package core + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" +) + +// chainValidatorFake is a mock for the chain validator service +type chainValidatorFake struct { + validate func(currentHeader *types.Header, chain []*types.Header) bool +} + +// chainReaderFake is a mock for the chain reader service +type chainReaderFake struct { + getTd func(hash common.Hash, number uint64) *big.Int +} + +func newChainValidatorFake(validate func(currentHeader *types.Header, chain []*types.Header) bool) *chainValidatorFake { + return &chainValidatorFake{validate: validate} +} + +func newChainReaderFake(getTd func(hash common.Hash, number uint64) *big.Int) *chainReaderFake { + return &chainReaderFake{getTd: getTd} +} + +func TestPastChainInsert(t *testing.T) { + t.Parallel() + + var ( + db = rawdb.NewMemoryDatabase() + genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + ) + + hc, err := NewHeaderChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), func() bool { return false }) + if err != nil { + t.Fatal(err) + } + + // Create mocks for forker + getTd := func(hash common.Hash, number uint64) *big.Int { + return big.NewInt(int64(number)) + } + validate := func(currentHeader *types.Header, chain []*types.Header) bool { + // Put all explicit conditions here + // If canonical chain is empty and we're importing a chain of 64 blocks + if currentHeader.Number.Uint64() == uint64(0) && len(chain) == 64 { + return true + } + // If canonical chain is of len 64 and we're importing a past chain from 54-64, then accept it + if currentHeader.Number.Uint64() == uint64(64) && chain[0].Number.Uint64() == 55 && len(chain) == 10 { + return true + } + + return false + } + mockChainReader := newChainReaderFake(getTd) + mockChainValidator := newChainValidatorFake(validate) + mockForker := NewForkChoice(mockChainReader, nil, mockChainValidator) + + // chain A: G->A1->A2...A64 + chainA := makeHeaderChain(genesis.Header(), 64, ethash.NewFaker(), db, 10) + + // Inserting 64 headers on an empty chain + // expecting 1 write status with no error + testInsert(t, hc, chainA, CanonStatTy, nil, mockForker) + + // The current chain is: G->A1->A2...A64 + // chain B: G->A1->A2...A44->B45->B46...B64 + chainB := makeHeaderChain(chainA[43], 20, ethash.NewFaker(), db, 10) + + // The current chain is: G->A1->A2...A64 + // chain C: G->A1->A2...A54->C55->C56...C64 + chainC := makeHeaderChain(chainA[53], 10, ethash.NewFaker(), db, 10) + + // Update the function to consider chainC with higher difficulty + getTd = func(hash common.Hash, number uint64) *big.Int { + td := big.NewInt(int64(number)) + if hash == chainB[len(chainB)-1].Hash() || hash == chainC[len(chainC)-1].Hash() { + td = big.NewInt(65) + } + + return td + } + mockChainReader = newChainReaderFake(getTd) + mockForker = NewForkChoice(mockChainReader, nil, mockChainValidator) + + // Inserting 20 blocks from chainC on canonical chain + // expecting 2 write status with no error + testInsert(t, hc, chainB, SideStatTy, nil, mockForker) + + // Inserting 10 blocks from chainB on canonical chain + // expecting 1 write status with no error + testInsert(t, hc, chainC, CanonStatTy, nil, mockForker) +} + +func TestFutureChainInsert(t *testing.T) { + t.Parallel() + + var ( + db = rawdb.NewMemoryDatabase() + genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + ) + + hc, err := NewHeaderChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), func() bool { return false }) + if err != nil { + t.Fatal(err) + } + + // Create mocks for forker + getTd := func(hash common.Hash, number uint64) *big.Int { + return big.NewInt(int64(number)) + } + validate := func(currentHeader *types.Header, chain []*types.Header) bool { + // Put all explicit conditions here + // If canonical chain is empty and we're importing a chain of 64 blocks + if currentHeader.Number.Uint64() == uint64(0) && len(chain) == 64 { + return true + } + // If length of future chains > some value, they should not be accepted + if currentHeader.Number.Uint64() == uint64(64) && len(chain) <= 10 { + return true + } + + return false + } + mockChainReader := newChainReaderFake(getTd) + mockChainValidator := newChainValidatorFake(validate) + mockForker := NewForkChoice(mockChainReader, nil, mockChainValidator) + + // chain A: G->A1->A2...A64 + chainA := makeHeaderChain(genesis.Header(), 64, ethash.NewFaker(), db, 10) + + // Inserting 64 headers on an empty chain + // expecting 1 write status with no error + testInsert(t, hc, chainA, CanonStatTy, nil, mockForker) + + // The current chain is: G->A1->A2...A64 + // chain B: G->A1->A2...A64->B65->B66...B84 + chainB := makeHeaderChain(chainA[63], 20, ethash.NewFaker(), db, 10) + + // Inserting 20 headers on the canonical chain + // expecting 0 write status with no error + testInsert(t, hc, chainB, SideStatTy, nil, mockForker) + + // The current chain is: G->A1->A2...A64 + // chain C: G->A1->A2...A64->C65->C66...C74 + chainC := makeHeaderChain(chainA[63], 10, ethash.NewFaker(), db, 10) + + // Inserting 10 headers on the canonical chain + // expecting 0 write status with no error + testInsert(t, hc, chainC, CanonStatTy, nil, mockForker) +} + +func TestOverlappingChainInsert(t *testing.T) { + t.Parallel() + + var ( + db = rawdb.NewMemoryDatabase() + genesis = (&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) + ) + + hc, err := NewHeaderChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), func() bool { return false }) + if err != nil { + t.Fatal(err) + } + + // Create mocks for forker + getTd := func(hash common.Hash, number uint64) *big.Int { + return big.NewInt(int64(number)) + } + validate := func(currentHeader *types.Header, chain []*types.Header) bool { + // Put all explicit conditions here + // If canonical chain is empty and we're importing a chain of 64 blocks + if currentHeader.Number.Uint64() == uint64(0) && len(chain) == 64 { + return true + } + // If length of chain is > some fixed value then don't accept it + if currentHeader.Number.Uint64() == uint64(64) && len(chain) <= 20 { + return true + } + + return false + } + mockChainReader := newChainReaderFake(getTd) + mockChainValidator := newChainValidatorFake(validate) + mockForker := NewForkChoice(mockChainReader, nil, mockChainValidator) + + // chain A: G->A1->A2...A64 + chainA := makeHeaderChain(genesis.Header(), 64, ethash.NewFaker(), db, 10) + + // Inserting 64 headers on an empty chain + // expecting 1 write status with no error + testInsert(t, hc, chainA, CanonStatTy, nil, mockForker) + + // The current chain is: G->A1->A2...A64 + // chain B: G->A1->A2...A54->B55->B56...B84 + chainB := makeHeaderChain(chainA[53], 30, ethash.NewFaker(), db, 10) + + // Inserting 20 blocks on canonical chain + // expecting 2 write status with no error + testInsert(t, hc, chainB, SideStatTy, nil, mockForker) + + // The current chain is: G->A1->A2...A64 + // chain C: G->A1->A2...A54->C55->C56...C74 + chainC := makeHeaderChain(chainA[53], 20, ethash.NewFaker(), db, 10) + + // Inserting 10 blocks on canonical chain + // expecting 1 write status with no error + testInsert(t, hc, chainC, CanonStatTy, nil, mockForker) +} + +// Mock chain reader functions +func (c *chainReaderFake) Config() *params.ChainConfig { + return ¶ms.ChainConfig{TerminalTotalDifficulty: nil} +} +func (c *chainReaderFake) GetTd(hash common.Hash, number uint64) *big.Int { + return c.getTd(hash, number) +} + +// Mock chain validator functions +func (w *chainValidatorFake) IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) { + return true, nil +} +func (w *chainValidatorFake) IsValidChain(current *types.Header, headers []*types.Header) bool { + return w.validate(current, headers) +} +func (w *chainValidatorFake) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {} +func (w *chainValidatorFake) GetCheckpointWhitelist() map[uint64]common.Hash { + return nil +} +func (w *chainValidatorFake) PurgeCheckpointWhitelist() {} +func (w *chainValidatorFake) GetCheckpoints(current, sidechainHeader *types.Header, sidechainCheckpoints []*types.Header) (map[uint64]*types.Header, error) { + return map[uint64]*types.Header{}, nil +} diff --git a/core/genesis_test.go b/core/genesis_test.go index e8010e3d4e..3d3480bff8 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -117,7 +117,7 @@ func TestSetupGenesis(t *testing.T) { // Advance to block #4, past the homestead transition block of customg. genesis := oldcustomg.MustCommit(db) - bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil) defer bc.Stop() blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) diff --git a/core/headerchain.go b/core/headerchain.go index 99364f638f..83e1125305 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -283,8 +283,10 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F lastHeader: lastHeader, } ) + // Ask the fork choicer if the reorg is necessary - if reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader); err != nil { + reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader) + if err != nil { return nil, err } else if !reorg { if inserted != 0 { @@ -292,6 +294,16 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F } return result, nil } + + isValid, err := forker.ValidateReorg(hc.CurrentHeader(), headers) + if err != nil { + return nil, err + } else if !isValid { + if inserted != 0 { + result.status = SideStatTy + } + return result, nil + } // Special case, all the inserted headers are already on the canonical // header chain, skip the reorg operation. if hc.GetCanonicalHash(lastHeader.Number.Uint64()) == lastHash && lastHeader.Number.Uint64() <= hc.CurrentHeader().Number.Uint64() { diff --git a/core/headerchain_test.go b/core/headerchain_test.go index ed0522671f..85432876fa 100644 --- a/core/headerchain_test.go +++ b/core/headerchain_test.go @@ -84,7 +84,7 @@ func TestHeaderInsertion(t *testing.T) { chainB := makeHeaderChain(chainA[0], 128, ethash.NewFaker(), db, 10) log.Root().SetHandler(log.StdoutHandler) - forker := NewForkChoice(hc, nil) + forker := NewForkChoice(hc, nil, nil) // Inserting 64 headers on an empty chain, expecting // 1 callbacks, 1 canon-status, 0 sidestatus, testInsert(t, hc, chainA[:64], CanonStatTy, nil, forker) diff --git a/core/rawdb/bor_receipt.go b/core/rawdb/bor_receipt.go index 63c4be12a1..e225083741 100644 --- a/core/rawdb/bor_receipt.go +++ b/core/rawdb/bor_receipt.go @@ -18,7 +18,11 @@ var ( getDerivedBorTxHash = types.GetDerivedBorTxHash // borTxLookupPrefix + hash -> transaction/receipt lookup metadata - borTxLookupPrefix = []byte("matic-bor-tx-lookup-") + borTxLookupPrefix = []byte(borTxLookupPrefixStr) +) + +const ( + borTxLookupPrefixStr = "matic-bor-tx-lookup-" // freezerBorReceiptTable indicates the name of the freezer bor receipts table. freezerBorReceiptTable = "matic-bor-receipts" diff --git a/core/state/statedb.go b/core/state/statedb.go index 1d31cf470b..c236a79b5a 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -601,8 +601,8 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) // CreateAccount is called during the EVM CREATE operation. The situation might arise that // a contract does the following: // -// 1. sends funds to sha(account ++ (nonce + 1)) -// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1) +// 1. sends funds to sha(account ++ (nonce + 1)) +// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1) // // Carrying over the balance ensures that Ether doesn't disappear. func (s *StateDB) CreateAccount(addr common.Address) { diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 158e8c1eeb..5dc076a11c 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -94,7 +94,7 @@ func TestStateProcessorErrors(t *testing.T) { }, } genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ) defer blockchain.Stop() bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) @@ -235,7 +235,7 @@ func TestStateProcessorErrors(t *testing.T) { }, } genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ) defer blockchain.Stop() for i, tt := range []struct { @@ -275,7 +275,7 @@ func TestStateProcessorErrors(t *testing.T) { }, } genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ) defer blockchain.Stop() for i, tt := range []struct { diff --git a/core/state_transition.go b/core/state_transition.go index e867d032bf..3fc5a635e9 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -42,8 +42,10 @@ The state transitioning model does all the necessary work to work out a valid ne 3) Create a new state object if the recipient is \0*32 4) Value transfer == If contract creation == - 4a) Attempt to run transaction data - 4b) If valid, use result as code for the new state object + + 4a) Attempt to run transaction data + 4b) If valid, use result as code for the new state object + == end == 5) Run Script section 6) Derive new state root @@ -262,13 +264,13 @@ func (st *StateTransition) preCheck() error { // TransitionDb will transition the state by applying the current message and // returning the evm execution result with following fields. // -// - used gas: -// total gas used (including gas being refunded) -// - returndata: -// the returned data from evm -// - concrete execution error: -// various **EVM** error which aborts the execution, -// e.g. ErrOutOfGas, ErrExecutionReverted +// - used gas: +// total gas used (including gas being refunded) +// - returndata: +// the returned data from evm +// - concrete execution error: +// various **EVM** error which aborts the execution, +// e.g. ErrOutOfGas, ErrExecutionReverted // // However if any consensus issue encountered, return the error directly with // nil evm execution result. diff --git a/core/tests/blockchain_repair_test.go b/core/tests/blockchain_repair_test.go index b52bf76fd9..9b166b7165 100644 --- a/core/tests/blockchain_repair_test.go +++ b/core/tests/blockchain_repair_test.go @@ -29,7 +29,6 @@ import ( "github.com/golang/mock/gomock" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/bor" "github.com/ethereum/go-ethereum/consensus/bor/api" @@ -1788,6 +1787,8 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { } defer db.Close() // Might double close, should be fine + chainConfig := params.BorUnittestChainConfig + ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -1795,10 +1796,10 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { ethAPIMock.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() spanner := bor.NewMockSpanner(ctrl) - spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any()).Return([]*valset.Validator{ + spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{ { ID: 0, - Address: common.Address{0x1}, + Address: miner.TestBankAddress, VotingPower: 100, ProposerPriority: 0, }, @@ -1809,44 +1810,15 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { contractMock := bor.NewMockGenesisContract(ctrl) - // Initialize a fresh chain - var ( - gspec = &core.Genesis{ - Config: params.BorUnittestChainConfig, - BaseFee: big.NewInt(params.InitialBaseFee), - } - config = &core.CacheConfig{ - TrieCleanLimit: 256, - TrieDirtyLimit: 256, - TrieTimeLimit: 5 * time.Minute, - SnapshotLimit: 0, // Disable snapshot by default - } - ) - - engine := miner.NewFakeBor(t, db, params.BorUnittestChainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock) + engine := miner.NewFakeBor(t, db, chainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock) defer engine.Close() - engineBorInternal, ok := engine.(*bor.Bor) - if ok { - gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) - copy(gspec.ExtraData[32:32+common.AddressLength], testAddress1.Bytes()) + chainConfig.LondonBlock = big.NewInt(0) - engineBorInternal.Authorize(testAddress1, func(account accounts.Account, s string, data []byte) ([]byte, error) { - return crypto.Sign(crypto.Keccak256(data), testKey1) - }) - } + _, back, closeFn := miner.NewTestWorker(t, chainConfig, engine, db, 0) + defer closeFn() - genesis := gspec.MustCommit(db) - - if snapshots { - config.SnapshotLimit = 256 - config.SnapshotWait = true - } - - chain, err := core.NewBlockChain(db, config, params.BorUnittestChainConfig, engine, vm.Config{}, nil, nil) - if err != nil { - t.Fatalf("Failed to create chain: %v", err) - } + genesis := back.BlockChain().Genesis() // If sidechain blocks are needed, make a light chain and import it var sideblocks types.Blocks @@ -1854,56 +1826,60 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { sideblocks, _ = core.GenerateChain(params.BorUnittestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.sidechainBlocks, func(i int, b *core.BlockGen) { b.SetCoinbase(testAddress1) - if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.Sprint) { - b.SetExtra(gspec.ExtraData) + if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.CalculateSprint(b.Number().Uint64())) { + b.SetExtra(back.Genesis.ExtraData) } else { b.SetExtra(make([]byte, 32+crypto.SignatureLength)) } }) - if _, err := chain.InsertChain(sideblocks); err != nil { + if _, err := back.BlockChain().InsertChain(sideblocks); err != nil { t.Fatalf("Failed to import side chain: %v", err) } } canonblocks, _ := core.GenerateChain(params.BorUnittestChainConfig, genesis, engine, rawdb.NewMemoryDatabase(), tt.canonicalBlocks, func(i int, b *core.BlockGen) { - b.SetCoinbase(common.Address{0x02}) + b.SetCoinbase(miner.TestBankAddress) b.SetDifficulty(big.NewInt(1000000)) - if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.Sprint) { - b.SetExtra(gspec.ExtraData) + if bor.IsSprintStart(b.Number().Uint64(), params.BorUnittestChainConfig.Bor.CalculateSprint(b.Number().Uint64())) { + b.SetExtra(back.Genesis.ExtraData) } else { b.SetExtra(make([]byte, 32+crypto.SignatureLength)) } }) - if _, err := chain.InsertChain(canonblocks[:tt.commitBlock]); err != nil { + if _, err := back.BlockChain().InsertChain(canonblocks[:tt.commitBlock]); err != nil { t.Fatalf("Failed to import canonical chain start: %v", err) } if tt.commitBlock > 0 { - err = chain.StateCache().TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil) + err = back.BlockChain().StateCache().TrieDB().Commit(canonblocks[tt.commitBlock-1].Root(), true, nil) if err != nil { t.Fatal("on trieDB.Commit", err) } if snapshots { - if err := chain.Snaps().Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil { + if err := back.BlockChain().Snaps().Cap(canonblocks[tt.commitBlock-1].Root(), 0); err != nil { t.Fatalf("Failed to flatten snapshots: %v", err) } } } - if _, err := chain.InsertChain(canonblocks[tt.commitBlock:]); err != nil { + + if _, err := back.BlockChain().InsertChain(canonblocks[tt.commitBlock:]); err != nil { t.Fatalf("Failed to import canonical chain tail: %v", err) } + // Force run a freeze cycle type freezer interface { Freeze(threshold uint64) error Ancients() (uint64, error) } + db.(freezer).Freeze(tt.freezeThreshold) // Set the simulated pivot block if tt.pivotBlock != nil { rawdb.WriteLastPivotNumber(db, *tt.pivotBlock) } + // Pull the plug on the database, simulating a hard crash db.Close() @@ -1912,12 +1888,14 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { if err != nil { t.Fatalf("Failed to reopen persistent database: %v", err) } + defer db.Close() - newChain, err := core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + newChain, err := core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } + defer newChain.Stop() // Iterate over all the remaining blocks and ensure there are no gaps @@ -1929,12 +1907,15 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) { if head := newChain.CurrentHeader(); head.Number.Uint64() != tt.expHeadHeader { t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader) } + if head := newChain.CurrentFastBlock(); head.NumberU64() != tt.expHeadFastBlock { t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadFastBlock) } + if head := newChain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock { t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock) } + if frozen, err := db.(freezer).Ancients(); err != nil { t.Errorf("Failed to retrieve ancient count: %v\n", err) } else if int(frozen) != tt.expFrozen { @@ -1988,7 +1969,7 @@ func TestIssue23496(t *testing.T) { } ) - chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -2043,7 +2024,7 @@ func TestIssue23496(t *testing.T) { defer db.Close() - chain, err = core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + chain, err = core.NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } diff --git a/core/tests/blockchain_sethead_test.go b/core/tests/blockchain_sethead_test.go index 3a2d87c4eb..6160dfb48f 100644 --- a/core/tests/blockchain_sethead_test.go +++ b/core/tests/blockchain_sethead_test.go @@ -1987,7 +1987,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { config.SnapshotWait = true } - chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -2082,6 +2082,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) { // verifyNoGaps checks that there are no gaps after the initial set of blocks in // the database and errors if found. +// //nolint:gocognit func verifyNoGaps(t *testing.T, chain *core.BlockChain, canonical bool, inserted types.Blocks) { t.Helper() @@ -2135,6 +2136,7 @@ func verifyNoGaps(t *testing.T, chain *core.BlockChain, canonical bool, inserted // verifyCutoff checks that there are no chain data available in the chain after // the specified limit, but that it is available before. +// //nolint:gocognit func verifyCutoff(t *testing.T, chain *core.BlockChain, canonical bool, inserted types.Blocks, head int) { t.Helper() diff --git a/core/tests/blockchain_snapshot_test.go b/core/tests/blockchain_snapshot_test.go index fb4c09867c..26ef58f99f 100644 --- a/core/tests/blockchain_snapshot_test.go +++ b/core/tests/blockchain_snapshot_test.go @@ -84,7 +84,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*core.BlockChain, []*type cacheConfig = core.DefaultCacheConfig ) - chain, err := core.NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to create chain: %v", err) } @@ -246,7 +246,7 @@ func (snaptest *snapshotTest) test(t *testing.T) { // Restart the chain normally chain.Stop() - newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -283,13 +283,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) { // the crash, we do restart twice here: one after the crash and one // after the normal stop. It's used to ensure the broken snapshot // can be detected all the time. - newchain, err := core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } newchain.Stop() - newchain, err = core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = core.NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -327,7 +327,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { SnapshotLimit: 0, } - newchain, err := core.NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := core.NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -336,7 +336,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) { newchain.Stop() // Restart the chain with enabling the snapshot - newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -365,7 +365,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) { chain.SetHead(snaptest.setHead) chain.Stop() - newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -396,7 +396,7 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) { // and state committed. chain.Stop() - newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -414,7 +414,7 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) { // journal and latest state will be committed // Restart the chain after the crash - newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -449,8 +449,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { TrieTimeLimit: 5 * time.Minute, SnapshotLimit: 0, } - - newchain, err := core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err := core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } @@ -467,14 +466,13 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { SnapshotLimit: 256, SnapshotWait: false, // Don't wait rebuild } - - _, err = core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + _, err = core.NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } // Simulate the blockchain crash. - newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) + newchain, err = core.NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to recreate chain: %v", err) } diff --git a/core/tx_pool.go b/core/tx_pool.go index 91d221ded0..7648668688 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -268,6 +268,8 @@ type TxPool struct { initDoneCh chan struct{} // is closed once the pool is initialized (for tests) changesSinceReorg int // A counter for how many drops we've performed in-between reorg. + + promoteTxCh chan struct{} // should be used only for tests } type txpoolResetRequest struct { @@ -276,7 +278,7 @@ type txpoolResetRequest struct { // NewTxPool creates a new transaction pool to gather, sort and filter inbound // transactions from the network. -func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain) *TxPool { +func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain, options ...func(pool *TxPool)) *TxPool { // Sanitize the input to ensure no vulnerable gas prices are set config = (&config).sanitize() @@ -299,6 +301,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block initDoneCh: make(chan struct{}), gasPrice: new(big.Int).SetUint64(config.PriceLimit), } + pool.locals = newAccountSet(pool.signer) for _, addr := range config.Locals { log.Info("Setting new local account", "address", addr) @@ -307,6 +310,11 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block pool.priced = newTxPricedList(pool.all) pool.reset(nil, chain.CurrentBlock().Header()) + // apply options + for _, fn := range options { + fn(pool) + } + // Start the reorg loop early so it can handle requests generated during journal loading. pool.wg.Add(1) go pool.scheduleReorgLoop() @@ -809,6 +817,17 @@ func (pool *TxPool) journalTx(from common.Address, tx *types.Transaction) { // // Note, this method assumes the pool lock is held! func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.Transaction) bool { + defer func() { + if pool.promoteTxCh == nil { + return + } + + select { + case pool.promoteTxCh <- struct{}{}: + default: + } + }() + // Try to insert the transaction into the pending queue if pool.pending[addr] == nil { pool.pending[addr] = newTxList(true) @@ -1080,6 +1099,7 @@ func (pool *TxPool) scheduleReorgLoop() { dirtyAccounts *accountSet queuedEvents = make(map[common.Address]*txSortedMap) ) + for { // Launch next background reorg if needed if curDone == nil && launchNextRun { diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index a7af275835..664ca6c9d4 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -17,6 +17,7 @@ package core import ( + "context" "crypto/ecdsa" "errors" "fmt" @@ -24,10 +25,17 @@ import ( "math/big" "math/rand" "os" + "runtime" + "strings" + "sync" "sync/atomic" "testing" "time" + "gonum.org/v1/gonum/floats" + "gonum.org/v1/gonum/stat" + "pgregory.net/rapid" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" @@ -47,6 +55,10 @@ var ( eip1559Config *params.ChainConfig ) +const ( + txPoolGasLimit = 10_000_000 +) + func init() { testTxPoolConfig = DefaultTxPoolConfig testTxPoolConfig.Journal = "" @@ -114,15 +126,17 @@ func dynamicFeeTx(nonce uint64, gaslimit uint64, gasFee *big.Int, tip *big.Int, } func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { - return setupTxPoolWithConfig(params.TestChainConfig) + return setupTxPoolWithConfig(params.TestChainConfig, testTxPoolConfig, txPoolGasLimit) } -func setupTxPoolWithConfig(config *params.ChainConfig) (*TxPool, *ecdsa.PrivateKey) { +func setupTxPoolWithConfig(config *params.ChainConfig, txPoolConfig TxPoolConfig, gasLimit uint64, options ...func(pool *TxPool)) (*TxPool, *ecdsa.PrivateKey) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - blockchain := &testBlockChain{10000000, statedb, new(event.Feed)} + + blockchain := &testBlockChain{gasLimit, statedb, new(event.Feed)} key, _ := crypto.GenerateKey() - pool := NewTxPool(testTxPoolConfig, config, blockchain) + + pool := NewTxPool(txPoolConfig, config, blockchain, options...) // wait for the pool to initialize <-pool.initDoneCh @@ -273,6 +287,16 @@ func testSetNonce(pool *TxPool, addr common.Address, nonce uint64) { pool.mu.Unlock() } +func getBalance(pool *TxPool, addr common.Address) *big.Int { + bal := big.NewInt(0) + + pool.mu.Lock() + bal.Set(pool.currentState.GetBalance(addr)) + pool.mu.Unlock() + + return bal +} + func TestInvalidTransactions(t *testing.T) { t.Parallel() @@ -384,7 +408,7 @@ func TestTransactionNegativeValue(t *testing.T) { func TestTransactionTipAboveFeeCap(t *testing.T) { t.Parallel() - pool, key := setupTxPoolWithConfig(eip1559Config) + pool, key := setupTxPoolWithConfig(eip1559Config, testTxPoolConfig, txPoolGasLimit) defer pool.Stop() tx := dynamicFeeTx(0, 100, big.NewInt(1), big.NewInt(2), key) @@ -397,7 +421,7 @@ func TestTransactionTipAboveFeeCap(t *testing.T) { func TestTransactionVeryHighValues(t *testing.T) { t.Parallel() - pool, key := setupTxPoolWithConfig(eip1559Config) + pool, key := setupTxPoolWithConfig(eip1559Config, testTxPoolConfig, txPoolGasLimit) defer pool.Stop() veryBigNumber := big.NewInt(1) @@ -1449,7 +1473,7 @@ func TestTransactionPoolRepricingDynamicFee(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - pool, _ := setupTxPoolWithConfig(eip1559Config) + pool, _ := setupTxPoolWithConfig(eip1559Config, testTxPoolConfig, txPoolGasLimit) defer pool.Stop() // Keep track of transaction events to ensure all executables get announced @@ -1820,7 +1844,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) { func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) { t.Parallel() - pool, _ := setupTxPoolWithConfig(eip1559Config) + pool, _ := setupTxPoolWithConfig(eip1559Config, testTxPoolConfig, txPoolGasLimit) defer pool.Stop() pool.config.GlobalSlots = 2 @@ -1927,7 +1951,7 @@ func TestTransactionPoolUnderpricingDynamicFee(t *testing.T) { func TestDualHeapEviction(t *testing.T) { t.Parallel() - pool, _ := setupTxPoolWithConfig(eip1559Config) + pool, _ := setupTxPoolWithConfig(eip1559Config, testTxPoolConfig, txPoolGasLimit) defer pool.Stop() pool.config.GlobalSlots = 10 @@ -2130,7 +2154,7 @@ func TestTransactionReplacementDynamicFee(t *testing.T) { t.Parallel() // Create the pool to test the pricing enforcement with - pool, key := setupTxPoolWithConfig(eip1559Config) + pool, key := setupTxPoolWithConfig(eip1559Config, testTxPoolConfig, txPoolGasLimit) defer pool.Stop() testAddBalance(pool, crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000)) @@ -2561,3 +2585,516 @@ func BenchmarkPoolMultiAccountBatchInsert(b *testing.B) { pool.AddRemotesSync([]*types.Transaction{tx}) } } + +type acc struct { + nonce uint64 + key *ecdsa.PrivateKey + account common.Address +} + +type testTx struct { + tx *types.Transaction + idx int + isLocal bool +} + +const localIdx = 0 + +func getTransactionGen(t *rapid.T, keys []*acc, nonces []uint64, localKey *acc, gasPriceMin, gasPriceMax, gasLimitMin, gasLimitMax uint64) *testTx { + idx := rapid.IntRange(0, len(keys)-1).Draw(t, "accIdx").(int) + + var ( + isLocal bool + key *ecdsa.PrivateKey + ) + + if idx == localIdx { + isLocal = true + key = localKey.key + } else { + key = keys[idx].key + } + + nonces[idx]++ + + gasPriceUint := rapid.Uint64Range(gasPriceMin, gasPriceMax).Draw(t, "gasPrice").(uint64) + gasPrice := big.NewInt(0).SetUint64(gasPriceUint) + gasLimit := rapid.Uint64Range(gasLimitMin, gasLimitMax).Draw(t, "gasLimit").(uint64) + + return &testTx{ + tx: pricedTransaction(nonces[idx]-1, gasLimit, gasPrice, key), + idx: idx, + isLocal: isLocal, + } +} + +type transactionBatches struct { + txs []*testTx + totalTxs int +} + +func transactionsGen(keys []*acc, nonces []uint64, localKey *acc, minTxs int, maxTxs int, gasPriceMin, gasPriceMax, gasLimitMin, gasLimitMax uint64, caseParams *strings.Builder) func(t *rapid.T) *transactionBatches { + return func(t *rapid.T) *transactionBatches { + totalTxs := rapid.IntRange(minTxs, maxTxs).Draw(t, "totalTxs").(int) + txs := make([]*testTx, totalTxs) + + gasValues := make([]float64, totalTxs) + + fmt.Fprintf(caseParams, " totalTxs = %d;", totalTxs) + + keys = keys[:len(nonces)] + + for i := 0; i < totalTxs; i++ { + txs[i] = getTransactionGen(t, keys, nonces, localKey, gasPriceMin, gasPriceMax, gasLimitMin, gasLimitMax) + + gasValues[i] = float64(txs[i].tx.Gas()) + } + + mean, stddev := stat.MeanStdDev(gasValues, nil) + fmt.Fprintf(caseParams, " gasValues mean %d, stdev %d, %d-%d);", int64(mean), int64(stddev), int64(floats.Min(gasValues)), int64(floats.Max(gasValues))) + + return &transactionBatches{txs, totalTxs} + } +} + +type txPoolRapidConfig struct { + gasLimit uint64 + avgBlockTxs uint64 + + minTxs int + maxTxs int + + minAccs int + maxAccs int + + // less tweakable, more like constants + gasPriceMin uint64 + gasPriceMax uint64 + + gasLimitMin uint64 + gasLimitMax uint64 + + balance int64 + + blockTime time.Duration + maxEmptyBlocks int + maxStuckBlocks int +} + +func defaultTxPoolRapidConfig() txPoolRapidConfig { + gasLimit := uint64(30_000_000) + avgBlockTxs := gasLimit/params.TxGas + 1 + maxTxs := int(25 * avgBlockTxs) + + return txPoolRapidConfig{ + gasLimit: gasLimit, + + avgBlockTxs: avgBlockTxs, + + minTxs: 1, + maxTxs: maxTxs, + + minAccs: 1, + maxAccs: maxTxs, + + // less tweakable, more like constants + gasPriceMin: 1, + gasPriceMax: 1_000, + + gasLimitMin: params.TxGas, + gasLimitMax: gasLimit / 2, + + balance: 0xffffffffffffff, + + blockTime: 2 * time.Second, + maxEmptyBlocks: 10, + maxStuckBlocks: 10, + } +} + +// TestSmallTxPool is not something to run in parallel as far it uses all CPUs +// nolint:paralleltest +func TestSmallTxPool(t *testing.T) { + t.Parallel() + + t.Skip("a red test to be fixed") + + cfg := defaultTxPoolRapidConfig() + + cfg.maxEmptyBlocks = 10 + cfg.maxStuckBlocks = 10 + + cfg.minTxs = 1 + cfg.maxTxs = 2 + + cfg.minAccs = 1 + cfg.maxAccs = 2 + + testPoolBatchInsert(t, cfg) +} + +// This test is not something to run in parallel as far it uses all CPUs +// nolint:paralleltest +func TestBigTxPool(t *testing.T) { + t.Parallel() + + t.Skip("a red test to be fixed") + + cfg := defaultTxPoolRapidConfig() + + testPoolBatchInsert(t, cfg) +} + +//nolint:gocognit,thelper +func testPoolBatchInsert(t *testing.T, cfg txPoolRapidConfig) { + t.Helper() + + t.Parallel() + + const debug = false + + initialBalance := big.NewInt(cfg.balance) + + keys := make([]*acc, cfg.maxAccs) + + var key *ecdsa.PrivateKey + + // prealloc keys + for idx := 0; idx < cfg.maxAccs; idx++ { + key, _ = crypto.GenerateKey() + + keys[idx] = &acc{ + key: key, + nonce: 0, + account: crypto.PubkeyToAddress(key.PublicKey), + } + } + + var threads = runtime.NumCPU() + + if debug { + // 1 is set only for debug + threads = 1 + } + + testsDone := new(uint64) + + for i := 0; i < threads; i++ { + t.Run(fmt.Sprintf("thread %d", i), func(t *testing.T) { + t.Parallel() + + rapid.Check(t, func(rt *rapid.T) { + caseParams := new(strings.Builder) + + defer func() { + res := atomic.AddUint64(testsDone, 1) + + if res%100 == 0 { + fmt.Println("case-done", res) + } + }() + + // Generate a batch of transactions to enqueue into the pool + testTxPoolConfig := testTxPoolConfig + + // from sentry config + testTxPoolConfig.AccountQueue = 16 + testTxPoolConfig.AccountSlots = 16 + testTxPoolConfig.GlobalQueue = 32768 + testTxPoolConfig.GlobalSlots = 32768 + testTxPoolConfig.Lifetime = time.Hour + 30*time.Minute //"1h30m0s" + testTxPoolConfig.PriceLimit = 1 + + now := time.Now() + pendingAddedCh := make(chan struct{}, 1024) + pool, key := setupTxPoolWithConfig(params.TestChainConfig, testTxPoolConfig, cfg.gasLimit, MakeWithPromoteTxCh(pendingAddedCh)) + defer pool.Stop() + + totalAccs := rapid.IntRange(cfg.minAccs, cfg.maxAccs).Draw(rt, "totalAccs").(int) + + fmt.Fprintf(caseParams, "Case params: totalAccs = %d;", totalAccs) + + defer func() { + pending, queued := pool.Content() + + if len(pending) != 0 { + pendingGas := make([]float64, 0, len(pending)) + + for _, txs := range pending { + for _, tx := range txs { + pendingGas = append(pendingGas, float64(tx.Gas())) + } + } + + mean, stddev := stat.MeanStdDev(pendingGas, nil) + fmt.Fprintf(caseParams, "\tpending mean %d, stdev %d, %d-%d;\n", int64(mean), int64(stddev), int64(floats.Min(pendingGas)), int64(floats.Max(pendingGas))) + } + + if len(queued) != 0 { + queuedGas := make([]float64, 0, len(queued)) + + for _, txs := range queued { + for _, tx := range txs { + queuedGas = append(queuedGas, float64(tx.Gas())) + } + } + + mean, stddev := stat.MeanStdDev(queuedGas, nil) + fmt.Fprintf(caseParams, "\tqueued mean %d, stdev %d, %d-%d);\n\n", int64(mean), int64(stddev), int64(floats.Min(queuedGas)), int64(floats.Max(queuedGas))) + } + + rt.Log(caseParams) + }() + + // regenerate only local key + localKey := &acc{ + key: key, + account: crypto.PubkeyToAddress(key.PublicKey), + } + + if err := validateTxPoolInternals(pool); err != nil { + rt.Fatalf("pool internal state corrupted: %v", err) + } + + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + now = time.Now() + + testAddBalance(pool, localKey.account, initialBalance) + + for idx := 0; idx < totalAccs; idx++ { + testAddBalance(pool, keys[idx].account, initialBalance) + } + }() + + nonces := make([]uint64, totalAccs) + gen := rapid.Custom(transactionsGen(keys, nonces, localKey, cfg.minTxs, cfg.maxTxs, cfg.gasPriceMin, cfg.gasPriceMax, cfg.gasLimitMin, cfg.gasLimitMax, caseParams)) + + txs := gen.Draw(rt, "batches").(*transactionBatches) + + wg.Wait() + + var ( + addIntoTxPool func(tx []*types.Transaction) []error + totalInBatch int + ) + + for _, tx := range txs.txs { + addIntoTxPool = pool.AddRemotesSync + + if tx.isLocal { + addIntoTxPool = pool.AddLocals + } + + err := addIntoTxPool([]*types.Transaction{tx.tx}) + if len(err) != 0 && err[0] != nil { + rt.Log("on adding a transaction to the tx pool", err[0], tx.tx.Gas(), tx.tx.GasPrice(), pool.GasPrice(), getBalance(pool, keys[tx.idx].account)) + } + } + + var ( + block int + emptyBlocks int + stuckBlocks int + lastTxPoolStats int + currentTxPoolStats int + ) + + for { + // we'd expect fulfilling block take comparable, but less than blockTime + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(cfg.maxStuckBlocks)*cfg.blockTime) + + select { + case <-pendingAddedCh: + case <-ctx.Done(): + pendingStat, queuedStat := pool.Stats() + if pendingStat+queuedStat == 0 { + cancel() + + break + } + + rt.Fatalf("got %ds block timeout (expected less then %s): total accounts %d. Pending %d, queued %d)", + block, 5*cfg.blockTime, txs.totalTxs, pendingStat, queuedStat) + } + + pendingStat, queuedStat := pool.Stats() + currentTxPoolStats = pendingStat + queuedStat + if currentTxPoolStats == 0 { + cancel() + break + } + + // check if txPool got stuck + if currentTxPoolStats == lastTxPoolStats { + stuckBlocks++ //todo: переписать + } else { + stuckBlocks = 0 + lastTxPoolStats = currentTxPoolStats + } + + // copy-paste + start := time.Now() + pending := pool.Pending(true) + locals := pool.Locals() + + // from fillTransactions + removedFromPool, blockGasLeft, err := fillTransactions(ctx, pool, locals, pending, cfg.gasLimit) + + done := time.Since(start) + + if removedFromPool > 0 { + emptyBlocks = 0 + } else { + emptyBlocks++ + } + + if emptyBlocks >= cfg.maxEmptyBlocks || stuckBlocks >= cfg.maxStuckBlocks { + // check for nonce gaps + var lastNonce, currentNonce int + + pending = pool.Pending(true) + + for txAcc, pendingTxs := range pending { + lastNonce = int(pool.Nonce(txAcc)) - len(pendingTxs) - 1 + + isFirst := true + + for _, tx := range pendingTxs { + currentNonce = int(tx.Nonce()) + if currentNonce-lastNonce != 1 { + rt.Fatalf("got a nonce gap for account %q. Current pending nonce %d, previous %d %v; emptyBlocks - %v; stuckBlocks - %v", + txAcc, currentNonce, lastNonce, isFirst, emptyBlocks >= cfg.maxEmptyBlocks, stuckBlocks >= cfg.maxStuckBlocks) + } + + lastNonce = currentNonce + } + } + } + + if emptyBlocks >= cfg.maxEmptyBlocks { + rt.Fatalf("got %d empty blocks in a row(expected less then %d): total time %s, total accounts %d. Pending %d, locals %d)", + emptyBlocks, cfg.maxEmptyBlocks, done, txs.totalTxs, len(pending), len(locals)) + } + + if stuckBlocks >= cfg.maxStuckBlocks { + rt.Fatalf("got %d empty blocks in a row(expected less then %d): total time %s, total accounts %d. Pending %d, locals %d)", + emptyBlocks, cfg.maxEmptyBlocks, done, txs.totalTxs, len(pending), len(locals)) + } + + if err != nil { + rt.Fatalf("took too long: total time %s(expected %s), total accounts %d. Pending %d, locals %d)", + done, cfg.blockTime, txs.totalTxs, len(pending), len(locals)) + } + + rt.Log("current_total", txs.totalTxs, "in_batch", totalInBatch, "removed", removedFromPool, "emptyBlocks", emptyBlocks, "blockGasLeft", blockGasLeft, "pending", len(pending), "locals", len(locals), + "locals+pending", done) + + rt.Log("block", block, "pending", pendingStat, "queued", queuedStat, "elapsed", done) + + block++ + + cancel() + + //time.Sleep(time.Second) + } + + rt.Logf("case completed totalTxs %d %v\n\n", txs.totalTxs, time.Since(now)) + }) + }) + } + + t.Log("done test cases", atomic.LoadUint64(testsDone)) +} + +func fillTransactions(ctx context.Context, pool *TxPool, locals []common.Address, pending map[common.Address]types.Transactions, gasLimit uint64) (int, uint64, error) { + localTxs := make(map[common.Address]types.Transactions) + remoteTxs := pending + + for _, txAcc := range locals { + if txs := remoteTxs[txAcc]; len(txs) > 0 { + delete(remoteTxs, txAcc) + + localTxs[txAcc] = txs + } + } + + // fake signer + signer := types.NewLondonSigner(big.NewInt(1)) + + // fake baseFee + baseFee := big.NewInt(1) + + blockGasLimit := gasLimit + + var ( + txLocalCount int + txRemoteCount int + ) + + if len(localTxs) > 0 { + txs := types.NewTransactionsByPriceAndNonce(signer, localTxs, baseFee) + + select { + case <-ctx.Done(): + return txLocalCount + txRemoteCount, blockGasLimit, ctx.Err() + default: + } + + blockGasLimit, txLocalCount = commitTransactions(pool, txs, blockGasLimit) + } + + select { + case <-ctx.Done(): + return txLocalCount + txRemoteCount, blockGasLimit, ctx.Err() + default: + } + + if len(remoteTxs) > 0 { + txs := types.NewTransactionsByPriceAndNonce(signer, remoteTxs, baseFee) + + select { + case <-ctx.Done(): + return txLocalCount + txRemoteCount, blockGasLimit, ctx.Err() + default: + } + + blockGasLimit, txRemoteCount = commitTransactions(pool, txs, blockGasLimit) + } + + return txLocalCount + txRemoteCount, blockGasLimit, nil +} + +func commitTransactions(pool *TxPool, txs *types.TransactionsByPriceAndNonce, blockGasLimit uint64) (uint64, int) { + var ( + tx *types.Transaction + txCount int + ) + + for { + tx = txs.Peek() + + if tx == nil { + return blockGasLimit, txCount + } + + if tx.Gas() <= blockGasLimit { + blockGasLimit -= tx.Gas() + pool.removeTx(tx.Hash(), false) + + txCount++ + } else { + // we don't maximize fulfilment of the block. just fill somehow + return blockGasLimit, txCount + } + } +} + +func MakeWithPromoteTxCh(ch chan struct{}) func(*TxPool) { + return func(pool *TxPool) { + pool.promoteTxCh = ch + } +} diff --git a/core/types/transaction.go b/core/types/transaction.go index 29820a0d78..e0e52f25bc 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -508,6 +508,10 @@ func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transa // Initialize a price and received time based heap with the head transactions heads := make(TxByPriceAndTime, 0, len(txs)) for from, accTxs := range txs { + if len(accTxs) == 0 { + continue + } + acc, _ := Sender(signer, accTxs[0]) wrapped, err := NewTxWithMinerFee(accTxs[0], baseFee) // Remove transaction if sender doesn't match from, or if wrapping fails. @@ -550,6 +554,10 @@ func (t *TransactionsByPriceAndNonce) Shift() { heap.Pop(&t.heads) } +func (t *TransactionsByPriceAndNonce) GetTxs() int { + return len(t.txs) +} + // Pop removes the best transaction, *not* replacing it with the next one from // the same account. This should be used when a transaction cannot be executed // and hence all subsequent ones should be discarded from the same account. diff --git a/eth/api.go b/eth/api.go index f81dfa922b..f571a57507 100644 --- a/eth/api.go +++ b/eth/api.go @@ -343,7 +343,8 @@ func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, } else { blockRlp = fmt.Sprintf("0x%x", rlpBytes) } - if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig()); err != nil { + + if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig(), api.eth.chainDb); err != nil { blockJSON = map[string]interface{}{"error": err.Error()} } results = append(results, &BadBlockArgs{ diff --git a/eth/backend.go b/eth/backend.go index 0b8a956cfa..824fec8914 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -18,6 +18,7 @@ package eth import ( + "context" "errors" "fmt" "math/big" @@ -40,6 +41,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" + "github.com/ethereum/go-ethereum/eth/downloader/whitelist" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" @@ -216,9 +218,13 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { TrieTimeLimit: config.TrieTimeout, SnapshotLimit: config.SnapshotCache, Preimages: config.Preimages, + TriesInMemory: config.TriesInMemory, } ) - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) + + checker := whitelist.NewService(10) + + eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit, checker) if err != nil { return nil, err } @@ -259,6 +265,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { Checkpoint: checkpoint, EthAPI: ethAPI, PeerRequiredBlocks: config.PeerRequiredBlocks, + checker: checker, }); err != nil { return nil, err } @@ -376,6 +383,10 @@ func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { s.blockchain.ResetWithGenesisBlock(gb) } +func (s *Ethereum) PublicBlockChainAPI() *ethapi.PublicBlockChainAPI { + return s.handler.ethAPI +} + func (s *Ethereum) Etherbase() (eb common.Address, err error) { s.lock.RLock() etherbase := s.etherbase @@ -621,6 +632,13 @@ func (s *Ethereum) Start() error { return nil } +var ( + ErrNotBorConsensus = errors.New("not bor consensus was given") + ErrBorConsensusWithoutHeimdall = errors.New("bor consensus without heimdall") + + whitelistTimeout = 30 * time.Second +) + // StartCheckpointWhitelistService starts the goroutine to fetch checkpoints and update the // checkpoint whitelist map. func (s *Ethereum) startCheckpointWhitelistService() { @@ -632,7 +650,11 @@ func (s *Ethereum) startCheckpointWhitelistService() { } // first run the checkpoint whitelist - err := s.handleWhitelistCheckpoint() + firstCtx, cancel := context.WithTimeout(context.Background(), whitelistTimeout) + err := s.handleWhitelistCheckpoint(firstCtx, true) + + cancel() + if err != nil { if errors.Is(err, ErrBorConsensusWithoutHeimdall) || errors.Is(err, ErrNotBorConsensus) { return @@ -647,7 +669,11 @@ func (s *Ethereum) startCheckpointWhitelistService() { for { select { case <-ticker.C: - err := s.handleWhitelistCheckpoint() + ctx, cancel := context.WithTimeout(context.Background(), whitelistTimeout) + err := s.handleWhitelistCheckpoint(ctx, false) + + cancel() + if err != nil { log.Warn("unable to whitelist checkpoint", "err", err) } @@ -657,13 +683,8 @@ func (s *Ethereum) startCheckpointWhitelistService() { } } -var ( - ErrNotBorConsensus = errors.New("not bor consensus was given") - ErrBorConsensusWithoutHeimdall = errors.New("bor consensus without heimdall") -) - // handleWhitelistCheckpoint handles the checkpoint whitelist mechanism. -func (s *Ethereum) handleWhitelistCheckpoint() error { +func (s *Ethereum) handleWhitelistCheckpoint(ctx context.Context, first bool) error { ethHandler := (*ethHandler)(s.handler) bor, ok := ethHandler.chain.Engine().(*bor.Bor) @@ -675,13 +696,20 @@ func (s *Ethereum) handleWhitelistCheckpoint() error { return ErrBorConsensusWithoutHeimdall } - endBlockNum, endBlockHash, err := ethHandler.fetchWhitelistCheckpoint(bor) - if err != nil { + // Create a new checkpoint verifier + verifier := newCheckpointVerifier(nil) + blockNums, blockHashes, err := ethHandler.fetchWhitelistCheckpoints(ctx, bor, verifier, first) + // If the array is empty, we're bound to receive an error. Non-nill error and non-empty array + // means that array has partial elements and it failed for some block. We'll add those partial + // elements anyway. + if len(blockNums) == 0 { return err } // Update the checkpoint whitelist map. - ethHandler.downloader.ProcessCheckpoint(endBlockNum, endBlockHash) + for i := 0; i < len(blockNums); i++ { + ethHandler.downloader.ProcessCheckpoint(blockNums[i], blockHashes[i]) + } return nil } diff --git a/eth/bor_checkpoint_verifier.go b/eth/bor_checkpoint_verifier.go new file mode 100644 index 0000000000..61e8c382e1 --- /dev/null +++ b/eth/bor_checkpoint_verifier.go @@ -0,0 +1,60 @@ +package eth + +import ( + "context" + "fmt" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" +) + +type checkpointVerifier struct { + verify func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error) +} + +func newCheckpointVerifier(verifyFn func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error)) *checkpointVerifier { + if verifyFn != nil { + return &checkpointVerifier{verifyFn} + } + + verifyFn = func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error) { + var ( + startBlock = checkpoint.StartBlock.Uint64() + endBlock = checkpoint.EndBlock.Uint64() + ) + + // check if we have the checkpoint blocks + head := handler.ethAPI.BlockNumber() + if head < hexutil.Uint64(endBlock) { + log.Debug("Head block behind checkpoint block", "head", head, "checkpoint end block", endBlock) + return "", errMissingCheckpoint + } + + // verify the root hash of checkpoint + roothash, err := handler.ethAPI.GetRootHash(ctx, startBlock, endBlock) + if err != nil { + log.Debug("Failed to get root hash of checkpoint while whitelisting", "err", err) + return "", errRootHash + } + + if roothash != checkpoint.RootHash.String()[2:] { + log.Warn("Checkpoint root hash mismatch while whitelisting", "expected", checkpoint.RootHash.String()[2:], "got", roothash) + return "", errCheckpointRootHashMismatch + } + + // fetch the end checkpoint block hash + block, err := handler.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(endBlock), false) + if err != nil { + log.Debug("Failed to get end block hash of checkpoint while whitelisting", "err", err) + return "", errEndBlock + } + + hash := fmt.Sprintf("%v", block["hash"]) + + return hash, nil + } + + return &checkpointVerifier{verifyFn} +} diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 1a9d815ccd..f92bc652a6 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -144,7 +144,7 @@ type Downloader struct { quitCh chan struct{} // Quit channel to signal termination quitLock sync.Mutex // Lock to prevent double closes - ChainValidator + ethereum.ChainValidator // Testing hooks syncInitHook func(uint64, uint64) // Method to call upon initiating a new sync run @@ -153,14 +153,6 @@ type Downloader struct { chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations) } -// interface for whitelist service -type ChainValidator interface { - IsValidChain(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) - ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) - GetCheckpointWhitelist() map[uint64]common.Hash - PurgeCheckpointWhitelist() -} - // LightChain encapsulates functions required to synchronise a light chain. type LightChain interface { // HasHeader verifies a header's presence in the local chain. @@ -215,8 +207,8 @@ type BlockChain interface { } // New creates a new downloader to fetch hashes and blocks from remote peers. -//nolint: staticcheck -func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func(), whitelistService ChainValidator) *Downloader { +// nolint: staticcheck +func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func(), whitelistService ethereum.ChainValidator) *Downloader { if lightchain == nil { lightchain = chain } @@ -737,9 +729,11 @@ func (d *Downloader) fetchHead(p *peerConnection) (head *types.Header, pivot *ty // calculateRequestSpan calculates what headers to request from a peer when trying to determine the // common ancestor. // It returns parameters to be used for peer.RequestHeadersByNumber: -// from - starting block number -// count - number of headers to request -// skip - number of headers to skip +// +// from - starting block number +// count - number of headers to request +// skip - number of headers to skip +// // and also returns 'max', the last block which is expected to be returned by the remote peers, // given the (from,count,skip) func calculateRequestSpan(remoteHeight, localHeight uint64) (int64, int, int, uint64) { @@ -799,9 +793,11 @@ func (d *Downloader) getFetchHeadersByNumber(p *peerConnection) func(number uint // In the rare scenario when we ended up on a long reorganisation (i.e. none of // the head links match), we do a binary search to find the common ancestor. func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) (uint64, error) { - // Check the validity of chain to be downloaded - if _, err := d.IsValidChain(remoteHeader, d.getFetchHeadersByNumber(p)); err != nil { - return 0, err + // Check the validity of peer from which the chain is to be downloaded + if d.ChainValidator != nil { + if _, err := d.IsValidPeer(remoteHeader, d.getFetchHeadersByNumber(p)); err != nil { + return 0, err + } } // Figure out the valid ancestor range to prevent rewrite attacks diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 37b07424dd..d8765ef077 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -71,7 +71,7 @@ func newTester() *downloadTester { core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000)) - chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if err != nil { panic(err) } @@ -88,7 +88,7 @@ func newTester() *downloadTester { return tester } -func (dl *downloadTester) setWhitelist(w ChainValidator) { +func (dl *downloadTester) setWhitelist(w ethereum.ChainValidator) { dl.downloader.ChainValidator = w } @@ -1416,9 +1416,9 @@ func newWhitelistFake(validate func(count int) (bool, error)) *whitelistFake { return &whitelistFake{0, validate} } -// IsValidChain is the mock function which the downloader will use to validate the chain +// IsValidPeer is the mock function which the downloader will use to validate the chain // to be received from a peer. -func (w *whitelistFake) IsValidChain(_ *types.Header, _ func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) { +func (w *whitelistFake) IsValidPeer(_ *types.Header, _ func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) { defer func() { w.count++ }() @@ -1426,13 +1426,18 @@ func (w *whitelistFake) IsValidChain(_ *types.Header, _ func(number uint64, amou return w.validate(w.count) } +func (w *whitelistFake) IsValidChain(current *types.Header, headers []*types.Header) bool { + return true +} func (w *whitelistFake) ProcessCheckpoint(_ uint64, _ common.Hash) {} func (w *whitelistFake) GetCheckpointWhitelist() map[uint64]common.Hash { return nil } - func (w *whitelistFake) PurgeCheckpointWhitelist() {} +func (w *whitelistFake) GetCheckpoints(current, sidechainHeader *types.Header, sidechainCheckpoints []*types.Header) (map[uint64]*types.Header, error) { + return map[uint64]*types.Header{}, nil +} // TestFakedSyncProgress66WhitelistMismatch tests if in case of whitelisted // checkpoint mismatch with opposite peer, the sync should fail. diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 8b873343ca..cd4d9e6550 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -214,7 +214,7 @@ func newTestBlockchain(blocks []*types.Block) *core.BlockChain { db := rawdb.NewMemoryDatabase() core.GenesisBlockForTesting(db, testAddress, big.NewInt(1000000000000000)) - chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if err != nil { panic(err) } diff --git a/eth/downloader/whitelist/service.go b/eth/downloader/whitelist/service.go index 7036f24a8f..0e905cce28 100644 --- a/eth/downloader/whitelist/service.go +++ b/eth/downloader/whitelist/service.go @@ -15,7 +15,8 @@ type Service struct { m sync.Mutex checkpointWhitelist map[uint64]common.Hash // Checkpoint whitelist, populated by reaching out to heimdall checkpointOrder []uint64 // Checkpoint order, populated by reaching out to heimdall - maxCapacity uint + maxCapacity uint // Max capacity of the whitelist + checkpointInterval uint64 // Checkpoint interval, until which we can allow importing } func NewService(maxCapacity uint) *Service { @@ -23,6 +24,7 @@ func NewService(maxCapacity uint) *Service { checkpointWhitelist: make(map[uint64]common.Hash), checkpointOrder: []uint64{}, maxCapacity: maxCapacity, + checkpointInterval: 256, // TODO: make it configurable through params? } } @@ -31,9 +33,9 @@ var ( ErrNoRemoteCheckoint = errors.New("remote peer doesn't have a checkoint") ) -// IsValidChain checks if the chain we're about to receive from this peer is valid or not +// IsValidPeer checks if the chain we're about to receive from a peer is valid or not // in terms of reorgs. We won't reorg beyond the last bor checkpoint submitted to mainchain. -func (w *Service) IsValidChain(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) { +func (w *Service) IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) { // We want to validate the chain by comparing the last checkpointed block // we're storing in `checkpointWhitelist` with the peer's block. // @@ -70,6 +72,84 @@ func (w *Service) IsValidChain(remoteHeader *types.Header, fetchHeadersByNumber return false, ErrCheckpointMismatch } +// IsValidChain checks the validity of chain by comparing it +// against the local checkpoint entries +func (w *Service) IsValidChain(currentHeader *types.Header, chain []*types.Header) bool { + // Check if we have checkpoints to validate incoming chain in memory + if len(w.checkpointWhitelist) == 0 { + // We don't have any entries, no additional validation will be possible + return true + } + + // Return if we've received empty chain + if len(chain) == 0 { + return false + } + + var ( + oldestCheckpointNumber uint64 = w.checkpointOrder[0] + current uint64 = currentHeader.Number.Uint64() + ) + + // Check if we have whitelist entries in required range + if chain[len(chain)-1].Number.Uint64() < oldestCheckpointNumber { + // We have future whitelisted entries, so no additional validation will be possible + // This case will occur when bor is in middle of sync, but heimdall is ahead/fully synced. + return true + } + + // Split the chain into past and future chain + pastChain, futureChain := splitChain(current, chain) + + // Add an offset to future chain if it's not in continuity + offset := 0 + if len(futureChain) != 0 { + offset += int(futureChain[0].Number.Uint64()-currentHeader.Number.Uint64()) - 1 + } + + // Don't accept future chain of unacceptable length (from current block) + if len(futureChain)+offset > int(w.checkpointInterval) { + return false + } + + // Iterate over the chain and validate against the last checkpoint + // It will handle all cases where the incoming chain has atleast one checkpoint + for i := len(pastChain) - 1; i >= 0; i-- { + if _, ok := w.checkpointWhitelist[pastChain[i].Number.Uint64()]; ok { + return pastChain[i].Hash() == w.checkpointWhitelist[pastChain[i].Number.Uint64()] + } + } + + return true +} + +func splitChain(current uint64, chain []*types.Header) ([]*types.Header, []*types.Header) { + var ( + pastChain []*types.Header + futureChain []*types.Header + first uint64 = chain[0].Number.Uint64() + last uint64 = chain[len(chain)-1].Number.Uint64() + ) + + if current >= first { + if len(chain) == 1 || current >= last { + pastChain = chain + } else { + pastChain = chain[:current-first+1] + } + } + + if current < last { + if len(chain) == 1 || current < first { + futureChain = chain + } else { + futureChain = chain[current-first+1:] + } + } + + return pastChain, futureChain +} + func (w *Service) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) { w.m.Lock() defer w.m.Unlock() @@ -116,7 +196,7 @@ func (w *Service) dequeueCheckpointWhitelist() { log.Debug("Dequeing checkpoint whitelist", "block number", w.checkpointOrder[0], "block hash", w.checkpointWhitelist[w.checkpointOrder[0]]) delete(w.checkpointWhitelist, w.checkpointOrder[0]) - w.checkpointOrder = w.checkpointOrder[1:] + w.checkpointOrder = w.checkpointOrder[1:] // fixme: this slice is growing infinitely and never will be released. also a panic is possible if the last element is going to be removed } } diff --git a/eth/downloader/whitelist/service_test.go b/eth/downloader/whitelist/service_test.go index ca202cc3ad..c21490d125 100644 --- a/eth/downloader/whitelist/service_test.go +++ b/eth/downloader/whitelist/service_test.go @@ -2,21 +2,26 @@ package whitelist import ( "errors" + "fmt" "math/big" + "reflect" + "sort" "testing" + "time" - "gotest.tools/assert" + "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) // NewMockService creates a new mock whitelist service -func NewMockService(maxCapacity uint) *Service { +func NewMockService(maxCapacity uint, checkpointInterval uint64) *Service { return &Service{ checkpointWhitelist: make(map[uint64]common.Hash), checkpointOrder: []uint64{}, maxCapacity: maxCapacity, + checkpointInterval: checkpointInterval, } } @@ -24,34 +29,34 @@ func NewMockService(maxCapacity uint) *Service { func TestWhitelistCheckpoint(t *testing.T) { t.Parallel() - s := NewMockService(10) + s := NewMockService(10, 10) for i := 0; i < 10; i++ { s.enqueueCheckpointWhitelist(uint64(i), common.Hash{}) } - assert.Equal(t, s.length(), 10, "expected 10 items in whitelist") + require.Equal(t, s.length(), 10, "expected 10 items in whitelist") s.enqueueCheckpointWhitelist(11, common.Hash{}) s.dequeueCheckpointWhitelist() - assert.Equal(t, s.length(), 10, "expected 10 items in whitelist") + require.Equal(t, s.length(), 10, "expected 10 items in whitelist") } -// TestIsValidChain checks che IsValidChain function in isolation +// TestIsValidPeer checks the IsValidPeer function in isolation // for different cases by providing a mock fetchHeadersByNumber function -func TestIsValidChain(t *testing.T) { +func TestIsValidPeer(t *testing.T) { t.Parallel() - s := NewMockService(10) + s := NewMockService(10, 10) // case1: no checkpoint whitelist, should consider the chain as valid - res, err := s.IsValidChain(nil, nil) - assert.NilError(t, err, "expected no error") - assert.Equal(t, res, true, "expected chain to be valid") + res, err := s.IsValidPeer(nil, nil) + require.NoError(t, err, "expected no error") + require.Equal(t, res, true, "expected chain to be valid") // add checkpoint entries and mock fetchHeadersByNumber function s.ProcessCheckpoint(uint64(0), common.Hash{}) s.ProcessCheckpoint(uint64(1), common.Hash{}) - assert.Equal(t, s.length(), 2, "expected 2 items in whitelist") + require.Equal(t, s.length(), 2, "expected 2 items in whitelist") // create a false function, returning absolutely nothing falseFetchHeadersByNumber := func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error) { @@ -60,7 +65,7 @@ func TestIsValidChain(t *testing.T) { // case2: false fetchHeadersByNumber function provided, should consider the chain as invalid // and throw `ErrNoRemoteCheckoint` error - res, err = s.IsValidChain(nil, falseFetchHeadersByNumber) + res, err = s.IsValidPeer(nil, falseFetchHeadersByNumber) if err == nil { t.Fatal("expected error, got nil") } @@ -69,7 +74,7 @@ func TestIsValidChain(t *testing.T) { t.Fatalf("expected error ErrNoRemoteCheckoint, got %v", err) } - assert.Equal(t, res, false, "expected chain to be invalid") + require.Equal(t, res, false, "expected chain to be invalid") // case3: correct fetchHeadersByNumber function provided, should consider the chain as valid // create a mock function, returning a the required header @@ -91,17 +96,316 @@ func TestIsValidChain(t *testing.T) { } } - res, err = s.IsValidChain(nil, fetchHeadersByNumber) - assert.NilError(t, err, "expected no error") - assert.Equal(t, res, true, "expected chain to be valid") + res, err = s.IsValidPeer(nil, fetchHeadersByNumber) + require.NoError(t, err, "expected no error") + require.Equal(t, res, true, "expected chain to be valid") // add one more checkpoint whitelist entry s.ProcessCheckpoint(uint64(2), common.Hash{}) - assert.Equal(t, s.length(), 3, "expected 3 items in whitelist") + require.Equal(t, s.length(), 3, "expected 3 items in whitelist") // case4: correct fetchHeadersByNumber function provided with wrong header // for block number 2. Should consider the chain as invalid and throw an error - res, err = s.IsValidChain(nil, fetchHeadersByNumber) - assert.Equal(t, err, ErrCheckpointMismatch, "expected checkpoint mismatch error") - assert.Equal(t, res, false, "expected chain to be invalid") + res, err = s.IsValidPeer(nil, fetchHeadersByNumber) + require.Equal(t, err, ErrCheckpointMismatch, "expected checkpoint mismatch error") + require.Equal(t, res, false, "expected chain to be invalid") +} + +// TestIsValidChain checks the IsValidChain function in isolation +// for different cases by providing a mock current header and chain +func TestIsValidChain(t *testing.T) { + t.Parallel() + + s := NewMockService(10, 10) + chainA := createMockChain(1, 20) // A1->A2...A19->A20 + // case1: no checkpoint whitelist, should consider the chain as valid + res := s.IsValidChain(nil, chainA) + require.Equal(t, res, true, "expected chain to be valid") + + tempChain := createMockChain(21, 22) // A21->A22 + + // add mock checkpoint entries + s.ProcessCheckpoint(tempChain[0].Number.Uint64(), tempChain[0].Hash()) + s.ProcessCheckpoint(tempChain[1].Number.Uint64(), tempChain[1].Hash()) + + require.Equal(t, s.length(), 2, "expected 2 items in whitelist") + + // case2: We're behind the oldest whitelisted block entry, should consider + // the chain as valid as we're still far behind the latest blocks + res = s.IsValidChain(chainA[len(chainA)-1], chainA) + require.Equal(t, res, true, "expected chain to be valid") + + // Clear checkpoint whitelist and add blocks A5 and A15 in whitelist + s.PurgeCheckpointWhitelist() + s.ProcessCheckpoint(chainA[5].Number.Uint64(), chainA[5].Hash()) + s.ProcessCheckpoint(chainA[15].Number.Uint64(), chainA[15].Hash()) + + require.Equal(t, s.length(), 2, "expected 2 items in whitelist") + + // case3: Try importing a past chain having valid checkpoint, should + // consider the chain as valid + res = s.IsValidChain(chainA[len(chainA)-1], chainA) + require.Equal(t, res, true, "expected chain to be valid") + + // Clear checkpoint whitelist and mock blocks in whitelist + tempChain = createMockChain(20, 20) // A20 + + s.PurgeCheckpointWhitelist() + s.ProcessCheckpoint(tempChain[0].Number.Uint64(), tempChain[0].Hash()) + + require.Equal(t, s.length(), 1, "expected 1 items in whitelist") + + // case4: Try importing a past chain having invalid checkpoint + res = s.IsValidChain(chainA[len(chainA)-1], chainA) + require.Equal(t, res, false, "expected chain to be invalid") + + // create a future chain to be imported of length <= `checkpointInterval` + chainB := createMockChain(21, 30) // B21->B22...B29->B30 + + // case5: Try importing a future chain of acceptable length + res = s.IsValidChain(chainA[len(chainA)-1], chainB) + require.Equal(t, res, true, "expected chain to be valid") + + // create a future chain to be imported of length > `checkpointInterval` + chainB = createMockChain(21, 40) // C21->C22...C39->C40 + + // case5: Try importing a future chain of unacceptable length + res = s.IsValidChain(chainA[len(chainA)-1], chainB) + require.Equal(t, res, false, "expected chain to be invalid") +} + +func TestSplitChain(t *testing.T) { + t.Parallel() + + type Result struct { + pastStart uint64 + pastEnd uint64 + futureStart uint64 + futureEnd uint64 + pastLength int + futureLength int + } + + // Current chain is at block: X + // Incoming chain is represented as [N, M] + testCases := []struct { + name string + current uint64 + chain []*types.Header + result Result + }{ + {name: "X = 10, N = 11, M = 20", current: uint64(10), chain: createMockChain(11, 20), result: Result{futureStart: 11, futureEnd: 20, futureLength: 10}}, + {name: "X = 10, N = 13, M = 20", current: uint64(10), chain: createMockChain(13, 20), result: Result{futureStart: 13, futureEnd: 20, futureLength: 8}}, + {name: "X = 10, N = 2, M = 10", current: uint64(10), chain: createMockChain(2, 10), result: Result{pastStart: 2, pastEnd: 10, pastLength: 9}}, + {name: "X = 10, N = 2, M = 9", current: uint64(10), chain: createMockChain(2, 9), result: Result{pastStart: 2, pastEnd: 9, pastLength: 8}}, + {name: "X = 10, N = 2, M = 8", current: uint64(10), chain: createMockChain(2, 8), result: Result{pastStart: 2, pastEnd: 8, pastLength: 7}}, + {name: "X = 10, N = 5, M = 15", current: uint64(10), chain: createMockChain(5, 15), result: Result{pastStart: 5, pastEnd: 10, pastLength: 6, futureStart: 11, futureEnd: 15, futureLength: 5}}, + {name: "X = 10, N = 10, M = 20", current: uint64(10), chain: createMockChain(10, 20), result: Result{pastStart: 10, pastEnd: 10, pastLength: 1, futureStart: 11, futureEnd: 20, futureLength: 10}}, + } + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + past, future := splitChain(tc.current, tc.chain) + require.Equal(t, len(past), tc.result.pastLength) + require.Equal(t, len(future), tc.result.futureLength) + + if len(past) > 0 { + // Check if we have expected block/s + require.Equal(t, past[0].Number.Uint64(), tc.result.pastStart) + require.Equal(t, past[len(past)-1].Number.Uint64(), tc.result.pastEnd) + } + + if len(future) > 0 { + // Check if we have expected block/s + require.Equal(t, future[0].Number.Uint64(), tc.result.futureStart) + require.Equal(t, future[len(future)-1].Number.Uint64(), tc.result.futureEnd) + } + }) + } +} + +//nolint:gocognit +func TestSplitChainProperties(t *testing.T) { + t.Parallel() + + // Current chain is at block: X + // Incoming chain is represented as [N, M] + + currentChain := []int{0, 1, 2, 3, 10, 100} // blocks starting from genesis + blockDiffs := []int{0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 90, 100, 101, 102} + + caseParams := make(map[int]map[int]map[int]struct{}) // X -> N -> M + + for _, current := range currentChain { + // past cases only + past to current + for _, diff := range blockDiffs { + from := current - diff + + // use int type for everything to not care about underflow + if from < 0 { + continue + } + + for _, diff := range blockDiffs { + to := current - diff + + if to >= from { + addTestCaseParams(caseParams, current, from, to) + } + } + } + + // future only + current to future + for _, diff := range blockDiffs { + from := current + diff + + if from < 0 { + continue + } + + for _, diff := range blockDiffs { + to := current + diff + + if to >= from { + addTestCaseParams(caseParams, current, from, to) + } + } + } + + // past-current-future + for _, diff := range blockDiffs { + from := current - diff + + if from < 0 { + continue + } + + for _, diff := range blockDiffs { + to := current + diff + + if to >= from { + addTestCaseParams(caseParams, current, from, to) + } + } + } + } + + type testCase struct { + current int + remoteStart int + remoteEnd int + } + + var ts []testCase + + // X -> N -> M + for x, nm := range caseParams { + for n, mMap := range nm { + for m := range mMap { + ts = append(ts, testCase{x, n, m}) + } + } + } + + //nolint:paralleltest + for i, tc := range ts { + tc := tc + + name := fmt.Sprintf("test case: index = %d, X = %d, N = %d, M = %d", i, tc.current, tc.remoteStart, tc.remoteEnd) + + t.Run(name, func(t *testing.T) { + t.Parallel() + + chain := createMockChain(uint64(tc.remoteStart), uint64(tc.remoteEnd)) + + past, future := splitChain(uint64(tc.current), chain) + + // properties + if len(past) > 0 { + // Check if the chain is ordered + isOrdered := sort.SliceIsSorted(past, func(i, j int) bool { + return past[i].Number.Uint64() < past[j].Number.Uint64() + }) + + require.True(t, isOrdered, "an ordered past chain expected: %v", past) + + isSequential := sort.SliceIsSorted(past, func(i, j int) bool { + return past[i].Number.Uint64() == past[j].Number.Uint64()-1 + }) + + require.True(t, isSequential, "a sequential past chain expected: %v", past) + + // Check if current block >= past chain's last block + require.Equal(t, past[len(past)-1].Number.Uint64() <= uint64(tc.current), true) + } + + if len(future) > 0 { + // Check if the chain is ordered + isOrdered := sort.SliceIsSorted(future, func(i, j int) bool { + return future[i].Number.Uint64() < future[j].Number.Uint64() + }) + + require.True(t, isOrdered, "an ordered future chain expected: %v", future) + + isSequential := sort.SliceIsSorted(future, func(i, j int) bool { + return future[i].Number.Uint64() == future[j].Number.Uint64()-1 + }) + + require.True(t, isSequential, "a sequential future chain expected: %v", future) + + // Check if future chain's first block > current block + require.Equal(t, future[len(future)-1].Number.Uint64() > uint64(tc.current), true) + } + + // Check if both chains are continuous + if len(past) > 0 && len(future) > 0 { + require.Equal(t, past[len(past)-1].Number.Uint64(), future[0].Number.Uint64()-1) + } + + // Check if we get the original chain on appending both + gotChain := append(past, future...) + require.Equal(t, reflect.DeepEqual(gotChain, chain), true) + }) + } +} + +// createMockChain returns a chain with dummy headers +// starting from `start` to `end` (inclusive) +func createMockChain(start, end uint64) []*types.Header { + var ( + i uint64 + idx uint64 + chain []*types.Header = make([]*types.Header, end-start+1) + ) + + for i = start; i <= end; i++ { + header := &types.Header{ + Number: big.NewInt(int64(i)), + Time: uint64(time.Now().UnixMicro()) + i, + } + chain[idx] = header + idx++ + } + + return chain +} + +// mXNM should be initialized +func addTestCaseParams(mXNM map[int]map[int]map[int]struct{}, x, n, m int) { + //nolint:ineffassign + mNM, ok := mXNM[x] + if !ok { + mNM = make(map[int]map[int]struct{}) + mXNM[x] = mNM + } + + //nolint:ineffassign + _, ok = mNM[n] + if !ok { + mM := make(map[int]struct{}) + mNM[n] = mM + } + + mXNM[x][n][m] = struct{}{} } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 091600d8b5..c9272758ab 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -30,8 +30,9 @@ import ( "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/bor" "github.com/ethereum/go-ethereum/consensus/bor/contract" - "github.com/ethereum/go-ethereum/consensus/bor/heimdall" + "github.com/ethereum/go-ethereum/consensus/bor/heimdall" //nolint:typecheck "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" + "github.com/ethereum/go-ethereum/consensus/bor/heimdallgrpc" "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" @@ -175,6 +176,7 @@ type Config struct { TrieTimeout time.Duration SnapshotCache int Preimages bool + TriesInMemory uint64 // Mining options Miner miner.Config @@ -216,6 +218,9 @@ type Config struct { // No heimdall service WithoutHeimdall bool + // Address to connect to Heimdall gRPC server + HeimdallgRPCAddress string + // Bor logs flag BorLogs bool @@ -246,7 +251,14 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, et if ethConfig.WithoutHeimdall { return bor.New(chainConfig, db, blockchainAPI, spanner, nil, genesisContractsClient) } else { - return bor.New(chainConfig, db, blockchainAPI, spanner, heimdall.NewHeimdallClient(ethConfig.HeimdallURL), genesisContractsClient) + var heimdallClient bor.IHeimdallClient + if ethConfig.HeimdallgRPCAddress != "" { + heimdallClient = heimdallgrpc.NewHeimdallGRPCClient(ethConfig.HeimdallgRPCAddress) + } else { + heimdallClient = heimdall.NewHeimdallClient(ethConfig.HeimdallURL) + } + + return bor.New(chainConfig, db, blockchainAPI, spanner, heimdallClient, genesisContractsClient) } } else { switch config.PowMode { diff --git a/eth/filters/IBackend.go b/eth/filters/IBackend.go new file mode 100644 index 0000000000..df844e82b9 --- /dev/null +++ b/eth/filters/IBackend.go @@ -0,0 +1,257 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ethereum/go-ethereum/eth/filters (interfaces: Backend) + +// Package filters is a generated GoMock package. +package filters + +import ( + context "context" + reflect "reflect" + + common "github.com/ethereum/go-ethereum/common" + core "github.com/ethereum/go-ethereum/core" + bloombits "github.com/ethereum/go-ethereum/core/bloombits" + types "github.com/ethereum/go-ethereum/core/types" + ethdb "github.com/ethereum/go-ethereum/ethdb" + event "github.com/ethereum/go-ethereum/event" + rpc "github.com/ethereum/go-ethereum/rpc" + gomock "github.com/golang/mock/gomock" +) + +// MockBackend is a mock of Backend interface. +type MockBackend struct { + ctrl *gomock.Controller + recorder *MockBackendMockRecorder +} + +// MockBackendMockRecorder is the mock recorder for MockBackend. +type MockBackendMockRecorder struct { + mock *MockBackend +} + +// NewMockBackend creates a new mock instance. +func NewMockBackend(ctrl *gomock.Controller) *MockBackend { + mock := &MockBackend{ctrl: ctrl} + mock.recorder = &MockBackendMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBackend) EXPECT() *MockBackendMockRecorder { + return m.recorder +} + +// BloomStatus mocks base method. +func (m *MockBackend) BloomStatus() (uint64, uint64) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BloomStatus") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(uint64) + return ret0, ret1 +} + +// BloomStatus indicates an expected call of BloomStatus. +func (mr *MockBackendMockRecorder) BloomStatus() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BloomStatus", reflect.TypeOf((*MockBackend)(nil).BloomStatus)) +} + +// ChainDb mocks base method. +func (m *MockBackend) ChainDb() ethdb.Database { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ChainDb") + ret0, _ := ret[0].(ethdb.Database) + return ret0 +} + +// ChainDb indicates an expected call of ChainDb. +func (mr *MockBackendMockRecorder) ChainDb() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainDb", reflect.TypeOf((*MockBackend)(nil).ChainDb)) +} + +// GetBorBlockLogs mocks base method. +func (m *MockBackend) GetBorBlockLogs(arg0 context.Context, arg1 common.Hash) ([]*types.Log, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBorBlockLogs", arg0, arg1) + ret0, _ := ret[0].([]*types.Log) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBorBlockLogs indicates an expected call of GetBorBlockLogs. +func (mr *MockBackendMockRecorder) GetBorBlockLogs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockLogs", reflect.TypeOf((*MockBackend)(nil).GetBorBlockLogs), arg0, arg1) +} + +// GetBorBlockReceipt mocks base method. +func (m *MockBackend) GetBorBlockReceipt(arg0 context.Context, arg1 common.Hash) (*types.Receipt, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBorBlockReceipt", arg0, arg1) + ret0, _ := ret[0].(*types.Receipt) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBorBlockReceipt indicates an expected call of GetBorBlockReceipt. +func (mr *MockBackendMockRecorder) GetBorBlockReceipt(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBorBlockReceipt", reflect.TypeOf((*MockBackend)(nil).GetBorBlockReceipt), arg0, arg1) +} + +// GetLogs mocks base method. +func (m *MockBackend) GetLogs(arg0 context.Context, arg1 common.Hash) ([][]*types.Log, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLogs", arg0, arg1) + ret0, _ := ret[0].([][]*types.Log) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLogs indicates an expected call of GetLogs. +func (mr *MockBackendMockRecorder) GetLogs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogs", reflect.TypeOf((*MockBackend)(nil).GetLogs), arg0, arg1) +} + +// GetReceipts mocks base method. +func (m *MockBackend) GetReceipts(arg0 context.Context, arg1 common.Hash) (types.Receipts, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetReceipts", arg0, arg1) + ret0, _ := ret[0].(types.Receipts) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetReceipts indicates an expected call of GetReceipts. +func (mr *MockBackendMockRecorder) GetReceipts(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReceipts", reflect.TypeOf((*MockBackend)(nil).GetReceipts), arg0, arg1) +} + +// HeaderByHash mocks base method. +func (m *MockBackend) HeaderByHash(arg0 context.Context, arg1 common.Hash) (*types.Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HeaderByHash", arg0, arg1) + ret0, _ := ret[0].(*types.Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HeaderByHash indicates an expected call of HeaderByHash. +func (mr *MockBackendMockRecorder) HeaderByHash(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByHash", reflect.TypeOf((*MockBackend)(nil).HeaderByHash), arg0, arg1) +} + +// HeaderByNumber mocks base method. +func (m *MockBackend) HeaderByNumber(arg0 context.Context, arg1 rpc.BlockNumber) (*types.Header, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HeaderByNumber", arg0, arg1) + ret0, _ := ret[0].(*types.Header) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HeaderByNumber indicates an expected call of HeaderByNumber. +func (mr *MockBackendMockRecorder) HeaderByNumber(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeaderByNumber", reflect.TypeOf((*MockBackend)(nil).HeaderByNumber), arg0, arg1) +} + +// ServiceFilter mocks base method. +func (m *MockBackend) ServiceFilter(arg0 context.Context, arg1 *bloombits.MatcherSession) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "ServiceFilter", arg0, arg1) +} + +// ServiceFilter indicates an expected call of ServiceFilter. +func (mr *MockBackendMockRecorder) ServiceFilter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ServiceFilter", reflect.TypeOf((*MockBackend)(nil).ServiceFilter), arg0, arg1) +} + +// SubscribeChainEvent mocks base method. +func (m *MockBackend) SubscribeChainEvent(arg0 chan<- core.ChainEvent) event.Subscription { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeChainEvent", arg0) + ret0, _ := ret[0].(event.Subscription) + return ret0 +} + +// SubscribeChainEvent indicates an expected call of SubscribeChainEvent. +func (mr *MockBackendMockRecorder) SubscribeChainEvent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeChainEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeChainEvent), arg0) +} + +// SubscribeLogsEvent mocks base method. +func (m *MockBackend) SubscribeLogsEvent(arg0 chan<- []*types.Log) event.Subscription { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeLogsEvent", arg0) + ret0, _ := ret[0].(event.Subscription) + return ret0 +} + +// SubscribeLogsEvent indicates an expected call of SubscribeLogsEvent. +func (mr *MockBackendMockRecorder) SubscribeLogsEvent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeLogsEvent), arg0) +} + +// SubscribeNewTxsEvent mocks base method. +func (m *MockBackend) SubscribeNewTxsEvent(arg0 chan<- core.NewTxsEvent) event.Subscription { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeNewTxsEvent", arg0) + ret0, _ := ret[0].(event.Subscription) + return ret0 +} + +// SubscribeNewTxsEvent indicates an expected call of SubscribeNewTxsEvent. +func (mr *MockBackendMockRecorder) SubscribeNewTxsEvent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeNewTxsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeNewTxsEvent), arg0) +} + +// SubscribePendingLogsEvent mocks base method. +func (m *MockBackend) SubscribePendingLogsEvent(arg0 chan<- []*types.Log) event.Subscription { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribePendingLogsEvent", arg0) + ret0, _ := ret[0].(event.Subscription) + return ret0 +} + +// SubscribePendingLogsEvent indicates an expected call of SubscribePendingLogsEvent. +func (mr *MockBackendMockRecorder) SubscribePendingLogsEvent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribePendingLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribePendingLogsEvent), arg0) +} + +// SubscribeRemovedLogsEvent mocks base method. +func (m *MockBackend) SubscribeRemovedLogsEvent(arg0 chan<- core.RemovedLogsEvent) event.Subscription { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeRemovedLogsEvent", arg0) + ret0, _ := ret[0].(event.Subscription) + return ret0 +} + +// SubscribeRemovedLogsEvent indicates an expected call of SubscribeRemovedLogsEvent. +func (mr *MockBackendMockRecorder) SubscribeRemovedLogsEvent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeRemovedLogsEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeRemovedLogsEvent), arg0) +} + +// SubscribeStateSyncEvent mocks base method. +func (m *MockBackend) SubscribeStateSyncEvent(arg0 chan<- core.StateSyncEvent) event.Subscription { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SubscribeStateSyncEvent", arg0) + ret0, _ := ret[0].(event.Subscription) + return ret0 +} + +// SubscribeStateSyncEvent indicates an expected call of SubscribeStateSyncEvent. +func (mr *MockBackendMockRecorder) SubscribeStateSyncEvent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeStateSyncEvent", reflect.TypeOf((*MockBackend)(nil).SubscribeStateSyncEvent), arg0) +} diff --git a/eth/filters/IDatabase.go b/eth/filters/IDatabase.go new file mode 100644 index 0000000000..fd0824b60d --- /dev/null +++ b/eth/filters/IDatabase.go @@ -0,0 +1,368 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ethereum/go-ethereum/ethdb (interfaces: Database) + +// Package filters is a generated GoMock package. +package filters + +import ( + reflect "reflect" + + ethdb "github.com/ethereum/go-ethereum/ethdb" + gomock "github.com/golang/mock/gomock" +) + +// MockDatabase is a mock of Database interface. +type MockDatabase struct { + ctrl *gomock.Controller + recorder *MockDatabaseMockRecorder +} + +// MockDatabaseMockRecorder is the mock recorder for MockDatabase. +type MockDatabaseMockRecorder struct { + mock *MockDatabase +} + +// NewMockDatabase creates a new mock instance. +func NewMockDatabase(ctrl *gomock.Controller) *MockDatabase { + mock := &MockDatabase{ctrl: ctrl} + mock.recorder = &MockDatabaseMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDatabase) EXPECT() *MockDatabaseMockRecorder { + return m.recorder +} + +// Ancient mocks base method. +func (m *MockDatabase) Ancient(arg0 string, arg1 uint64) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Ancient", arg0, arg1) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Ancient indicates an expected call of Ancient. +func (mr *MockDatabaseMockRecorder) Ancient(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ancient", reflect.TypeOf((*MockDatabase)(nil).Ancient), arg0, arg1) +} + +// AncientRange mocks base method. +func (m *MockDatabase) AncientRange(arg0 string, arg1, arg2, arg3 uint64) ([][]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AncientRange", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([][]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AncientRange indicates an expected call of AncientRange. +func (mr *MockDatabaseMockRecorder) AncientRange(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AncientRange", reflect.TypeOf((*MockDatabase)(nil).AncientRange), arg0, arg1, arg2, arg3) +} + +// AncientSize mocks base method. +func (m *MockDatabase) AncientSize(arg0 string) (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AncientSize", arg0) + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AncientSize indicates an expected call of AncientSize. +func (mr *MockDatabaseMockRecorder) AncientSize(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AncientSize", reflect.TypeOf((*MockDatabase)(nil).AncientSize), arg0) +} + +// Ancients mocks base method. +func (m *MockDatabase) Ancients() (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Ancients") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Ancients indicates an expected call of Ancients. +func (mr *MockDatabaseMockRecorder) Ancients() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ancients", reflect.TypeOf((*MockDatabase)(nil).Ancients)) +} + +// Close mocks base method. +func (m *MockDatabase) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockDatabaseMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockDatabase)(nil).Close)) +} + +// Compact mocks base method. +func (m *MockDatabase) Compact(arg0, arg1 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Compact", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Compact indicates an expected call of Compact. +func (mr *MockDatabaseMockRecorder) Compact(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Compact", reflect.TypeOf((*MockDatabase)(nil).Compact), arg0, arg1) +} + +// Delete mocks base method. +func (m *MockDatabase) Delete(arg0 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockDatabaseMockRecorder) Delete(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDatabase)(nil).Delete), arg0) +} + +// Get mocks base method. +func (m *MockDatabase) Get(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockDatabaseMockRecorder) Get(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockDatabase)(nil).Get), arg0) +} + +// Has mocks base method. +func (m *MockDatabase) Has(arg0 []byte) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Has", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Has indicates an expected call of Has. +func (mr *MockDatabaseMockRecorder) Has(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Has", reflect.TypeOf((*MockDatabase)(nil).Has), arg0) +} + +// HasAncient mocks base method. +func (m *MockDatabase) HasAncient(arg0 string, arg1 uint64) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasAncient", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HasAncient indicates an expected call of HasAncient. +func (mr *MockDatabaseMockRecorder) HasAncient(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasAncient", reflect.TypeOf((*MockDatabase)(nil).HasAncient), arg0, arg1) +} + +// MigrateTable mocks base method. +func (m *MockDatabase) MigrateTable(arg0 string, arg1 func([]byte) ([]byte, error)) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MigrateTable", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// MigrateTable indicates an expected call of MigrateTable. +func (mr *MockDatabaseMockRecorder) MigrateTable(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MigrateTable", reflect.TypeOf((*MockDatabase)(nil).MigrateTable), arg0, arg1) +} + +// ModifyAncients mocks base method. +func (m *MockDatabase) ModifyAncients(arg0 func(ethdb.AncientWriteOp) error) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ModifyAncients", arg0) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ModifyAncients indicates an expected call of ModifyAncients. +func (mr *MockDatabaseMockRecorder) ModifyAncients(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyAncients", reflect.TypeOf((*MockDatabase)(nil).ModifyAncients), arg0) +} + +// NewBatch mocks base method. +func (m *MockDatabase) NewBatch() ethdb.Batch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewBatch") + ret0, _ := ret[0].(ethdb.Batch) + return ret0 +} + +// NewBatch indicates an expected call of NewBatch. +func (mr *MockDatabaseMockRecorder) NewBatch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBatch", reflect.TypeOf((*MockDatabase)(nil).NewBatch)) +} + +// NewBatchWithSize mocks base method. +func (m *MockDatabase) NewBatchWithSize(arg0 int) ethdb.Batch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewBatchWithSize", arg0) + ret0, _ := ret[0].(ethdb.Batch) + return ret0 +} + +// NewBatchWithSize indicates an expected call of NewBatchWithSize. +func (mr *MockDatabaseMockRecorder) NewBatchWithSize(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBatchWithSize", reflect.TypeOf((*MockDatabase)(nil).NewBatchWithSize), arg0) +} + +// NewIterator mocks base method. +func (m *MockDatabase) NewIterator(arg0, arg1 []byte) ethdb.Iterator { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewIterator", arg0, arg1) + ret0, _ := ret[0].(ethdb.Iterator) + return ret0 +} + +// NewIterator indicates an expected call of NewIterator. +func (mr *MockDatabaseMockRecorder) NewIterator(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewIterator", reflect.TypeOf((*MockDatabase)(nil).NewIterator), arg0, arg1) +} + +// NewSnapshot mocks base method. +func (m *MockDatabase) NewSnapshot() (ethdb.Snapshot, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewSnapshot") + ret0, _ := ret[0].(ethdb.Snapshot) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// NewSnapshot indicates an expected call of NewSnapshot. +func (mr *MockDatabaseMockRecorder) NewSnapshot() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewSnapshot", reflect.TypeOf((*MockDatabase)(nil).NewSnapshot)) +} + +// Put mocks base method. +func (m *MockDatabase) Put(arg0, arg1 []byte) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Put", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Put indicates an expected call of Put. +func (mr *MockDatabaseMockRecorder) Put(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockDatabase)(nil).Put), arg0, arg1) +} + +// ReadAncients mocks base method. +func (m *MockDatabase) ReadAncients(arg0 func(ethdb.AncientReader) error) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadAncients", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// ReadAncients indicates an expected call of ReadAncients. +func (mr *MockDatabaseMockRecorder) ReadAncients(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadAncients", reflect.TypeOf((*MockDatabase)(nil).ReadAncients), arg0) +} + +// Stat mocks base method. +func (m *MockDatabase) Stat(arg0 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Stat", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Stat indicates an expected call of Stat. +func (mr *MockDatabaseMockRecorder) Stat(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockDatabase)(nil).Stat), arg0) +} + +// Sync mocks base method. +func (m *MockDatabase) Sync() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Sync") + ret0, _ := ret[0].(error) + return ret0 +} + +// Sync indicates an expected call of Sync. +func (mr *MockDatabaseMockRecorder) Sync() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sync", reflect.TypeOf((*MockDatabase)(nil).Sync)) +} + +// Tail mocks base method. +func (m *MockDatabase) Tail() (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Tail") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Tail indicates an expected call of Tail. +func (mr *MockDatabaseMockRecorder) Tail() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Tail", reflect.TypeOf((*MockDatabase)(nil).Tail)) +} + +// TruncateHead mocks base method. +func (m *MockDatabase) TruncateHead(arg0 uint64) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TruncateHead", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// TruncateHead indicates an expected call of TruncateHead. +func (mr *MockDatabaseMockRecorder) TruncateHead(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TruncateHead", reflect.TypeOf((*MockDatabase)(nil).TruncateHead), arg0) +} + +// TruncateTail mocks base method. +func (m *MockDatabase) TruncateTail(arg0 uint64) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TruncateTail", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// TruncateTail indicates an expected call of TruncateTail. +func (mr *MockDatabaseMockRecorder) TruncateTail(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TruncateTail", reflect.TypeOf((*MockDatabase)(nil).TruncateTail), arg0) +} diff --git a/eth/filters/api.go b/eth/filters/api.go index ce454ed265..ad24bf34dd 100644 --- a/eth/filters/api.go +++ b/eth/filters/api.go @@ -337,8 +337,7 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([ return nil, errors.New("No chain config found. Proper PublicFilterAPI initialization required") } - // get sprint from bor config - sprint := api.chainConfig.Bor.Sprint + borConfig := api.chainConfig.Bor var filter *Filter var borLogsFilter *BorBlockLogsFilter @@ -347,7 +346,7 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([ filter = NewBlockFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics) // Block bor filter if api.borLogs { - borLogsFilter = NewBorBlockLogsFilter(api.backend, sprint, *crit.BlockHash, crit.Addresses, crit.Topics) + borLogsFilter = NewBorBlockLogsFilter(api.backend, borConfig, *crit.BlockHash, crit.Addresses, crit.Topics) } } else { // Convert the RPC block numbers into internal representations @@ -363,7 +362,7 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([ filter = NewRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics) // Block bor filter if api.borLogs { - borLogsFilter = NewBorBlockLogsRangeFilter(api.backend, sprint, begin, end, crit.Addresses, crit.Topics) + borLogsFilter = NewBorBlockLogsRangeFilter(api.backend, borConfig, begin, end, crit.Addresses, crit.Topics) } } @@ -417,10 +416,20 @@ func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*ty return nil, fmt.Errorf("filter not found") } + borConfig := api.chainConfig.Bor + var filter *Filter + + var borLogsFilter *BorBlockLogsFilter + if f.crit.BlockHash != nil { // Block filter requested, construct a single-shot filter filter = NewBlockFilter(api.backend, *f.crit.BlockHash, f.crit.Addresses, f.crit.Topics) + + // Block bor filter + if api.borLogs { + borLogsFilter = NewBorBlockLogsFilter(api.backend, borConfig, *f.crit.BlockHash, f.crit.Addresses, f.crit.Topics) + } } else { // Convert the RPC block numbers into internal representations begin := rpc.LatestBlockNumber.Int64() @@ -433,12 +442,27 @@ func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*ty } // Construct the range filter filter = NewRangeFilter(api.backend, begin, end, f.crit.Addresses, f.crit.Topics) + + if api.borLogs { + borLogsFilter = NewBorBlockLogsRangeFilter(api.backend, borConfig, begin, end, f.crit.Addresses, f.crit.Topics) + } } // Run the filter and return all the logs logs, err := filter.Logs(ctx) if err != nil { return nil, err } + + if borLogsFilter != nil { + // Run the filter and return all the logs + borBlockLogs, err := borLogsFilter.Logs(ctx) + if err != nil { + return nil, err + } + + return returnLogs(types.MergeBorLogs(logs, borBlockLogs)), nil + } + return returnLogs(logs), nil } diff --git a/eth/filters/bench_test.go b/eth/filters/bench_test.go index 9632f4195f..e0eb972a32 100644 --- a/eth/filters/bench_test.go +++ b/eth/filters/bench_test.go @@ -122,13 +122,14 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) { b.Log("Running filter benchmarks...") start = time.Now() - var backend *testBackend + + var backend *TestBackend for i := 0; i < benchFilterCnt; i++ { if i%20 == 0 { db.Close() db, _ = rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false) - backend = &testBackend{db: db, sections: cnt} + backend = &TestBackend{DB: db, sections: cnt} } var addr common.Address addr[0] = byte(i) @@ -173,7 +174,7 @@ func BenchmarkNoBloomBits(b *testing.B) { b.Log("Running filter benchmarks...") start := time.Now() - backend := &testBackend{db: db} + backend := &TestBackend{DB: db} filter := NewRangeFilter(backend, 0, int64(*headNum), []common.Address{{}}, nil) filter.Logs(context.Background()) d := time.Since(start) diff --git a/eth/filters/bor_api.go b/eth/filters/bor_api.go index 517ff894f4..db13c95959 100644 --- a/eth/filters/bor_api.go +++ b/eth/filters/bor_api.go @@ -23,12 +23,12 @@ func (api *PublicFilterAPI) GetBorBlockLogs(ctx context.Context, crit FilterCrit } // get sprint from bor config - sprint := api.chainConfig.Bor.Sprint + borConfig := api.chainConfig.Bor var filter *BorBlockLogsFilter if crit.BlockHash != nil { // Block filter requested, construct a single-shot filter - filter = NewBorBlockLogsFilter(api.backend, sprint, *crit.BlockHash, crit.Addresses, crit.Topics) + filter = NewBorBlockLogsFilter(api.backend, borConfig, *crit.BlockHash, crit.Addresses, crit.Topics) } else { // Convert the RPC block numbers into internal representations begin := rpc.LatestBlockNumber.Int64() @@ -40,7 +40,7 @@ func (api *PublicFilterAPI) GetBorBlockLogs(ctx context.Context, crit FilterCrit end = crit.ToBlock.Int64() } // Construct the range filter - filter = NewBorBlockLogsRangeFilter(api.backend, sprint, begin, end, crit.Addresses, crit.Topics) + filter = NewBorBlockLogsRangeFilter(api.backend, borConfig, begin, end, crit.Addresses, crit.Topics) } // Run the filter and return all the logs @@ -59,8 +59,9 @@ func (api *PublicFilterAPI) NewDeposits(ctx context.Context, crit ethereum.State } rpcSub := notifier.CreateSubscription() + go func() { - stateSyncData := make(chan *types.StateSyncData) + stateSyncData := make(chan *types.StateSyncData, 10) stateSyncSub := api.events.SubscribeNewDeposits(stateSyncData) for { diff --git a/eth/filters/bor_filter.go b/eth/filters/bor_filter.go index 009f6cde2a..8590d79eb1 100644 --- a/eth/filters/bor_filter.go +++ b/eth/filters/bor_filter.go @@ -22,13 +22,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) // BorBlockLogsFilter can be used to retrieve and filter logs. type BorBlockLogsFilter struct { - backend Backend - sprint uint64 + backend Backend + borConfig *params.BorConfig db ethdb.Database addresses []common.Address @@ -40,9 +41,9 @@ type BorBlockLogsFilter struct { // NewBorBlockLogsRangeFilter creates a new filter which uses a bloom filter on blocks to // figure out whether a particular block is interesting or not. -func NewBorBlockLogsRangeFilter(backend Backend, sprint uint64, begin, end int64, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter { +func NewBorBlockLogsRangeFilter(backend Backend, borConfig *params.BorConfig, begin, end int64, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter { // Create a generic filter and convert it into a range filter - filter := newBorBlockLogsFilter(backend, sprint, addresses, topics) + filter := newBorBlockLogsFilter(backend, borConfig, addresses, topics) filter.begin = begin filter.end = end @@ -51,19 +52,19 @@ func NewBorBlockLogsRangeFilter(backend Backend, sprint uint64, begin, end int64 // NewBorBlockLogsFilter creates a new filter which directly inspects the contents of // a block to figure out whether it is interesting or not. -func NewBorBlockLogsFilter(backend Backend, sprint uint64, block common.Hash, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter { +func NewBorBlockLogsFilter(backend Backend, borConfig *params.BorConfig, block common.Hash, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter { // Create a generic filter and convert it into a block filter - filter := newBorBlockLogsFilter(backend, sprint, addresses, topics) + filter := newBorBlockLogsFilter(backend, borConfig, addresses, topics) filter.block = block return filter } // newBorBlockLogsFilter creates a generic filter that can either filter based on a block hash, // or based on range queries. The search criteria needs to be explicitly set. -func newBorBlockLogsFilter(backend Backend, sprint uint64, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter { +func newBorBlockLogsFilter(backend Backend, borConfig *params.BorConfig, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter { return &BorBlockLogsFilter{ backend: backend, - sprint: sprint, + borConfig: borConfig, addresses: addresses, topics: topics, db: backend.ChainDb(), @@ -94,7 +95,7 @@ func (f *BorBlockLogsFilter) Logs(ctx context.Context) ([]*types.Log, error) { } // adjust begin for sprint - f.begin = currentSprintEnd(f.sprint, f.begin) + f.begin = currentSprintEnd(f.borConfig.CalculateSprint(uint64(f.begin)), f.begin) end := f.end if f.end == -1 { @@ -110,7 +111,9 @@ func (f *BorBlockLogsFilter) Logs(ctx context.Context) ([]*types.Log, error) { func (f *BorBlockLogsFilter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) { var logs []*types.Log - for ; f.begin <= int64(end); f.begin = f.begin + 64 { + sprintLength := f.borConfig.CalculateSprint(uint64(f.begin)) + + for ; f.begin <= int64(end); f.begin = f.begin + int64(sprintLength) { header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin)) if header == nil || err != nil { return logs, err @@ -128,6 +131,7 @@ func (f *BorBlockLogsFilter) unindexedLogs(ctx context.Context, end uint64) ([]* return logs, err } logs = append(logs, found...) + sprintLength = f.borConfig.CalculateSprint(uint64(f.begin)) } return logs, nil } @@ -146,5 +150,5 @@ func currentSprintEnd(sprint uint64, n int64) int64 { return n } - return n + 64 - m + return n + int64(sprint) - m } diff --git a/eth/filters/bor_filter_system_test.go b/eth/filters/bor_filter_system_test.go deleted file mode 100644 index 05f05893d6..0000000000 --- a/eth/filters/bor_filter_system_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package filters - -import ( - "context" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/types" -) - -func (b *testBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { - number := rawdb.ReadHeaderNumber(b.db, hash) - if number == nil { - return nil, nil - } - - receipt := rawdb.ReadBorReceipt(b.db, hash, *number) - if receipt == nil { - return nil, nil - } - return receipt, nil -} - -func (b *testBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) { - receipt, err := b.GetBorBlockReceipt(ctx, hash) - if receipt == nil || err != nil { - return nil, nil - } - return receipt.Logs, nil -} diff --git a/eth/filters/bor_filter_test.go b/eth/filters/bor_filter_test.go new file mode 100644 index 0000000000..1848648beb --- /dev/null +++ b/eth/filters/bor_filter_test.go @@ -0,0 +1,158 @@ +package filters + +import ( + "context" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + types "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" + + gomock "github.com/golang/mock/gomock" +) + +var ( + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr = crypto.PubkeyToAddress(key1.PublicKey) +) + +func newTestHeader(blockNumber uint) *types.Header { + return &types.Header{ + Number: big.NewInt(int64(blockNumber)), + } +} + +func newTestReceipt(contractAddr common.Address, topicAddress common.Hash) *types.Receipt { + receipt := types.NewReceipt(nil, false, 0) + receipt.Logs = []*types.Log{ + { + Address: contractAddr, + Topics: []common.Hash{topicAddress}, + }, + } + + receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + + return receipt +} + +func (backend *MockBackend) expectBorReceiptsFromMock(hashes []*common.Hash) { + for _, h := range hashes { + if h == nil { + backend.EXPECT().GetBorBlockReceipt(gomock.Any(), gomock.Any()).Return(nil, nil) + continue + } + + backend.EXPECT().GetBorBlockReceipt(gomock.Any(), gomock.Any()).Return(newTestReceipt(addr, *h), nil) + } +} + +func TestBorFilters(t *testing.T) { + t.Parallel() + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + var ( + hash1 = common.BytesToHash([]byte("topic1")) + hash2 = common.BytesToHash([]byte("topic2")) + hash3 = common.BytesToHash([]byte("topic3")) + hash4 = common.BytesToHash([]byte("topic4")) + db = NewMockDatabase(ctrl) + + testBorConfig = params.TestChainConfig.Bor + ) + + backend := NewMockBackend(ctrl) + + // should return the following at all times + backend.EXPECT().ChainDb().Return(db).AnyTimes() + backend.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Return(newTestHeader(1), nil).AnyTimes() + + // Block 1 + backend.expectBorReceiptsFromMock([]*common.Hash{nil, &hash1, &hash2, &hash3, &hash4}) + + filter := NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, 18, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}}) + logs, err := filter.Logs(context.Background()) + + if err != nil { + t.Error(err) + } + + if len(logs) != 4 { + t.Error("expected 4 log, got", len(logs)) + } + + // Block 2 + backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash3}) + + filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 990, 999, []common.Address{addr}, [][]common.Hash{{hash3}}) + logs, _ = filter.Logs(context.Background()) + + if len(logs) != 1 { + t.Error("expected 1 log, got", len(logs)) + } + + if len(logs) > 0 && logs[0].Topics[0] != hash3 { + t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) + } + + // Block 3 + backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash2, &hash3}) + + filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 992, 1000, []common.Address{addr}, [][]common.Hash{{hash3}}) + logs, _ = filter.Logs(context.Background()) + + if len(logs) != 1 { + t.Error("expected 1 log, got", len(logs)) + } + + if len(logs) > 0 && logs[0].Topics[0] != hash3 { + t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) + } + + // Block 4 + backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash2, nil, &hash3}) + + filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 1, 16, []common.Address{addr}, [][]common.Hash{{hash1, hash2}}) + + logs, _ = filter.Logs(context.Background()) + + if len(logs) != 2 { + t.Error("expected 2 log, got", len(logs)) + } + + // Block 5 + backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash2, nil, &hash3, &hash4, nil}) + + failHash := common.BytesToHash([]byte("fail")) + filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, 20, nil, [][]common.Hash{{failHash}}) + + logs, _ = filter.Logs(context.Background()) + if len(logs) != 0 { + t.Error("expected 0 log, got", len(logs)) + } + + // Block 6 + backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash2, nil, &hash3, &hash4, nil}) + + failAddr := common.BytesToAddress([]byte("failmenow")) + filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, 20, []common.Address{failAddr}, nil) + + logs, _ = filter.Logs(context.Background()) + if len(logs) != 0 { + t.Error("expected 0 log, got", len(logs)) + } + + // Block 7 + backend.expectBorReceiptsFromMock([]*common.Hash{&hash1, &hash2, nil, &hash3, &hash4, nil}) + + filter = NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, 20, nil, [][]common.Hash{{failHash}, {hash1}}) + + logs, _ = filter.Logs(context.Background()) + if len(logs) != 0 { + t.Error("expected 0 log, got", len(logs)) + } +} diff --git a/eth/filters/filter.go b/eth/filters/filter.go index 4af45c7ea6..a99f1e753a 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) +//go:generate mockgen -destination=../../eth/filters/IBackend.go -package=filters . Backend type Backend interface { ChainDb() ethdb.Database HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index a49f339f86..67d69bb628 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "math/big" - "math/rand" "reflect" "runtime" "testing" @@ -30,11 +29,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -44,126 +40,6 @@ var ( borLogs bool = true ) -type testBackend struct { - mux *event.TypeMux - db ethdb.Database - sections uint64 - txFeed event.Feed - logsFeed event.Feed - rmLogsFeed event.Feed - pendingLogsFeed event.Feed - chainFeed event.Feed - - stateSyncFeed event.Feed -} - -func (b *testBackend) ChainDb() ethdb.Database { - return b.db -} - -func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { - var ( - hash common.Hash - num uint64 - ) - if blockNr == rpc.LatestBlockNumber { - hash = rawdb.ReadHeadBlockHash(b.db) - number := rawdb.ReadHeaderNumber(b.db, hash) - if number == nil { - return nil, nil - } - num = *number - } else { - num = uint64(blockNr) - hash = rawdb.ReadCanonicalHash(b.db, num) - } - return rawdb.ReadHeader(b.db, hash, num), nil -} - -func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { - number := rawdb.ReadHeaderNumber(b.db, hash) - if number == nil { - return nil, nil - } - return rawdb.ReadHeader(b.db, hash, *number), nil -} - -func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { - if number := rawdb.ReadHeaderNumber(b.db, hash); number != nil { - return rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig), nil - } - return nil, nil -} - -func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { - number := rawdb.ReadHeaderNumber(b.db, hash) - if number == nil { - return nil, nil - } - receipts := rawdb.ReadReceipts(b.db, hash, *number, params.TestChainConfig) - - logs := make([][]*types.Log, len(receipts)) - for i, receipt := range receipts { - logs[i] = receipt.Logs - } - return logs, nil -} - -func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { - return b.txFeed.Subscribe(ch) -} - -func (b *testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { - return b.rmLogsFeed.Subscribe(ch) -} - -func (b *testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { - return b.logsFeed.Subscribe(ch) -} - -func (b *testBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { - return b.pendingLogsFeed.Subscribe(ch) -} - -func (b *testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { - return b.chainFeed.Subscribe(ch) -} - -func (b *testBackend) BloomStatus() (uint64, uint64) { - return params.BloomBitsBlocks, b.sections -} - -func (b *testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { - requests := make(chan chan *bloombits.Retrieval) - - go session.Multiplex(16, 0, requests) - go func() { - for { - // Wait for a service request or a shutdown - select { - case <-ctx.Done(): - return - - case request := <-requests: - task := <-request - - task.Bitsets = make([][]byte, len(task.Sections)) - for i, section := range task.Sections { - if rand.Int()%4 != 0 { // Handle occasional missing deliveries - head := rawdb.ReadCanonicalHash(b.db, (section+1)*params.BloomBitsBlocks-1) - task.Bitsets[i], _ = rawdb.ReadBloomBits(b.db, task.Bit, section, head) - } - } - request <- task - } - } - }() -} - -func (b *testBackend) SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription { - return b.stateSyncFeed.Subscribe(ch) -} - // TestBlockSubscription tests if a block subscription returns block hashes for posted chain events. // It creates multiple subscriptions: // - one at the start and should receive all posted chain events and a second (blockHashes) @@ -174,7 +50,7 @@ func TestBlockSubscription(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} + backend = &TestBackend{DB: db} api = NewPublicFilterAPI(backend, false, deadline, borLogs) genesis = (&core.Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(db) chain, _ = core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {}) @@ -226,7 +102,7 @@ func TestPendingTxFilter(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} + backend = &TestBackend{DB: db} api = NewPublicFilterAPI(backend, false, deadline, borLogs) transactions = []*types.Transaction{ @@ -281,7 +157,7 @@ func TestPendingTxFilter(t *testing.T) { func TestLogFilterCreation(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} + backend = &TestBackend{DB: db} api = NewPublicFilterAPI(backend, false, deadline, borLogs) testCases = []struct { @@ -325,7 +201,7 @@ func TestInvalidLogFilterCreation(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} + backend = &TestBackend{DB: db} api = NewPublicFilterAPI(backend, false, deadline, borLogs) ) @@ -347,7 +223,7 @@ func TestInvalidLogFilterCreation(t *testing.T) { func TestInvalidGetLogsRequest(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} + backend = &TestBackend{DB: db} api = NewPublicFilterAPI(backend, false, deadline, borLogs) blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") ) @@ -372,7 +248,7 @@ func TestLogFilter(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} + backend = &TestBackend{DB: db} api = NewPublicFilterAPI(backend, false, deadline, borLogs) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") @@ -486,7 +362,7 @@ func TestPendingLogsSubscription(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} + backend = &TestBackend{DB: db} api = NewPublicFilterAPI(backend, false, deadline, borLogs) firstAddr = common.HexToAddress("0x1111111111111111111111111111111111111111") @@ -670,7 +546,7 @@ func TestPendingTxFilterDeadlock(t *testing.T) { var ( db = rawdb.NewMemoryDatabase() - backend = &testBackend{db: db} + backend = &TestBackend{DB: db} api = NewPublicFilterAPI(backend, false, timeout, borLogs) done = make(chan struct{}) ) diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 63a48f762d..6a8443b67c 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -50,7 +50,7 @@ func BenchmarkFilters(b *testing.B) { var ( db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "", false) - backend = &testBackend{db: db} + backend = &TestBackend{DB: db} key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = common.BytesToAddress([]byte("jeff")) @@ -108,7 +108,7 @@ func TestFilters(t *testing.T) { var ( db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "", false) - backend = &testBackend{db: db} + backend = &TestBackend{DB: db} key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key1.PublicKey) diff --git a/eth/filters/test_backend.go b/eth/filters/test_backend.go new file mode 100644 index 0000000000..979ed3efb6 --- /dev/null +++ b/eth/filters/test_backend.go @@ -0,0 +1,177 @@ +package filters + +import ( + context "context" + "crypto/rand" + "math/big" + + common "github.com/ethereum/go-ethereum/common" + core "github.com/ethereum/go-ethereum/core" + bloombits "github.com/ethereum/go-ethereum/core/bloombits" + "github.com/ethereum/go-ethereum/core/rawdb" + types "github.com/ethereum/go-ethereum/core/types" + ethdb "github.com/ethereum/go-ethereum/ethdb" + event "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/params" + rpc "github.com/ethereum/go-ethereum/rpc" +) + +type TestBackend struct { + DB ethdb.Database + sections uint64 + txFeed event.Feed + logsFeed event.Feed + rmLogsFeed event.Feed + pendingLogsFeed event.Feed + chainFeed event.Feed + + stateSyncFeed event.Feed +} + +func (b *TestBackend) BloomStatus() (uint64, uint64) { + return params.BloomBitsBlocks, b.sections +} + +func (b *TestBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) { + number := rawdb.ReadHeaderNumber(b.DB, hash) + if number == nil { + return &types.Receipt{}, nil + } + + receipt := rawdb.ReadBorReceipt(b.DB, hash, *number) + if receipt == nil { + return &types.Receipt{}, nil + } + + return receipt, nil +} + +func (b *TestBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) { + receipt, err := b.GetBorBlockReceipt(ctx, hash) + if err != nil { + return []*types.Log{}, err + } + + if receipt == nil { + return []*types.Log{}, nil + } + + return receipt.Logs, nil +} + +func (b *TestBackend) ChainDb() ethdb.Database { + return b.DB +} + +func (b *TestBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { + var ( + hash common.Hash + num uint64 + ) + + if blockNr == rpc.LatestBlockNumber { + hash = rawdb.ReadHeadBlockHash(b.DB) + number := rawdb.ReadHeaderNumber(b.DB, hash) + + if number == nil { + return &types.Header{}, nil + } + + num = *number + } else { + num = uint64(blockNr) + hash = rawdb.ReadCanonicalHash(b.DB, num) + } + + return rawdb.ReadHeader(b.DB, hash, num), nil +} + +func (b *TestBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { + number := rawdb.ReadHeaderNumber(b.DB, hash) + if number == nil { + return &types.Header{}, nil + } + + return rawdb.ReadHeader(b.DB, hash, *number), nil +} + +func (b *TestBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { + if number := rawdb.ReadHeaderNumber(b.DB, hash); number != nil { + return rawdb.ReadReceipts(b.DB, hash, *number, params.TestChainConfig), nil + } + + return nil, nil +} + +func (b *TestBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { + number := rawdb.ReadHeaderNumber(b.DB, hash) + if number == nil { + return nil, nil + } + + receipts := rawdb.ReadReceipts(b.DB, hash, *number, params.TestChainConfig) + + logs := make([][]*types.Log, len(receipts)) + for i, receipt := range receipts { + logs[i] = receipt.Logs + } + + return logs, nil +} + +func (b *TestBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { + return b.txFeed.Subscribe(ch) +} + +func (b *TestBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { + return b.rmLogsFeed.Subscribe(ch) +} + +func (b *TestBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { + return b.logsFeed.Subscribe(ch) +} + +func (b *TestBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription { + return b.pendingLogsFeed.Subscribe(ch) +} + +func (b *TestBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { + return b.chainFeed.Subscribe(ch) +} + +func (b *TestBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) { + requests := make(chan chan *bloombits.Retrieval) + + go session.Multiplex(16, 0, requests) + go func() { + for { + // Wait for a service request or a shutdown + select { + case <-ctx.Done(): + return + + case request := <-requests: + task := <-request + + task.Bitsets = make([][]byte, len(task.Sections)) + for i, section := range task.Sections { + nBig, err := rand.Int(rand.Reader, big.NewInt(100)) + + if err != nil { + panic(err) + } + + if nBig.Int64()%4 != 0 { // Handle occasional missing deliveries + head := rawdb.ReadCanonicalHash(b.DB, (section+1)*params.BloomBitsBlocks-1) + task.Bitsets[i], _ = rawdb.ReadBloomBits(b.DB, task.Bit, section, head) + } + } + request <- task + } + } + }() +} + +func (b *TestBackend) SubscribeStateSyncEvent(ch chan<- core.StateSyncEvent) event.Subscription { + return b.stateSyncFeed.Subscribe(ch) +} diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index c0d3c6b603..134168b885 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -144,7 +144,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke // Construct testing chain diskdb := rawdb.NewMemoryDatabase() gspec.Commit(diskdb) - chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec.Config, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("Failed to create local chain, %v", err) } diff --git a/eth/handler.go b/eth/handler.go index 3d8380412c..8e6d89f9ef 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -24,6 +24,7 @@ import ( "sync/atomic" "time" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/beacon" @@ -31,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/core/forkid" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/eth/downloader/whitelist" "github.com/ethereum/go-ethereum/eth/fetcher" "github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/snap" @@ -91,6 +91,7 @@ type handlerConfig struct { EthAPI *ethapi.PublicBlockChainAPI // EthAPI to interact PeerRequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges + checker ethereum.ChainValidator } type handler struct { @@ -209,7 +210,7 @@ func newHandler(config *handlerConfig) (*handler, error) { // sync is requested. The downloader is responsible for deallocating the state // bloom when it's done. // todo: it'd better to extract maxCapacity into config - h.downloader = downloader.New(h.checkpointNumber, config.Database, h.eventMux, h.chain, nil, h.removePeer, success, whitelist.NewService(10)) + h.downloader = downloader.New(h.checkpointNumber, config.Database, h.eventMux, h.chain, nil, h.removePeer, success, config.checker) // Construct the fetcher (short sync) validator := func(header *types.Header) error { @@ -439,7 +440,7 @@ func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { }() } // If we have any explicit peer required block hashes, request them - for number := range h.peerRequiredBlocks { + for number, hash := range h.peerRequiredBlocks { resCh := make(chan *eth.Response) if _, err := peer.RequestHeadersByNumber(number, 1, 0, false, resCh); err != nil { return err diff --git a/eth/handler_bor.go b/eth/handler_bor.go index 11896f3c47..604deef282 100644 --- a/eth/handler_bor.go +++ b/eth/handler_bor.go @@ -3,16 +3,21 @@ package eth import ( "context" "errors" - "fmt" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/bor" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" ) var ( + // errCheckpointCount is returned when we are unable to fetch + // the checkpoint count from local heimdall. + errCheckpointCount = errors.New("failed to fetch checkpoint count") + + // errNoCheckpoint is returned when there is not checkpoint proposed + // by heimdall yet or heimdall is not in sync + errNoCheckpoint = errors.New("no checkpoint proposed") + // errCheckpoint is returned when we are unable to fetch the // latest checkpoint from the local heimdall. errCheckpoint = errors.New("failed to fetch latest checkpoint") @@ -33,43 +38,66 @@ var ( errEndBlock = errors.New("failed to get end block") ) -// fetchWhitelistCheckpoint fetched the latest checkpoint from it's local heimdall +// fetchWhitelistCheckpoints fetches the latest checkpoint/s from it's local heimdall // and verifies the data against bor data. -func (h *ethHandler) fetchWhitelistCheckpoint(bor *bor.Bor) (uint64, common.Hash, error) { - // check for checkpoint whitelisting: bor - checkpoint, err := bor.HeimdallClient.FetchLatestCheckpoint() +func (h *ethHandler) fetchWhitelistCheckpoints(ctx context.Context, bor *bor.Bor, checkpointVerifier *checkpointVerifier, first bool) ([]uint64, []common.Hash, error) { + // Create an array for block number and block hashes + //nolint:prealloc + var ( + blockNums []uint64 = make([]uint64, 0) + blockHashes []common.Hash = make([]common.Hash, 0) + ) + + // Fetch the checkpoint count from heimdall + count, err := bor.HeimdallClient.FetchCheckpointCount(ctx) if err != nil { - log.Debug("Failed to fetch latest checkpoint for whitelisting") - return 0, common.Hash{}, errCheckpoint + log.Debug("Failed to fetch checkpoint count for whitelisting", "err", err) + return blockNums, blockHashes, errCheckpointCount } - // check if we have the checkpoint blocks - head := h.ethAPI.BlockNumber() - if head < hexutil.Uint64(checkpoint.EndBlock.Uint64()) { - log.Debug("Head block behind checkpoint block", "head", head, "checkpoint end block", checkpoint.EndBlock) - return 0, common.Hash{}, errMissingCheckpoint + if count == 0 { + return blockNums, blockHashes, errNoCheckpoint } - // verify the root hash of checkpoint - roothash, err := h.ethAPI.GetRootHash(context.Background(), checkpoint.StartBlock.Uint64(), checkpoint.EndBlock.Uint64()) - if err != nil { - log.Debug("Failed to get root hash of checkpoint while whitelisting") - return 0, common.Hash{}, errRootHash + var ( + start int64 + end int64 + ) + + // Prepare the checkpoint range to fetch + if count <= 10 { + start = 1 + } else { + start = count - 10 + 1 // 10 is the max number of checkpoints to fetch } - if roothash != checkpoint.RootHash.String()[2:] { - log.Warn("Checkpoint root hash mismatch while whitelisting", "expected", checkpoint.RootHash.String()[2:], "got", roothash) - return 0, common.Hash{}, errCheckpointRootHashMismatch + end = count + + // If we're in not in the first iteration, only fetch the latest checkpoint + if !first { + start = count } - // fetch the end checkpoint block hash - block, err := h.ethAPI.GetBlockByNumber(context.Background(), rpc.BlockNumber(checkpoint.EndBlock.Uint64()), false) - if err != nil { - log.Debug("Failed to get end block hash of checkpoint while whitelisting") - return 0, common.Hash{}, errEndBlock + for i := start; i <= end; i++ { + // fetch `i` indexed checkpoint from heimdall + checkpoint, err := bor.HeimdallClient.FetchCheckpoint(ctx, i) + if err != nil { + log.Debug("Failed to fetch latest checkpoint for whitelisting", "err", err) + return blockNums, blockHashes, errCheckpoint + } + + // Verify if the checkpoint fetched can be added to the local whitelist entry or not + // If verified, it returns the hash of the end block of the checkpoint. If not, + // it will return appropriate error. + + hash, err := checkpointVerifier.verify(ctx, h, checkpoint) + if err != nil { + return blockNums, blockHashes, err + } + + blockNums = append(blockNums, checkpoint.EndBlock.Uint64()) + blockHashes = append(blockHashes, common.HexToHash(hash)) } - hash := fmt.Sprintf("%v", block["hash"]) - - return checkpoint.EndBlock.Uint64(), common.HexToHash(hash), nil + return blockNums, blockHashes, nil } diff --git a/eth/handler_bor_test.go b/eth/handler_bor_test.go new file mode 100644 index 0000000000..857db70e95 --- /dev/null +++ b/eth/handler_bor_test.go @@ -0,0 +1,134 @@ +package eth + +import ( + "context" + "math/big" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/bor" + "github.com/ethereum/go-ethereum/consensus/bor/clerk" + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint" + "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" +) + +type mockHeimdall struct { + fetchCheckpoint func(ctx context.Context, number int64) (*checkpoint.Checkpoint, error) + fetchCheckpointCount func(ctx context.Context) (int64, error) +} + +func (m *mockHeimdall) StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) { + return nil, nil +} +func (m *mockHeimdall) Span(ctx context.Context, spanID uint64) (*span.HeimdallSpan, error) { + //nolint:nilnil + return nil, nil +} +func (m *mockHeimdall) FetchCheckpoint(ctx context.Context, number int64) (*checkpoint.Checkpoint, error) { + return m.fetchCheckpoint(ctx, number) +} +func (m *mockHeimdall) FetchCheckpointCount(ctx context.Context) (int64, error) { + return m.fetchCheckpointCount(ctx) +} +func (m *mockHeimdall) Close() {} + +func TestFetchWhitelistCheckpoints(t *testing.T) { + t.Parallel() + + // create an empty ethHandler + handler := ðHandler{} + + // create a mock checkpoint verification function and use it to create a verifier + verify := func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error) { + return "", nil + } + + verifier := newCheckpointVerifier(verify) + + // Create a mock heimdall instance and use it for creating a bor instance + var heimdall mockHeimdall + + bor := &bor.Bor{HeimdallClient: &heimdall} + + // create 20 mock checkpoints + checkpoints := createMockCheckpoints(20) + + // create a mock fetch checkpoint function + heimdall.fetchCheckpoint = func(_ context.Context, number int64) (*checkpoint.Checkpoint, error) { + return checkpoints[number-1], nil // we're sure that number won't exceed 20 + } + + // create a background context + ctx := context.Background() + + testCases := []struct { + name string + first bool + count int64 + length int + start uint64 + end uint64 + fetchErr error + expectedErr error + }{ + {"fail to fetch checkpoint count", false, 0, 0, 0, 0, errCheckpointCount, errCheckpointCount}, + {"no checkpoints available", false, 0, 0, 0, 0, nil, errNoCheckpoint}, + {"fetch multiple checkpoints (count < 10)", true, 6, 6, 0, 6, nil, nil}, + {"fetch multiple checkpoints (count = 10)", true, 10, 10, 0, 10, nil, nil}, + {"fetch multiple checkpoints (count > 10)", true, 16, 10, 6, 16, nil, nil}, + {"fetch single checkpoint", false, 18, 1, 17, 18, nil, nil}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + heimdall.fetchCheckpointCount = getMockFetchCheckpointFn(tc.count, tc.fetchErr) + blockNums, blockHashes, err := handler.fetchWhitelistCheckpoints(ctx, bor, verifier, tc.first) + + // Check if we have expected result + require.Equal(t, tc.expectedErr, err) + require.Equal(t, tc.length, len(blockNums)) + require.Equal(t, tc.length, len(blockHashes)) + validateBlockNumber(t, blockNums, checkpoints[tc.start:tc.end]) + }) + } +} + +func validateBlockNumber(t *testing.T, blockNums []uint64, checkpoints []*checkpoint.Checkpoint) { + t.Helper() + + for i, blockNum := range blockNums { + require.Equal(t, blockNum, checkpoints[i].EndBlock.Uint64(), "expect block number in array to match with checkpoint") + } +} + +func getMockFetchCheckpointFn(number int64, err error) func(ctx context.Context) (int64, error) { + return func(_ context.Context) (int64, error) { + return number, err + } +} + +func createMockCheckpoints(count int) []*checkpoint.Checkpoint { + var ( + checkpoints []*checkpoint.Checkpoint = make([]*checkpoint.Checkpoint, count) + startBlock int64 = 257 // any number can be used + ) + + for i := 0; i < count; i++ { + checkpoints[i] = &checkpoint.Checkpoint{ + Proposer: common.Address{}, + StartBlock: big.NewInt(startBlock), + EndBlock: big.NewInt(startBlock + 255), + RootHash: common.Hash{}, + BorChainID: "137", + Timestamp: uint64(time.Now().Unix()), + } + startBlock += 256 + } + + return checkpoints +} diff --git a/eth/handler_eth_test.go b/eth/handler_eth_test.go index 7d5027ae77..6634b26871 100644 --- a/eth/handler_eth_test.go +++ b/eth/handler_eth_test.go @@ -105,8 +105,8 @@ func testForkIDSplit(t *testing.T, protocol uint) { genesisNoFork = gspecNoFork.MustCommit(dbNoFork) genesisProFork = gspecProFork.MustCommit(dbProFork) - chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil) - chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil) + chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil, nil) + chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil, nil) blocksNoFork, _ = core.GenerateChain(configNoFork, genesisNoFork, engine, dbNoFork, 2, nil) blocksProFork, _ = core.GenerateChain(configProFork, genesisProFork, engine, dbProFork, 2, nil) diff --git a/eth/handler_test.go b/eth/handler_test.go index d967b6df93..c6d7811d10 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -138,7 +138,7 @@ func newTestHandlerWithBlocks(blocks int) *testHandler { Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}}, }).MustCommit(db) - chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, nil) if _, err := chain.InsertChain(bs); err != nil { diff --git a/eth/protocols/eth/handler_test.go b/eth/protocols/eth/handler_test.go index 55e612b801..0bbe9f66a9 100644 --- a/eth/protocols/eth/handler_test.go +++ b/eth/protocols/eth/handler_test.go @@ -68,7 +68,7 @@ func newTestBackendWithGenerator(blocks int, generator func(int, *core.BlockGen) Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}}, }).MustCommit(db) - chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator) if _, err := chain.InsertChain(bs); err != nil { diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 665d7601cf..76a157df69 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -27,6 +27,8 @@ import ( "sync" "time" + "golang.org/x/crypto/sha3" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/rawdb" @@ -41,7 +43,6 @@ import ( "github.com/ethereum/go-ethereum/p2p/msgrate" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "golang.org/x/crypto/sha3" ) var ( diff --git a/eth/sync.go b/eth/sync.go index 22c0c9054a..aa79b6181c 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -230,7 +230,7 @@ func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) { // return downloader.SnapSync, td // } // } - // Nope, we're really full syncing + // // Nope, we're really full syncing // head := cs.handler.chain.CurrentBlock() // td := cs.handler.chain.GetTd(head.Hash(), head.NumberU64()) // return downloader.FullSync, td diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 36296e0d42..3fce91ac9c 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -629,7 +629,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config if *config.BorTraceEnabled { callmsg := prepareCallMessage(msg) - if _, err := statefull.ApplyMessage(callmsg, statedb, block.Header(), api.backend.ChainConfig(), api.chainContext(ctx)); err != nil { + if _, err := statefull.ApplyMessage(ctx, callmsg, statedb, block.Header(), api.backend.ChainConfig(), api.chainContext(ctx)); err != nil { log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) // We intentionally don't return the error here: if we do, then the RPC server will not // return the roots. Most likely, the caller already knows that a certain transaction fails to diff --git a/eth/tracers/api_bor.go b/eth/tracers/api_bor.go index 8993b9ae38..b93baae432 100644 --- a/eth/tracers/api_bor.go +++ b/eth/tracers/api_bor.go @@ -44,7 +44,7 @@ func (api *API) traceBorBlock(ctx context.Context, block *types.Block, config *T } // block object cannot be converted to JSON since much of the fields are non-public - blockFields, err := ethapi.RPCMarshalBlock(block, true, true, api.backend.ChainConfig()) + blockFields, err := ethapi.RPCMarshalBlock(block, true, true, api.backend.ChainConfig(), api.backend.ChainDb()) if err != nil { return nil, err } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index aa9f913396..6dd94e4870 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -81,7 +81,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i SnapshotLimit: 0, TrieDirtyDisabled: true, // Archive mode } - chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 6e8915358b..13a2e46d25 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -533,10 +533,23 @@ func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" } + pending := big.NewInt(-1) + finalized := big.NewInt(int64(rpc.FinalizedBlockNumber)) + safe := big.NewInt(int64(rpc.SafeBlockNumber)) + if number.Cmp(pending) == 0 { return "pending" } + + if number.Cmp(finalized) == 0 { + return "finalized" + } + + if number.Cmp(safe) == 0 { + return "safe" + } + return hexutil.EncodeBig(number) } diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index 538e23727d..2abeeaaf5c 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -183,10 +183,23 @@ func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" } + pending := big.NewInt(-1) + finalized := big.NewInt(int64(rpc.FinalizedBlockNumber)) + safe := big.NewInt(int64(rpc.SafeBlockNumber)) + if number.Cmp(pending) == 0 { return "pending" } + + if number.Cmp(finalized) == 0 { + return "finalized" + } + + if number.Cmp(safe) == 0 { + return "safe" + } + return hexutil.EncodeBig(number) } diff --git a/ethdb/database.go b/ethdb/database.go index b2e7c7228a..88c8de6a16 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -164,6 +164,7 @@ type AncientStore interface { // Database contains all the methods required by the high level database to not // only access the key-value data store but also the chain freezer. +//go:generate mockgen -destination=../eth/filters/IDatabase.go -package=filters . Database type Database interface { Reader Writer diff --git a/go.mod b/go.mod index e31612cfe3..36595ca307 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,11 @@ module github.com/ethereum/go-ethereum -go 1.18 +go 1.19 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 + github.com/BurntSushi/toml v1.1.0 + github.com/JekaMas/go-grpc-net-conn v0.0.0-20220708155319-6aff21f2d13d github.com/VictoriaMetrics/fastcache v1.6.0 github.com/aws/aws-sdk-go-v2 v1.2.0 github.com/aws/aws-sdk-go-v2/config v1.1.1 @@ -30,6 +32,7 @@ require ( github.com/google/uuid v1.2.0 github.com/gorilla/websocket v1.4.2 github.com/graph-gophers/graphql-go v1.3.0 + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/hashicorp/go-bexpr v0.1.10 github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d github.com/hashicorp/hcl/v2 v2.10.1 @@ -43,10 +46,11 @@ require ( github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/julienschmidt/httprouter v1.3.0 github.com/karalabe/usb v0.0.2 + github.com/maticnetwork/crand v1.0.2 + github.com/maticnetwork/polyproto v0.0.2 github.com/mattn/go-colorable v0.1.8 github.com/mattn/go-isatty v0.0.12 github.com/mitchellh/cli v1.1.2 - github.com/mitchellh/go-grpc-net-conn v0.0.0-20200427190222-eb030e4876f0 github.com/mitchellh/go-homedir v1.1.0 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 @@ -56,7 +60,7 @@ require ( github.com/ryanuber/columnize v2.1.2+incompatible github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.8.0 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef github.com/xsleonard/go-merkle v1.1.0 @@ -65,24 +69,24 @@ require ( go.opentelemetry.io/otel/sdk v1.2.0 go.uber.org/goleak v1.1.12 golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 + golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 golang.org/x/text v0.3.7 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba - golang.org/x/tools v0.1.10 - google.golang.org/grpc v1.42.0 - google.golang.org/protobuf v1.27.1 + golang.org/x/tools v0.1.12 + gonum.org/v1/gonum v0.11.0 + google.golang.org/grpc v1.48.0 + google.golang.org/protobuf v1.28.0 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 gopkg.in/urfave/cli.v1 v1.20.0 gotest.tools v2.2.0+incompatible - pgregory.net/rapid v0.4.7 + pgregory.net/rapid v0.4.8 ) require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect - github.com/BurntSushi/toml v1.1.0 // indirect github.com/Masterminds/goutils v1.1.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect @@ -101,7 +105,6 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect - github.com/go-kit/kit v0.9.0 // indirect github.com/go-logfmt/logfmt v0.5.0 // indirect github.com/go-ole/go-ole v1.2.1 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect @@ -119,7 +122,7 @@ require ( github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/opentracing/opentracing-go v1.1.0 // indirect - github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml v1.9.5 github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/posener/complete v1.1.1 // indirect @@ -127,13 +130,14 @@ require ( github.com/tklauser/numcpus v0.2.2 // indirect github.com/zclconf/go-cty v1.8.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 // indirect - go.opentelemetry.io/otel/trace v1.2.0 // indirect + go.opentelemetry.io/otel/trace v1.2.0 go.opentelemetry.io/proto/otlp v0.10.0 // indirect - golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect - golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect - golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect + golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.0.0-20220728030405-41545e8bf201 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect - google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect + google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 593c8e11d0..96fa9d3f04 100644 --- a/go.sum +++ b/go.sum @@ -29,6 +29,8 @@ github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/JekaMas/go-grpc-net-conn v0.0.0-20220708155319-6aff21f2d13d h1:RO27lgfZF8s9lZ3pWyzc0gCE0RZC+6/PXbRjAa0CNp8= +github.com/JekaMas/go-grpc-net-conn v0.0.0-20220708155319-6aff21f2d13d/go.mod h1:romz7UPgSYhfJkKOalzEEyV6sWtt/eAEm0nX2aOrod0= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -103,6 +105,7 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f h1:C43yEtQ6NIf4ftFXD/V55gnGFgPbMQobd//YlnLjUJ8= @@ -144,6 +147,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -184,6 +188,7 @@ github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3a github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= @@ -250,6 +255,8 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -311,6 +318,7 @@ github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= @@ -335,6 +343,10 @@ github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/maticnetwork/crand v1.0.2 h1:Af0tAivC8zrxXDpGWNWVT/0s1fOz8w0eRbahZgURS8I= +github.com/maticnetwork/crand v1.0.2/go.mod h1:/NRNL3bj2eYdqpWmoIP5puxndTpi0XRxpj5ZKxfHjyg= +github.com/maticnetwork/polyproto v0.0.2 h1:cPxuxbIDItdwGnucc3lZB58U8Zfe1mH73PWTGd15554= +github.com/maticnetwork/polyproto v0.0.2/go.mod h1:e1mU2EXSwEpn5jM7GfNwu3AupsV6WAGoPFFfswXOF0o= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -357,8 +369,6 @@ github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw= github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/go-grpc-net-conn v0.0.0-20200427190222-eb030e4876f0 h1:oZuel4h7224ILBLg2SlTxdaMYXDyqcVfL4Cg1PJQHZs= -github.com/mitchellh/go-grpc-net-conn v0.0.0-20200427190222-eb030e4876f0/go.mod h1:ZCzL0JMR6qfm7VrDC8HGwVtPA8D2Ijc/edUSBw58x94= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= @@ -437,6 +447,7 @@ github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -448,16 +459,15 @@ github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57N github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= @@ -480,6 +490,7 @@ github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xsleonard/go-merkle v1.1.0 h1:fHe1fuhJjGH22ZzVTAH0jqHLhTGhOq3wQjJN+8P0jQg= github.com/xsleonard/go-merkle v1.1.0/go.mod h1:cW4z+UZ/4f2n9IJgIiyDCdYguchoDyDAPmpuOWGxdGg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= @@ -503,10 +514,12 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.opentelemetry.io/proto/otlp v0.10.0 h1:n7brgtEbDvXEgGyKKo8SobKT1e9FewlDtXzkVP5djoE= go.opentelemetry.io/proto/otlp v0.10.0/go.mod h1:zG20xCK0szZ1xdokeSOwEcmlXu+x9kkdRe6N1DhKcfU= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -530,6 +543,8 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -547,10 +562,11 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -567,6 +583,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -579,8 +596,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220728030405-41545e8bf201 h1:bvOltf3SADAfG05iRml8lAB3qjoEX5RCyN4K6G5v3N0= +golang.org/x/net v0.0.0-20220728030405-41545e8bf201/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -593,8 +610,9 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -604,6 +622,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -635,11 +654,12 @@ golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -680,11 +700,13 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -694,6 +716,8 @@ golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8T gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= +gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= @@ -723,9 +747,11 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b h1:SfSkJugek6xm7lWywqth4r2iTrYLpD8lOj1nMIIhMNM= +google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -733,12 +759,13 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -750,8 +777,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -776,8 +804,9 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -786,7 +815,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= -pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= +pgregory.net/rapid v0.4.8 h1:d+5SGZWUbJPbl3ss6tmPFqnNeQR6VDOFly+eTjwPiEw= +pgregory.net/rapid v0.4.8/go.mod h1:Z5PbWqjvWR1I3UGjvboUuan4fe4ZYEYNLNQLExzCoUs= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/integration-tests/smoke_test.sh b/integration-tests/smoke_test.sh index 6f41aa5c16..62ca370ee7 100644 --- a/integration-tests/smoke_test.sh +++ b/integration-tests/smoke_test.sh @@ -1,33 +1,44 @@ #!/bin/bash set -e -delay=600 +balanceInit=$(docker exec bor0 bash -c "bor attach /root/.bor/data/bor.ipc -exec 'Math.round(web3.fromWei(eth.getBalance(eth.accounts[0])))'") -echo "Wait ${delay} seconds for state-sync..." -sleep $delay +stateSyncFound="false" +checkpointFound="false" +SECONDS=0 +start_time=$SECONDS +while true +do + + balance=$(docker exec bor0 bash -c "bor attach /root/.bor/data/bor.ipc -exec 'Math.round(web3.fromWei(eth.getBalance(eth.accounts[0])))'") -balance=$(docker exec bor0 bash -c "bor attach /root/.bor/data/bor.ipc -exec 'Math.round(web3.fromWei(eth.getBalance(eth.accounts[0])))'") + if ! [[ "$balance" =~ ^[0-9]+$ ]]; then + echo "Something is wrong! Can't find the balance of first account in bor network." + exit 1 + fi -if ! [[ "$balance" =~ ^[0-9]+$ ]]; then - echo "Something is wrong! Can't find the balance of first account in bor network." - exit 1 -fi + if (( $balance > $balanceInit )); then + if [ $stateSyncFound != "true" ]; then + stateSyncTime=$(( SECONDS - start_time )) + stateSyncFound="true" + fi + fi -echo "Found matic balance on account[0]: " $balance + checkpointID=$(curl -sL http://localhost:1317/checkpoints/latest | jq .result.id) -if (( $balance <= 1001 )); then - echo "Balance in bor network has not increased. This indicates that something is wrong with state sync." - exit 1 -fi + if [ $checkpointID != "null" ]; then + if [ $checkpointFound != "true" ]; then + checkpointTime=$(( SECONDS - start_time )) + checkpointFound="true" + fi + fi -checkpointID=$(curl -sL http://localhost:1317/checkpoints/latest | jq .result.id) + if [ $stateSyncFound == "true" ] && [ $checkpointFound == "true" ]; then + break + fi -if [ $checkpointID == "null" ]; then - echo "Something is wrong! Could not find any checkpoint." - exit 1 -else - echo "Found checkpoint ID:" $checkpointID -fi - -echo "All tests have passed!" \ No newline at end of file +done +echo "Both state sync and checkpoint went through. All tests have passed!" +echo "Time taken for state sync: $(printf '%02dm:%02ds\n' $(($stateSyncTime%3600/60)) $(($stateSyncTime%60)))" +echo "Time taken for checkpoint: $(printf '%02dm:%02ds\n' $(($checkpointTime%3600/60)) $(($checkpointTime%60)))" diff --git a/interfaces.go b/interfaces.go index 94a2492ae1..ff6d80b1ec 100644 --- a/interfaces.go +++ b/interfaces.go @@ -238,3 +238,12 @@ type StateSyncFilter struct { ID uint64 Contract common.Address } + +// interface for whitelist service +type ChainValidator interface { + IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) + IsValidChain(currentHeader *types.Header, chain []*types.Header) bool + ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) + GetCheckpointWhitelist() map[uint64]common.Hash + PurgeCheckpointWhitelist() +} diff --git a/internal/cli/bootnode.go b/internal/cli/bootnode.go index 9e1a0fcde9..d1dc1c2fd9 100644 --- a/internal/cli/bootnode.go +++ b/internal/cli/bootnode.go @@ -4,7 +4,6 @@ import ( "crypto/ecdsa" "errors" "fmt" - "io/ioutil" "net" "os" "os/signal" @@ -162,7 +161,7 @@ func (b *BootnodeCommand) Run(args []string) int { } // save the public key pubRaw := fmt.Sprintf("%x", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:]) - if err := ioutil.WriteFile(filepath.Join(path, "pub.key"), []byte(pubRaw), 0600); err != nil { + if err := os.WriteFile(filepath.Join(path, "pub.key"), []byte(pubRaw), 0600); err != nil { b.UI.Error(fmt.Sprintf("failed to write node pub key: %v", err)) return 1 } diff --git a/internal/cli/debug.go b/internal/cli/debug.go index 6e083a6974..e15be6d1f9 100644 --- a/internal/cli/debug.go +++ b/internal/cli/debug.go @@ -17,11 +17,10 @@ import ( "github.com/ethereum/go-ethereum/internal/cli/server/proto" - "github.com/golang/protobuf/jsonpb" // nolint:staticcheck - gproto "github.com/golang/protobuf/proto" // nolint:staticcheck - grpc_net_conn "github.com/mitchellh/go-grpc-net-conn" + grpc_net_conn "github.com/JekaMas/go-grpc-net-conn" "google.golang.org/grpc" - "google.golang.org/protobuf/runtime/protoiface" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/reflect/protoreflect" ) // DebugCommand is the command to group the peers commands @@ -160,11 +159,11 @@ func (d *debugEnv) writeFromStream(name string, stream debugStream) error { } // create the stream - conn := &grpc_net_conn.Conn{ + conn := &grpc_net_conn.Conn[*proto.DebugFileResponse_Input, *proto.DebugFileResponse_Input]{ Stream: stream, Response: &proto.DebugFileResponse_Input{}, - Decode: grpc_net_conn.SimpleDecoder(func(msg gproto.Message) *[]byte { - return &msg.(*proto.DebugFileResponse_Input).Data + Decode: grpc_net_conn.SimpleDecoder(func(msg *proto.DebugFileResponse_Input) *[]byte { + return &msg.Data }), } @@ -181,15 +180,15 @@ func (d *debugEnv) writeFromStream(name string, stream debugStream) error { return nil } -func (d *debugEnv) writeJSON(name string, msg protoiface.MessageV1) error { - m := jsonpb.Marshaler{} - data, err := m.MarshalToString(msg) +func (d *debugEnv) writeJSON(name string, msg protoreflect.ProtoMessage) error { + m := protojson.MarshalOptions{} + data, err := m.Marshal(msg) if err != nil { return err } - if err := ioutil.WriteFile(filepath.Join(d.dst, name), []byte(data), 0600); err != nil { + if err := ioutil.WriteFile(filepath.Join(d.dst, name), data, 0600); err != nil { return fmt.Errorf("failed to write status: %v", err) } diff --git a/internal/cli/debug_pprof.go b/internal/cli/debug_pprof.go index ef15e45b58..01698719e5 100644 --- a/internal/cli/debug_pprof.go +++ b/internal/cli/debug_pprof.go @@ -7,7 +7,7 @@ import ( "fmt" "strings" - "github.com/golang/protobuf/ptypes/empty" + empty "google.golang.org/protobuf/types/known/emptypb" "github.com/ethereum/go-ethereum/internal/cli/flagset" "github.com/ethereum/go-ethereum/internal/cli/server/proto" diff --git a/internal/cli/debug_test.go b/internal/cli/debug_test.go index f77cf839ac..fd896ef326 100644 --- a/internal/cli/debug_test.go +++ b/internal/cli/debug_test.go @@ -8,12 +8,12 @@ import ( "time" "github.com/mitchellh/cli" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/internal/cli/server" ) -var currentDir string = "" +var currentDir string func TestCommand_DebugBlock(t *testing.T) { t.Parallel() @@ -30,7 +30,7 @@ func TestCommand_DebugBlock(t *testing.T) { // start the mock server srv, err := server.CreateMockServer(config) - assert.NoError(t, err) + require.NoError(t, err) defer server.CloseMockServer(srv) @@ -53,7 +53,7 @@ func TestCommand_DebugBlock(t *testing.T) { start := time.Now() dst1 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json") res := traceBlock(port, 1, output) - assert.Equal(t, 0, res) + require.Equal(t, 0, res) t.Logf("Completed trace of block %d in %d ms at %s", 1, time.Since(start).Milliseconds(), dst1) // adding this to avoid debug directory name conflicts @@ -64,14 +64,14 @@ func TestCommand_DebugBlock(t *testing.T) { latestBlock := srv.GetLatestBlockNumber().Int64() dst2 := path.Join(output, prefix+time.Now().UTC().Format("2006-01-02-150405Z"), "block.json") res = traceBlock(port, latestBlock, output) - assert.Equal(t, 0, res) + require.Equal(t, 0, res) t.Logf("Completed trace of block %d in %d ms at %s", latestBlock, time.Since(start).Milliseconds(), dst2) // verify if the trace files are created done := verify(dst1) - assert.Equal(t, true, done) + require.Equal(t, true, done) done = verify(dst2) - assert.Equal(t, true, done) + require.Equal(t, true, done) // delete the traces deleteTraces(output) diff --git a/internal/cli/markdown_test.go b/internal/cli/markdown_test.go index 30c272a220..24a0e40e11 100644 --- a/internal/cli/markdown_test.go +++ b/internal/cli/markdown_test.go @@ -3,12 +3,12 @@ package cli import ( "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCodeBlock(t *testing.T) { t.Parallel() - assert := assert.New(t) + assert := require.New(t) lines := []string{ "abc", diff --git a/internal/cli/server/chains/chain.go b/internal/cli/server/chains/chain.go index d6717f5893..582ef64d21 100644 --- a/internal/cli/server/chains/chain.go +++ b/internal/cli/server/chains/chain.go @@ -4,7 +4,6 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "os" "github.com/ethereum/go-ethereum/common" @@ -50,7 +49,7 @@ func GetChain(name string) (*Chain, error) { } func ImportFromFile(filename string) (*Chain, error) { - data, err := ioutil.ReadFile(filename) + data, err := os.ReadFile(filename) if err != nil { return nil, err } diff --git a/internal/cli/server/chains/mainnet.go b/internal/cli/server/chains/mainnet.go index 199fe1a0d7..7aee9cd606 100644 --- a/internal/cli/server/chains/mainnet.go +++ b/internal/cli/server/chains/mainnet.go @@ -29,12 +29,16 @@ var mainnetBor = &Chain{ BerlinBlock: big.NewInt(14750000), LondonBlock: big.NewInt(23850000), Bor: ¶ms.BorConfig{ - JaipurBlock: 23850000, + JaipurBlock: big.NewInt(23850000), Period: map[string]uint64{ "0": 2, }, - ProducerDelay: 6, - Sprint: 64, + ProducerDelay: map[string]uint64{ + "0": 6, + }, + Sprint: map[string]uint64{ + "0": 64, + }, BackupMultiplier: map[string]uint64{ "0": 2, }, diff --git a/internal/cli/server/chains/mumbai.go b/internal/cli/server/chains/mumbai.go index 1343230b95..64a5b80060 100644 --- a/internal/cli/server/chains/mumbai.go +++ b/internal/cli/server/chains/mumbai.go @@ -29,16 +29,25 @@ var mumbaiTestnet = &Chain{ BerlinBlock: big.NewInt(13996000), LondonBlock: big.NewInt(22640000), Bor: ¶ms.BorConfig{ - JaipurBlock: 22770000, + JaipurBlock: big.NewInt(22770000), + DelhiBlock: big.NewInt(29638656), Period: map[string]uint64{ "0": 2, "25275000": 5, + "29638656": 2, + }, + ProducerDelay: map[string]uint64{ + "0": 6, + "29638656": 4, + }, + Sprint: map[string]uint64{ + "0": 64, + "29638656": 16, }, - ProducerDelay: 6, - Sprint: 64, BackupMultiplier: map[string]uint64{ "0": 2, "25275000": 5, + "29638656": 2, }, ValidatorContract: "0x0000000000000000000000000000000000001000", StateReceiverContract: "0x0000000000000000000000000000000000001001", diff --git a/internal/cli/server/chains/test_files/chain_legacy_test.json b/internal/cli/server/chains/test_files/chain_legacy_test.json index 5702eaca40..b97c8b1f8e 100644 --- a/internal/cli/server/chains/test_files/chain_legacy_test.json +++ b/internal/cli/server/chains/test_files/chain_legacy_test.json @@ -1,83 +1,94 @@ { - "config":{ - "chainId":80001, - "homesteadBlock":0, - "daoForkSupport":true, - "eip150Block":0, - "eip150Hash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "eip155Block":0, - "eip158Block":0, - "byzantiumBlock":0, - "constantinopleBlock":0, - "petersburgBlock":0, - "istanbulBlock":2722000, - "muirGlacierBlock":2722000, - "berlinBlock":13996000, - "londonBlock":13996000, - "bor":{ - "period":{ - "0":2 + "config": { + "chainId": 80001, + "homesteadBlock": 0, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 2722000, + "muirGlacierBlock": 2722000, + "berlinBlock": 13996000, + "londonBlock": 13996000, + "bor": { + "period": { + "0": 2, + "25275000": 5, + "29638656": 2 }, - "producerDelay":6, - "sprint":64, - "backupMultiplier":{ - "0":2 + "producerDelay": { + "0": 6, + "29638656": 4 }, - "validatorContract":"0x0000000000000000000000000000000000001000", - "stateReceiverContract":"0x0000000000000000000000000000000000001001", - "overrideStateSyncRecords":null, - "blockAlloc":{ - "22244000":{ - "0000000000000000000000000000000000001010":{ - "balance":"0x0", - "code":"0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610caa565b005b3480156103eb57600080fd5b506103f4610dfc565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e05565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fc1565b005b3480156104e857600080fd5b506104f1611090565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b506105486110b6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506110dc565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b506106046110fd565b005b34801561061257600080fd5b5061061b6111cd565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506111d3565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b50610758611358565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af611381565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de6113d8565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e611411565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061144e565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b50610964611474565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b8101908080359060200190929190505050611501565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050611521565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a65611541565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a90611548565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb61154e565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506115db565b005b348015610b2e57600080fd5b50610b376115f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b60006040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b60003390506000610cba826110dc565b9050610cd18360065461161e90919063ffffffff16565b600681905550600083118015610ce657508234145b610d58576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610dd4876110dc565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610e0d611381565b610e1657600080fd5b600081118015610e535750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b610ea8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611da96023913960400191505060405180910390fd5b6000610eb3836110dc565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f19350505050158015610f00573d6000803e3d6000fd5b50610f168360065461163e90919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f68585610f98896110dc565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611027576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611d866023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061108c8261165d565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b611105611381565b61110e57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b60008060008060418551146111ee5760009350505050611352565b602085015192506040850151915060ff6041860151169050601b8160ff16101561121957601b810190505b601b8160ff16141580156112315750601c8160ff1614155b156112425760009350505050611352565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561129f573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561134e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600381526020017f013881000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b6000813414611460576000905061146e565b61146b338484611755565b90505b92915050565b6040518060800160405280605b8152602001611e1e605b91396040516020018082805190602001908083835b602083106114c357805182526020820191506020810190506020830392506114a0565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061153761153286868686611b12565b611be8565b9050949350505050565b6201388181565b60015481565b604051806080016040528060528152602001611dcc605291396040516020018082805190602001908083835b6020831061159d578051825260208201915060208101905060208303925061157a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b6115e3611381565b6115ec57600080fd5b6115f58161165d565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008282111561162d57600080fd5b600082840390508091505092915050565b60008082840190508381101561165357600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561169757600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117d557600080fd5b505afa1580156117e9573d6000803e3d6000fd5b505050506040513d60208110156117ff57600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561189157600080fd5b505afa1580156118a5573d6000803e3d6000fd5b505050506040513d60208110156118bb57600080fd5b810190808051906020019092919050505090506118d9868686611c32565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156119e157600080fd5b505afa1580156119f5573d6000803e3d6000fd5b505050506040513d6020811015611a0b57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a9957600080fd5b505afa158015611aad573d6000803e3d6000fd5b505050506040513d6020811015611ac357600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b6000806040518060800160405280605b8152602001611e1e605b91396040516020018082805190602001908083835b60208310611b645780518252602082019150602081019050602083039250611b41565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611cd4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f63616e27742073656e6420746f204d524332300000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611d1a573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a72315820ccd6c2a9c259832bbb367986ee06cd87af23022681b0cb22311a864b701d939564736f6c63430005100032" + "sprint": { + "0": 64, + "29638656": 16 + }, + "backupMultiplier": { + "0": 2, + "25275000": 5, + "29638656": 2 + }, + "validatorContract": "0x0000000000000000000000000000000000001000", + "stateReceiverContract": "0x0000000000000000000000000000000000001001", + "overrideStateSyncRecords": null, + "blockAlloc": { + "22244000": { + "0000000000000000000000000000000000001010": { + "balance": "0x0", + "code": "0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610caa565b005b3480156103eb57600080fd5b506103f4610dfc565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e05565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610fc1565b005b3480156104e857600080fd5b506104f1611090565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b506105486110b6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506110dc565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b506106046110fd565b005b34801561061257600080fd5b5061061b6111cd565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506111d3565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b50610758611358565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af611381565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de6113d8565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e611411565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061144e565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b50610964611474565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b8101908080359060200190929190505050611501565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050611521565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a65611541565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a90611548565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb61154e565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506115db565b005b348015610b2e57600080fd5b50610b376115f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b60006040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b60003390506000610cba826110dc565b9050610cd18360065461161e90919063ffffffff16565b600681905550600083118015610ce657508234145b610d58576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610dd4876110dc565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610e0d611381565b610e1657600080fd5b600081118015610e535750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b610ea8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611da96023913960400191505060405180910390fd5b6000610eb3836110dc565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f19350505050158015610f00573d6000803e3d6000fd5b50610f168360065461163e90919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f68585610f98896110dc565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611027576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611d866023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061108c8261165d565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b611105611381565b61110e57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b60008060008060418551146111ee5760009350505050611352565b602085015192506040850151915060ff6041860151169050601b8160ff16101561121957601b810190505b601b8160ff16141580156112315750601c8160ff1614155b156112425760009350505050611352565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561129f573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561134e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600381526020017f013881000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b6000813414611460576000905061146e565b61146b338484611755565b90505b92915050565b6040518060800160405280605b8152602001611e1e605b91396040516020018082805190602001908083835b602083106114c357805182526020820191506020810190506020830392506114a0565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061153761153286868686611b12565b611be8565b9050949350505050565b6201388181565b60015481565b604051806080016040528060528152602001611dcc605291396040516020018082805190602001908083835b6020831061159d578051825260208201915060208101905060208303925061157a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b6115e3611381565b6115ec57600080fd5b6115f58161165d565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008282111561162d57600080fd5b600082840390508091505092915050565b60008082840190508381101561165357600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561169757600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117d557600080fd5b505afa1580156117e9573d6000803e3d6000fd5b505050506040513d60208110156117ff57600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561189157600080fd5b505afa1580156118a5573d6000803e3d6000fd5b505050506040513d60208110156118bb57600080fd5b810190808051906020019092919050505090506118d9868686611c32565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156119e157600080fd5b505afa1580156119f5573d6000803e3d6000fd5b505050506040513d6020811015611a0b57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a9957600080fd5b505afa158015611aad573d6000803e3d6000fd5b505050506040513d6020811015611ac357600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b6000806040518060800160405280605b8152602001611e1e605b91396040516020018082805190602001908083835b60208310611b645780518252602082019150602081019050602083039250611b41565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611cd4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f63616e27742073656e6420746f204d524332300000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611d1a573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a72315820ccd6c2a9c259832bbb367986ee06cd87af23022681b0cb22311a864b701d939564736f6c63430005100032" } } }, - "burntContract":{ - "22640000":"0x70bcA57F4579f58670aB2d18Ef16e02C17553C38" + "burntContract": { + "22640000": "0x70bcA57F4579f58670aB2d18Ef16e02C17553C38" }, - "jaipurBlock":22770000 + "jaipurBlock": 22770000, + "delhiBlock": 29638656 } }, - "nonce":"0x0", - "timestamp":"0x5ce28211", - "extraData":"0x", - "gasLimit":"0x989680", - "difficulty":"0x1", - "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase":"0x0000000000000000000000000000000000000000", - "alloc":{ - "0000000000000000000000000000000000001000":{ - "code":"0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a9190810190612b24565b610706565b60405161021e93929190613463565b60405180910390f35b610241600480360361023c9190810190612b24565b61075d565b60405161024f929190613284565b60405180910390f35b610272600480360361026d9190810190612b4d565b610939565b60405161027f91906132bb565b60405180910390f35b6102a2600480360361029d9190810190612c2c565b610a91565b005b6102be60048036036102b99190810190612b4d565b61112a565b6040516102cb91906132bb565b60405180910390f35b6102dc611281565b6040516102e99190613411565b60405180910390f35b61030c60048036036103079190810190612a81565b611286565b60405161031991906132d6565b60405180910390f35b61033c60048036036103379190810190612b24565b611307565b6040516103499190613411565b60405180910390f35b61035a611437565b6040516103679190613269565b60405180910390f35b61038a60048036036103859190810190612abd565b61144f565b60405161039791906132bb565b60405180910390f35b6103a861151a565b6040516103b591906132d6565b60405180910390f35b6103d860048036036103d39190810190612b89565b611531565b6040516103e59190613411565b60405180910390f35b61040860048036036104039190810190612b4d565b611619565b60405161041591906133f6565b60405180910390f35b610426611781565b6040516104339190613411565b60405180910390f35b61045660048036036104519190810190612a06565b611791565b60405161046391906132bb565b60405180910390f35b61048660048036036104819190810190612a2f565b6117ab565b60405161049391906132d6565b60405180910390f35b6104a4611829565b6040516104b393929190613463565b60405180910390f35b6104c461189d565b6040516104d2929190613284565b60405180910390f35b6104e3611b6e565b6040516104f09190613411565b60405180910390f35b610513600480360361050e9190810190612bf0565b611b73565b6040516105229392919061342c565b60405180910390f35b61054560048036036105409190810190612a06565b611bd7565b60405161055291906132bb565b60405180910390f35b610563611bf1565b60405161057091906132d6565b60405180910390f35b610593600480360361058e9190810190612b24565b611c08565b6040516105a09190613411565b60405180910390f35b6105b1611d39565b6040516105be91906132d6565b60405180910390f35b6105cf611d50565b6040516105de93929190613463565b60405180910390f35b61060160048036036105fc9190810190612b24565b611db1565b60405161060e9190613411565b60405180910390f35b61061f611eb1565b60405161062d929190613284565b60405180910390f35b610650600480360361064b9190810190612b24565b611ec5565b60405161065d9190613411565b60405180910390f35b61066e611ee6565b60405161067b919061349a565b60405180910390f35b61069e60048036036106999190810190612bf0565b611eeb565b6040516106ad9392919061342c565b60405180910390f35b6106be611f4f565b6040516106cb9190613411565b60405180910390f35b6106ee60048036036106e99190810190612b24565b611f61565b6040516106fd93929190613463565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107795761077061189d565b91509150610934565b600061078484611db1565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a906133d6565b60405180910390fd5b6000610b1d611781565b90506000811415610b3157610b30611f8b565b5b610b456001826122ac90919063ffffffff16565b8814610b86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7d90613356565b60405180910390fd5b868611610bc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbf906133b6565b60405180910390fd5b6000604060018989030181610bd957fe5b0614610c1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1190613396565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a90613336565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610ccc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc390613376565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d669190612800565b506000600160008a815260200190815260200160002081610d879190612800565b506060610ddf610dda87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506122cb565b6122f9565b905060008090505b8151811015610f51576060610e0e838381518110610e0157fe5b60200260200101516122f9565b90506000808c81526020019081526020016000208054809190600101610e349190612800565b506040518060600160405280610e5d83600081518110610e5057fe5b60200260200101516123d6565b8152602001610e7f83600181518110610e7257fe5b60200260200101516123d6565b8152602001610ea183600281518110610e9457fe5b6020026020010151612447565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ed757fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610de7565b506060610fa9610fa486868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506122cb565b6122f9565b905060008090505b815181101561111d576060610fd8838381518110610fcb57fe5b60200260200101516122f9565b9050600160008d81526020019081526020016000208054809190600101610fff9190612800565b5060405180606001604052806110288360008151811061101b57fe5b60200260200101516123d6565b815260200161104a8360018151811061103d57fe5b60200260200101516123d6565b815260200161106c8360028151811061105f57fe5b6020026020010151612447565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e815260200190815260200160002083815481106110a357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fb1565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111fc578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611160565b50505050905060008090505b8151811015611274578373ffffffffffffffffffffffffffffffffffffffff1682828151811061123457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112675760019250505061127b565b8080600101915050611208565b5060009150505b92915050565b604081565b60006002600160f81b84846040516020016112a3939291906131d6565b6040516020818303038152906040526040516112bf9190613213565b602060405180830381855afa1580156112dc573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112ff9190810190612a58565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113d9578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061133d565b505050509050600080905060008090505b825181101561142c5761141d83828151811061140257fe5b602002602001015160200151836122ac90919063ffffffff16565b915080806001019150506113ea565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161146657fe5b04029050600081111561147f5761147c876117ab565b91505b6000602190505b818111611509576000600182038801519050818801519550806000602081106114ab57fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114f0576114e98685611286565b93506114fd565b6114fa8487611286565b93505b50602181019050611486565b508782149450505050509392505050565b60405161152690613254565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff16101561160c57606061156e868367ffffffffffffffff16604161246a565b9050600061158582896124f690919063ffffffff16565b905061158f612832565b6115998a83611619565b90506115a58a8361112a565b80156115dc57508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115fe578194506115fb8160200151876122ac90919063ffffffff16565b95505b505050604181019050611543565b5081925050509392505050565b611621612832565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116f1578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611655565b50505050905060008090505b8151811015611779578373ffffffffffffffffffffffffffffffffffffffff1682828151811061172957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561176c5781818151811061175d57fe5b60200260200101519250611779565b80806001019150506116fd565b505092915050565b600061178c43611db1565b905090565b60006117a461179e611781565b8361112a565b9050919050565b60006002600060f81b836040516020016117c69291906131aa565b6040516020818303038152906040526040516117e29190613213565b602060405180830381855afa1580156117ff573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506118229190810190612a58565b9050919050565b60008060008061184a600161183c611781565b6122ac90919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b606080606060056040519080825280602002602001820160405280156118d25781602001602082028038833980820191505090505b50905073c26880a0af2ea0c7e8130e6ec47af756465452e8816000815181106118f757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073be188d6641e8b680743a4815dfa0f6208038960f8160018151811061195357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073c275dc8be39f50d12f66b6a63629c39da5bae5bd816002815181106119af57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073f903ba9e006193c1527bfbe65fe2123704ea3f9981600381518110611a0b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073928ed6a3e94437bbd316ccad78479f1d163a6a8c81600481518110611a6757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060606005604051908082528060200260200182016040528015611ad35781602001602082028038833980820191505090505b50905061271081600081518110611ae657fe5b60200260200101818152505061271081600181518110611b0257fe5b60200260200101818152505061271081600281518110611b1e57fe5b60200260200101818152505061271081600381518110611b3a57fe5b60200260200101818152505061271081600481518110611b5657fe5b60200260200101818152505081819350935050509091565b60ff81565b60016020528160005260406000208181548110611b8c57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000611bea611be4611781565b83610939565b9050919050565b604051611bfd9061322a565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611cdb578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611c3f565b505050509050600080905060008090505b8251811015611d2e57611d1f838281518110611d0457fe5b602002602001015160200151836122ac90919063ffffffff16565b91508080600101915050611cec565b508092505050919050565b604051611d459061323f565b604051809103902081565b600080600080611d5e611781565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b6000811115611e7157611dce612869565b6002600060036001850381548110611de257fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611e3f57506000816040015114155b8015611e4f575080604001518411155b15611e6257806000015192505050611eac565b50808060019003915050611dbd565b5060006003805490501115611ea757600360016003805490500381548110611e9557fe5b90600052602060002001549050611eac565b600090505b919050565b606080611ebd4361075d565b915091509091565b60038181548110611ed257fe5b906000526020600020016000915090505481565b600281565b60006020528160005260406000208181548110611f0457fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b600060404381611f5b57fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b606080611f9661189d565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff81525060026000838152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600381908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008381526020019081526020016000208161203f9190612800565b50600060016000838152602001908152602001600020816120609190612800565b5060008090505b83518110156121825760008083815260200190815260200160002080548091906001016120949190612800565b5060405180606001604052808281526020018483815181106120b257fe5b602002602001015181526020018583815181106120cb57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16815250600080848152602001908152602001600020828154811061210957fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612067565b5060008090505b83518110156122a6576001600083815260200190815260200160002080548091906001016121b79190612800565b5060405180606001604052808281526020018483815181106121d557fe5b602002602001015181526020018583815181106121ee57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060016000848152602001908152602001600020828154811061222d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612189565b50505050565b6000808284019050838110156122c157600080fd5b8091505092915050565b6122d361288a565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061230482612600565b61230d57600080fd5b60006123188361264e565b905060608160405190808252806020026020018201604052801561235657816020015b6123436128a4565b81526020019060019003908161233b5790505b509050600061236885602001516126bf565b8560200151019050600080600090505b848110156123c95761238983612748565b91506040518060400160405280838152602001848152508482815181106123ac57fe5b602002602001018190525081830192508080600101915050612378565b5082945050505050919050565b60008082600001511180156123f057506021826000015111155b6123f957600080fd5b600061240883602001516126bf565b9050600081846000015103905060008083866020015101905080519150602083101561243b57826020036101000a820491505b81945050505050919050565b6000601582600001511461245a57600080fd5b612463826123d6565b9050919050565b60608183018451101561247c57600080fd5b6060821560008114612499576040519150602082016040526124ea565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156124d757805183526020830192506020810190506124ba565b50868552601f19601f8301166040525050505b50809150509392505050565b600080600080604185511461251157600093505050506125fa565b602085015192506040850151915060ff6041860151169050601b8160ff16101561253c57601b810190505b601b8160ff16141580156125545750601c8160ff1614155b1561256557600093505050506125fa565b60006001878386866040516000815260200160405260405161258a94939291906132f1565b6020604051602081039080840390855afa1580156125ac573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156125f257600080fd5b809450505050505b92915050565b600080826000015114156126175760009050612649565b60008083602001519050805160001a915060c060ff168260ff16101561264257600092505050612649565b6001925050505b919050565b6000808260000151141561266557600090506126ba565b6000809050600061267984602001516126bf565b84602001510190506000846000015185602001510190505b808210156126b3576126a282612748565b820191508280600101935050612691565b8293505050505b919050565b600080825160001a9050608060ff168110156126df576000915050612743565b60b860ff16811080612704575060c060ff168110158015612703575060f860ff1681105b5b15612713576001915050612743565b60c060ff168110156127335760018060b80360ff16820301915050612743565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561276957600191506127f6565b60b860ff16811015612786576001608060ff1682030191506127f5565b60c060ff168110156127b65760b78103600185019450806020036101000a855104600182018101935050506127f4565b60f860ff168110156127d357600160c060ff1682030191506127f3565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b81548183558181111561282d5760030281600302836000526020600020918201910161282c91906128be565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b61291191905b8082111561290d5760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506003016128c4565b5090565b90565b60008135905061292381613693565b92915050565b600081359050612938816136aa565b92915050565b60008151905061294d816136aa565b92915050565b60008083601f84011261296557600080fd5b8235905067ffffffffffffffff81111561297e57600080fd5b60208301915083600182028301111561299657600080fd5b9250929050565b600082601f8301126129ae57600080fd5b81356129c16129bc826134e2565b6134b5565b915080825260208301602083018583830111156129dd57600080fd5b6129e883828461363d565b50505092915050565b600081359050612a00816136c1565b92915050565b600060208284031215612a1857600080fd5b6000612a2684828501612914565b91505092915050565b600060208284031215612a4157600080fd5b6000612a4f84828501612929565b91505092915050565b600060208284031215612a6a57600080fd5b6000612a788482850161293e565b91505092915050565b60008060408385031215612a9457600080fd5b6000612aa285828601612929565b9250506020612ab385828601612929565b9150509250929050565b600080600060608486031215612ad257600080fd5b6000612ae086828701612929565b9350506020612af186828701612929565b925050604084013567ffffffffffffffff811115612b0e57600080fd5b612b1a8682870161299d565b9150509250925092565b600060208284031215612b3657600080fd5b6000612b44848285016129f1565b91505092915050565b60008060408385031215612b6057600080fd5b6000612b6e858286016129f1565b9250506020612b7f85828601612914565b9150509250929050565b600080600060608486031215612b9e57600080fd5b6000612bac868287016129f1565b9350506020612bbd86828701612929565b925050604084013567ffffffffffffffff811115612bda57600080fd5b612be68682870161299d565b9150509250925092565b60008060408385031215612c0357600080fd5b6000612c11858286016129f1565b9250506020612c22858286016129f1565b9150509250929050565b600080600080600080600060a0888a031215612c4757600080fd5b6000612c558a828b016129f1565b9750506020612c668a828b016129f1565b9650506040612c778a828b016129f1565b955050606088013567ffffffffffffffff811115612c9457600080fd5b612ca08a828b01612953565b9450945050608088013567ffffffffffffffff811115612cbf57600080fd5b612ccb8a828b01612953565b925092505092959891949750929550565b6000612ce88383612d0c565b60208301905092915050565b6000612d00838361317d565b60208301905092915050565b612d15816135b2565b82525050565b612d24816135b2565b82525050565b6000612d358261352e565b612d3f8185613569565b9350612d4a8361350e565b8060005b83811015612d7b578151612d628882612cdc565b9750612d6d8361354f565b925050600181019050612d4e565b5085935050505092915050565b6000612d9382613539565b612d9d818561357a565b9350612da88361351e565b8060005b83811015612dd9578151612dc08882612cf4565b9750612dcb8361355c565b925050600181019050612dac565b5085935050505092915050565b612def816135c4565b82525050565b612e06612e01826135d0565b61367f565b82525050565b612e15816135fc565b82525050565b612e2c612e27826135fc565b613689565b82525050565b6000612e3d82613544565b612e47818561358b565b9350612e5781856020860161364c565b80840191505092915050565b6000612e706004836135a7565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000612eb0602d83613596565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000612f16600f83613596565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000612f56601383613596565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000612f96604583613596565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000613022602a83613596565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000613088601283613596565b91507f4e6f742053797374656d204164646573732100000000000000000000000000006000830152602082019050919050565b60006130c86005836135a7565b91507f38303030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b6000613108600e836135a7565b91507f6865696d64616c6c2d38303030310000000000000000000000000000000000006000830152600e82019050919050565b606082016000820151613151600085018261317d565b506020820151613164602085018261317d565b5060408201516131776040850182612d0c565b50505050565b61318681613626565b82525050565b61319581613626565b82525050565b6131a481613630565b82525050565b60006131b68285612df5565b6001820191506131c68284612e1b565b6020820191508190509392505050565b60006131e28286612df5565b6001820191506131f28285612e1b565b6020820191506132028284612e1b565b602082019150819050949350505050565b600061321f8284612e32565b915081905092915050565b600061323582612e63565b9150819050919050565b600061324a826130bb565b9150819050919050565b600061325f826130fb565b9150819050919050565b600060208201905061327e6000830184612d1b565b92915050565b6000604082019050818103600083015261329e8185612d2a565b905081810360208301526132b28184612d88565b90509392505050565b60006020820190506132d06000830184612de6565b92915050565b60006020820190506132eb6000830184612e0c565b92915050565b60006080820190506133066000830187612e0c565b613313602083018661319b565b6133206040830185612e0c565b61332d6060830184612e0c565b95945050505050565b6000602082019050818103600083015261334f81612ea3565b9050919050565b6000602082019050818103600083015261336f81612f09565b9050919050565b6000602082019050818103600083015261338f81612f49565b9050919050565b600060208201905081810360008301526133af81612f89565b9050919050565b600060208201905081810360008301526133cf81613015565b9050919050565b600060208201905081810360008301526133ef8161307b565b9050919050565b600060608201905061340b600083018461313b565b92915050565b6000602082019050613426600083018461318c565b92915050565b6000606082019050613441600083018661318c565b61344e602083018561318c565b61345b6040830184612d1b565b949350505050565b6000606082019050613478600083018661318c565b613485602083018561318c565b613492604083018461318c565b949350505050565b60006020820190506134af600083018461319b565b92915050565b6000604051905081810181811067ffffffffffffffff821117156134d857600080fd5b8060405250919050565b600067ffffffffffffffff8211156134f957600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006135bd82613606565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b8381101561366a57808201518184015260208101905061364f565b83811115613679576000848401525b50505050565b6000819050919050565b6000819050919050565b61369c816135b2565b81146136a757600080fd5b50565b6136b3816135fc565b81146136be57600080fd5b50565b6136ca81613626565b81146136d557600080fd5b5056fea365627a7a723158208f52ee07630ffe523cc6ad3e15f437f973dcfa36729cd697f9b0fc4a145a48f06c6578706572696d656e74616cf564736f6c634300050b0040", - "balance":"0x0" + "nonce": "0x0", + "timestamp": "0x5ce28211", + "extraData": "0x", + "gasLimit": "0x989680", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000001000": { + "code": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a9190810190612b24565b610706565b60405161021e93929190613463565b60405180910390f35b610241600480360361023c9190810190612b24565b61075d565b60405161024f929190613284565b60405180910390f35b610272600480360361026d9190810190612b4d565b610939565b60405161027f91906132bb565b60405180910390f35b6102a2600480360361029d9190810190612c2c565b610a91565b005b6102be60048036036102b99190810190612b4d565b61112a565b6040516102cb91906132bb565b60405180910390f35b6102dc611281565b6040516102e99190613411565b60405180910390f35b61030c60048036036103079190810190612a81565b611286565b60405161031991906132d6565b60405180910390f35b61033c60048036036103379190810190612b24565b611307565b6040516103499190613411565b60405180910390f35b61035a611437565b6040516103679190613269565b60405180910390f35b61038a60048036036103859190810190612abd565b61144f565b60405161039791906132bb565b60405180910390f35b6103a861151a565b6040516103b591906132d6565b60405180910390f35b6103d860048036036103d39190810190612b89565b611531565b6040516103e59190613411565b60405180910390f35b61040860048036036104039190810190612b4d565b611619565b60405161041591906133f6565b60405180910390f35b610426611781565b6040516104339190613411565b60405180910390f35b61045660048036036104519190810190612a06565b611791565b60405161046391906132bb565b60405180910390f35b61048660048036036104819190810190612a2f565b6117ab565b60405161049391906132d6565b60405180910390f35b6104a4611829565b6040516104b393929190613463565b60405180910390f35b6104c461189d565b6040516104d2929190613284565b60405180910390f35b6104e3611b6e565b6040516104f09190613411565b60405180910390f35b610513600480360361050e9190810190612bf0565b611b73565b6040516105229392919061342c565b60405180910390f35b61054560048036036105409190810190612a06565b611bd7565b60405161055291906132bb565b60405180910390f35b610563611bf1565b60405161057091906132d6565b60405180910390f35b610593600480360361058e9190810190612b24565b611c08565b6040516105a09190613411565b60405180910390f35b6105b1611d39565b6040516105be91906132d6565b60405180910390f35b6105cf611d50565b6040516105de93929190613463565b60405180910390f35b61060160048036036105fc9190810190612b24565b611db1565b60405161060e9190613411565b60405180910390f35b61061f611eb1565b60405161062d929190613284565b60405180910390f35b610650600480360361064b9190810190612b24565b611ec5565b60405161065d9190613411565b60405180910390f35b61066e611ee6565b60405161067b919061349a565b60405180910390f35b61069e60048036036106999190810190612bf0565b611eeb565b6040516106ad9392919061342c565b60405180910390f35b6106be611f4f565b6040516106cb9190613411565b60405180910390f35b6106ee60048036036106e99190810190612b24565b611f61565b6040516106fd93929190613463565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107795761077061189d565b91509150610934565b600061078484611db1565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a906133d6565b60405180910390fd5b6000610b1d611781565b90506000811415610b3157610b30611f8b565b5b610b456001826122ac90919063ffffffff16565b8814610b86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7d90613356565b60405180910390fd5b868611610bc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbf906133b6565b60405180910390fd5b6000604060018989030181610bd957fe5b0614610c1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1190613396565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a90613336565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610ccc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc390613376565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d669190612800565b506000600160008a815260200190815260200160002081610d879190612800565b506060610ddf610dda87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506122cb565b6122f9565b905060008090505b8151811015610f51576060610e0e838381518110610e0157fe5b60200260200101516122f9565b90506000808c81526020019081526020016000208054809190600101610e349190612800565b506040518060600160405280610e5d83600081518110610e5057fe5b60200260200101516123d6565b8152602001610e7f83600181518110610e7257fe5b60200260200101516123d6565b8152602001610ea183600281518110610e9457fe5b6020026020010151612447565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ed757fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610de7565b506060610fa9610fa486868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506122cb565b6122f9565b905060008090505b815181101561111d576060610fd8838381518110610fcb57fe5b60200260200101516122f9565b9050600160008d81526020019081526020016000208054809190600101610fff9190612800565b5060405180606001604052806110288360008151811061101b57fe5b60200260200101516123d6565b815260200161104a8360018151811061103d57fe5b60200260200101516123d6565b815260200161106c8360028151811061105f57fe5b6020026020010151612447565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e815260200190815260200160002083815481106110a357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fb1565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111fc578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611160565b50505050905060008090505b8151811015611274578373ffffffffffffffffffffffffffffffffffffffff1682828151811061123457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112675760019250505061127b565b8080600101915050611208565b5060009150505b92915050565b604081565b60006002600160f81b84846040516020016112a3939291906131d6565b6040516020818303038152906040526040516112bf9190613213565b602060405180830381855afa1580156112dc573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112ff9190810190612a58565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113d9578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061133d565b505050509050600080905060008090505b825181101561142c5761141d83828151811061140257fe5b602002602001015160200151836122ac90919063ffffffff16565b915080806001019150506113ea565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161146657fe5b04029050600081111561147f5761147c876117ab565b91505b6000602190505b818111611509576000600182038801519050818801519550806000602081106114ab57fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114f0576114e98685611286565b93506114fd565b6114fa8487611286565b93505b50602181019050611486565b508782149450505050509392505050565b60405161152690613254565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff16101561160c57606061156e868367ffffffffffffffff16604161246a565b9050600061158582896124f690919063ffffffff16565b905061158f612832565b6115998a83611619565b90506115a58a8361112a565b80156115dc57508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115fe578194506115fb8160200151876122ac90919063ffffffff16565b95505b505050604181019050611543565b5081925050509392505050565b611621612832565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116f1578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611655565b50505050905060008090505b8151811015611779578373ffffffffffffffffffffffffffffffffffffffff1682828151811061172957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561176c5781818151811061175d57fe5b60200260200101519250611779565b80806001019150506116fd565b505092915050565b600061178c43611db1565b905090565b60006117a461179e611781565b8361112a565b9050919050565b60006002600060f81b836040516020016117c69291906131aa565b6040516020818303038152906040526040516117e29190613213565b602060405180830381855afa1580156117ff573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506118229190810190612a58565b9050919050565b60008060008061184a600161183c611781565b6122ac90919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b606080606060056040519080825280602002602001820160405280156118d25781602001602082028038833980820191505090505b50905073c26880a0af2ea0c7e8130e6ec47af756465452e8816000815181106118f757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073be188d6641e8b680743a4815dfa0f6208038960f8160018151811061195357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073c275dc8be39f50d12f66b6a63629c39da5bae5bd816002815181106119af57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073f903ba9e006193c1527bfbe65fe2123704ea3f9981600381518110611a0b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073928ed6a3e94437bbd316ccad78479f1d163a6a8c81600481518110611a6757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060606005604051908082528060200260200182016040528015611ad35781602001602082028038833980820191505090505b50905061271081600081518110611ae657fe5b60200260200101818152505061271081600181518110611b0257fe5b60200260200101818152505061271081600281518110611b1e57fe5b60200260200101818152505061271081600381518110611b3a57fe5b60200260200101818152505061271081600481518110611b5657fe5b60200260200101818152505081819350935050509091565b60ff81565b60016020528160005260406000208181548110611b8c57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000611bea611be4611781565b83610939565b9050919050565b604051611bfd9061322a565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611cdb578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611c3f565b505050509050600080905060008090505b8251811015611d2e57611d1f838281518110611d0457fe5b602002602001015160200151836122ac90919063ffffffff16565b91508080600101915050611cec565b508092505050919050565b604051611d459061323f565b604051809103902081565b600080600080611d5e611781565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b6000811115611e7157611dce612869565b6002600060036001850381548110611de257fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611e3f57506000816040015114155b8015611e4f575080604001518411155b15611e6257806000015192505050611eac565b50808060019003915050611dbd565b5060006003805490501115611ea757600360016003805490500381548110611e9557fe5b90600052602060002001549050611eac565b600090505b919050565b606080611ebd4361075d565b915091509091565b60038181548110611ed257fe5b906000526020600020016000915090505481565b600281565b60006020528160005260406000208181548110611f0457fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b600060404381611f5b57fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b606080611f9661189d565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff81525060026000838152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600381908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008381526020019081526020016000208161203f9190612800565b50600060016000838152602001908152602001600020816120609190612800565b5060008090505b83518110156121825760008083815260200190815260200160002080548091906001016120949190612800565b5060405180606001604052808281526020018483815181106120b257fe5b602002602001015181526020018583815181106120cb57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16815250600080848152602001908152602001600020828154811061210957fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612067565b5060008090505b83518110156122a6576001600083815260200190815260200160002080548091906001016121b79190612800565b5060405180606001604052808281526020018483815181106121d557fe5b602002602001015181526020018583815181106121ee57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060016000848152602001908152602001600020828154811061222d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612189565b50505050565b6000808284019050838110156122c157600080fd5b8091505092915050565b6122d361288a565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061230482612600565b61230d57600080fd5b60006123188361264e565b905060608160405190808252806020026020018201604052801561235657816020015b6123436128a4565b81526020019060019003908161233b5790505b509050600061236885602001516126bf565b8560200151019050600080600090505b848110156123c95761238983612748565b91506040518060400160405280838152602001848152508482815181106123ac57fe5b602002602001018190525081830192508080600101915050612378565b5082945050505050919050565b60008082600001511180156123f057506021826000015111155b6123f957600080fd5b600061240883602001516126bf565b9050600081846000015103905060008083866020015101905080519150602083101561243b57826020036101000a820491505b81945050505050919050565b6000601582600001511461245a57600080fd5b612463826123d6565b9050919050565b60608183018451101561247c57600080fd5b6060821560008114612499576040519150602082016040526124ea565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156124d757805183526020830192506020810190506124ba565b50868552601f19601f8301166040525050505b50809150509392505050565b600080600080604185511461251157600093505050506125fa565b602085015192506040850151915060ff6041860151169050601b8160ff16101561253c57601b810190505b601b8160ff16141580156125545750601c8160ff1614155b1561256557600093505050506125fa565b60006001878386866040516000815260200160405260405161258a94939291906132f1565b6020604051602081039080840390855afa1580156125ac573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156125f257600080fd5b809450505050505b92915050565b600080826000015114156126175760009050612649565b60008083602001519050805160001a915060c060ff168260ff16101561264257600092505050612649565b6001925050505b919050565b6000808260000151141561266557600090506126ba565b6000809050600061267984602001516126bf565b84602001510190506000846000015185602001510190505b808210156126b3576126a282612748565b820191508280600101935050612691565b8293505050505b919050565b600080825160001a9050608060ff168110156126df576000915050612743565b60b860ff16811080612704575060c060ff168110158015612703575060f860ff1681105b5b15612713576001915050612743565b60c060ff168110156127335760018060b80360ff16820301915050612743565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561276957600191506127f6565b60b860ff16811015612786576001608060ff1682030191506127f5565b60c060ff168110156127b65760b78103600185019450806020036101000a855104600182018101935050506127f4565b60f860ff168110156127d357600160c060ff1682030191506127f3565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b81548183558181111561282d5760030281600302836000526020600020918201910161282c91906128be565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b61291191905b8082111561290d5760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506003016128c4565b5090565b90565b60008135905061292381613693565b92915050565b600081359050612938816136aa565b92915050565b60008151905061294d816136aa565b92915050565b60008083601f84011261296557600080fd5b8235905067ffffffffffffffff81111561297e57600080fd5b60208301915083600182028301111561299657600080fd5b9250929050565b600082601f8301126129ae57600080fd5b81356129c16129bc826134e2565b6134b5565b915080825260208301602083018583830111156129dd57600080fd5b6129e883828461363d565b50505092915050565b600081359050612a00816136c1565b92915050565b600060208284031215612a1857600080fd5b6000612a2684828501612914565b91505092915050565b600060208284031215612a4157600080fd5b6000612a4f84828501612929565b91505092915050565b600060208284031215612a6a57600080fd5b6000612a788482850161293e565b91505092915050565b60008060408385031215612a9457600080fd5b6000612aa285828601612929565b9250506020612ab385828601612929565b9150509250929050565b600080600060608486031215612ad257600080fd5b6000612ae086828701612929565b9350506020612af186828701612929565b925050604084013567ffffffffffffffff811115612b0e57600080fd5b612b1a8682870161299d565b9150509250925092565b600060208284031215612b3657600080fd5b6000612b44848285016129f1565b91505092915050565b60008060408385031215612b6057600080fd5b6000612b6e858286016129f1565b9250506020612b7f85828601612914565b9150509250929050565b600080600060608486031215612b9e57600080fd5b6000612bac868287016129f1565b9350506020612bbd86828701612929565b925050604084013567ffffffffffffffff811115612bda57600080fd5b612be68682870161299d565b9150509250925092565b60008060408385031215612c0357600080fd5b6000612c11858286016129f1565b9250506020612c22858286016129f1565b9150509250929050565b600080600080600080600060a0888a031215612c4757600080fd5b6000612c558a828b016129f1565b9750506020612c668a828b016129f1565b9650506040612c778a828b016129f1565b955050606088013567ffffffffffffffff811115612c9457600080fd5b612ca08a828b01612953565b9450945050608088013567ffffffffffffffff811115612cbf57600080fd5b612ccb8a828b01612953565b925092505092959891949750929550565b6000612ce88383612d0c565b60208301905092915050565b6000612d00838361317d565b60208301905092915050565b612d15816135b2565b82525050565b612d24816135b2565b82525050565b6000612d358261352e565b612d3f8185613569565b9350612d4a8361350e565b8060005b83811015612d7b578151612d628882612cdc565b9750612d6d8361354f565b925050600181019050612d4e565b5085935050505092915050565b6000612d9382613539565b612d9d818561357a565b9350612da88361351e565b8060005b83811015612dd9578151612dc08882612cf4565b9750612dcb8361355c565b925050600181019050612dac565b5085935050505092915050565b612def816135c4565b82525050565b612e06612e01826135d0565b61367f565b82525050565b612e15816135fc565b82525050565b612e2c612e27826135fc565b613689565b82525050565b6000612e3d82613544565b612e47818561358b565b9350612e5781856020860161364c565b80840191505092915050565b6000612e706004836135a7565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000612eb0602d83613596565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000612f16600f83613596565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000612f56601383613596565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000612f96604583613596565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000613022602a83613596565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000613088601283613596565b91507f4e6f742053797374656d204164646573732100000000000000000000000000006000830152602082019050919050565b60006130c86005836135a7565b91507f38303030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b6000613108600e836135a7565b91507f6865696d64616c6c2d38303030310000000000000000000000000000000000006000830152600e82019050919050565b606082016000820151613151600085018261317d565b506020820151613164602085018261317d565b5060408201516131776040850182612d0c565b50505050565b61318681613626565b82525050565b61319581613626565b82525050565b6131a481613630565b82525050565b60006131b68285612df5565b6001820191506131c68284612e1b565b6020820191508190509392505050565b60006131e28286612df5565b6001820191506131f28285612e1b565b6020820191506132028284612e1b565b602082019150819050949350505050565b600061321f8284612e32565b915081905092915050565b600061323582612e63565b9150819050919050565b600061324a826130bb565b9150819050919050565b600061325f826130fb565b9150819050919050565b600060208201905061327e6000830184612d1b565b92915050565b6000604082019050818103600083015261329e8185612d2a565b905081810360208301526132b28184612d88565b90509392505050565b60006020820190506132d06000830184612de6565b92915050565b60006020820190506132eb6000830184612e0c565b92915050565b60006080820190506133066000830187612e0c565b613313602083018661319b565b6133206040830185612e0c565b61332d6060830184612e0c565b95945050505050565b6000602082019050818103600083015261334f81612ea3565b9050919050565b6000602082019050818103600083015261336f81612f09565b9050919050565b6000602082019050818103600083015261338f81612f49565b9050919050565b600060208201905081810360008301526133af81612f89565b9050919050565b600060208201905081810360008301526133cf81613015565b9050919050565b600060208201905081810360008301526133ef8161307b565b9050919050565b600060608201905061340b600083018461313b565b92915050565b6000602082019050613426600083018461318c565b92915050565b6000606082019050613441600083018661318c565b61344e602083018561318c565b61345b6040830184612d1b565b949350505050565b6000606082019050613478600083018661318c565b613485602083018561318c565b613492604083018461318c565b949350505050565b60006020820190506134af600083018461319b565b92915050565b6000604051905081810181811067ffffffffffffffff821117156134d857600080fd5b8060405250919050565b600067ffffffffffffffff8211156134f957600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006135bd82613606565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b8381101561366a57808201518184015260208101905061364f565b83811115613679576000848401525b50505050565b6000819050919050565b6000819050919050565b61369c816135b2565b81146136a757600080fd5b50565b6136b3816135fc565b81146136be57600080fd5b50565b6136ca81613626565b81146136d557600080fd5b5056fea365627a7a723158208f52ee07630ffe523cc6ad3e15f437f973dcfa36729cd697f9b0fc4a145a48f06c6578706572696d656e74616cf564736f6c634300050b0040", + "balance": "0x0" }, - "0000000000000000000000000000000000001001":{ - "code":"0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a7231582083fbdacb76f32b4112d0f7db9a596937925824798a0026ba0232322390b5263764736f6c634300050b0032", - "balance":"0x0" + "0000000000000000000000000000000000001001": { + "code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a7231582083fbdacb76f32b4112d0f7db9a596937925824798a0026ba0232322390b5263764736f6c634300050b0032", + "balance": "0x0" }, - "0000000000000000000000000000000000001010":{ - "code":"0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a4565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116aa565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611737565b005b348015610b2e57600080fd5b50610b37611754565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa82848861177a565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3790919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e636023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5790919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e406023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b76565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600381526020017f013881000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c733848461177a565b90505b92915050565b6040518060800160405280605b8152602001611ed8605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6e565b611d44565b9050949350505050565b6201388181565b60015481565b604051806080016040528060528152602001611e86605291396040516020018082805190602001908083835b602083106116f957805182526020820191506020810190506020830392506116d6565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173f6114dd565b61174857600080fd5b61175181611b76565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117fa57600080fd5b505afa15801561180e573d6000803e3d6000fd5b505050506040513d602081101561182457600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b657600080fd5b505afa1580156118ca573d6000803e3d6000fd5b505050506040513d60208110156118e057600080fd5b810190808051906020019092919050505090506118fe868686611d8e565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0657600080fd5b505afa158015611a1a573d6000803e3d6000fd5b505050506040513d6020811015611a3057600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abe57600080fd5b505afa158015611ad2573d6000803e3d6000fd5b505050506040513d6020811015611ae857600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4657600080fd5b600082840390508091505092915050565b600080828401905083811015611b6c57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611bb057600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611ed8605b91396040516020018082805190602001908083835b60208310611cc05780518252602082019150602081019050602083039250611c9d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611dd4573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a723158208f81700133738d766ae3d68af591ad588b0125bd91449192179f460893f79f6b64736f6c634300050b0032", - "balance":"0x204fcd4f31349d83b6e00000" + "0000000000000000000000000000000000001010": { + "code": "0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a4565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116aa565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611737565b005b348015610b2e57600080fd5b50610b37611754565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa82848861177a565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3790919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e636023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5790919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e406023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b76565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600381526020017f013881000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c733848461177a565b90505b92915050565b6040518060800160405280605b8152602001611ed8605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6e565b611d44565b9050949350505050565b6201388181565b60015481565b604051806080016040528060528152602001611e86605291396040516020018082805190602001908083835b602083106116f957805182526020820191506020810190506020830392506116d6565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173f6114dd565b61174857600080fd5b61175181611b76565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117fa57600080fd5b505afa15801561180e573d6000803e3d6000fd5b505050506040513d602081101561182457600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b657600080fd5b505afa1580156118ca573d6000803e3d6000fd5b505050506040513d60208110156118e057600080fd5b810190808051906020019092919050505090506118fe868686611d8e565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0657600080fd5b505afa158015611a1a573d6000803e3d6000fd5b505050506040513d6020811015611a3057600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abe57600080fd5b505afa158015611ad2573d6000803e3d6000fd5b505050506040513d6020811015611ae857600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4657600080fd5b600082840390508091505092915050565b600080828401905083811015611b6c57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611bb057600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611ed8605b91396040516020018082805190602001908083835b60208310611cc05780518252602082019150602081019050602083039250611c9d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611dd4573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a723158208f81700133738d766ae3d68af591ad588b0125bd91449192179f460893f79f6b64736f6c634300050b0032", + "balance": "0x204fcd4f31349d83b6e00000" }, - "928ed6a3e94437bbd316ccad78479f1d163a6a8c":{ - "balance":"0x3635c9adc5dea00000" + "928ed6a3e94437bbd316ccad78479f1d163a6a8c": { + "balance": "0x3635c9adc5dea00000" }, - "be188d6641e8b680743a4815dfa0f6208038960f":{ - "balance":"0x3635c9adc5dea00000" + "be188d6641e8b680743a4815dfa0f6208038960f": { + "balance": "0x3635c9adc5dea00000" }, - "c26880a0af2ea0c7e8130e6ec47af756465452e8":{ - "balance":"0x3635c9adc5dea00000" + "c26880a0af2ea0c7e8130e6ec47af756465452e8": { + "balance": "0x3635c9adc5dea00000" }, - "c275dc8be39f50d12f66b6a63629c39da5bae5bd":{ - "balance":"0x3635c9adc5dea00000" + "c275dc8be39f50d12f66b6a63629c39da5bae5bd": { + "balance": "0x3635c9adc5dea00000" }, - "f903ba9e006193c1527bfbe65fe2123704ea3f99":{ - "balance":"0x3635c9adc5dea00000" + "f903ba9e006193c1527bfbe65fe2123704ea3f99": { + "balance": "0x3635c9adc5dea00000" } }, - "number":"0x0", - "gasUsed":"0x0", - "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", - "baseFeePerGas":null + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": null } diff --git a/internal/cli/server/chains/test_files/chain_test.json b/internal/cli/server/chains/test_files/chain_test.json index 5bfe155d27..7907adfcfa 100644 --- a/internal/cli/server/chains/test_files/chain_test.json +++ b/internal/cli/server/chains/test_files/chain_test.json @@ -18,12 +18,22 @@ "londonBlock":13996000, "bor":{ "period":{ - "0":2 + "0":2, + "25275000": 5, + "29638656": 2 + }, + "producerDelay":{ + "0": 6, + "29638656": 4 + }, + "sprint":{ + "0": 64, + "29638656": 16 }, - "producerDelay":6, - "sprint":64, "backupMultiplier":{ - "0":2 + "0": 2, + "25275000": 5, + "29638656": 2 }, "validatorContract":"0x0000000000000000000000000000000000001000", "stateReceiverContract":"0x0000000000000000000000000000000000001001", @@ -39,7 +49,8 @@ "burntContract":{ "22640000":"0x70bcA57F4579f58670aB2d18Ef16e02C17553C38" }, - "jaipurBlock":22770000 + "jaipurBlock":22770000, + "delhiBlock": 29638656 } }, "nonce":"0x0", diff --git a/internal/cli/server/command.go b/internal/cli/server/command.go index 2995f10f69..3386735507 100644 --- a/internal/cli/server/command.go +++ b/internal/cli/server/command.go @@ -41,7 +41,7 @@ func (c *Command) MarkDown() string { // Help implements the cli.Command interface func (c *Command) Help() string { return `Usage: bor [options] - + Run the Bor server. ` + c.Flags().Help() } @@ -72,7 +72,7 @@ func (c *Command) extractFlags(args []string) error { } // read if config file is provided, this will overwrite the cli flags, if provided if c.configFile != "" { - log.Warn("Config File provided, this will overwrite the cli flags.", "configFile:", c.configFile) + log.Warn("Config File provided, this will overwrite the cli flags", "path", c.configFile) cfg, err := readConfigFile(c.configFile) if err != nil { c.UI.Error(err.Error()) @@ -101,7 +101,7 @@ func (c *Command) Run(args []string) int { return 1 } - srv, err := NewServer(c.config) + srv, err := NewServer(c.config, WithGRPCAddress()) if err != nil { c.UI.Error(err.Error()) return 1 diff --git a/internal/cli/server/config.go b/internal/cli/server/config.go index 5657e85b20..1ab0a83712 100644 --- a/internal/cli/server/config.go +++ b/internal/cli/server/config.go @@ -161,6 +161,9 @@ type HeimdallConfig struct { // Without is used to disable remote heimdall during testing Without bool `hcl:"bor.without,optional" toml:"bor.without,optional"` + + // GRPCAddress is the address of the heimdall grpc server + GRPCAddress string `hcl:"grpc-address,optional" toml:"grpc-address,optional"` } type TxPoolConfig struct { @@ -398,6 +401,8 @@ type CacheConfig struct { // TxLookupLimit sets the maximum number of blocks from head whose tx indices are reserved. TxLookupLimit uint64 `hcl:"txlookuplimit,optional" toml:"txlookuplimit,optional"` + // Number of block states to keep in memory (default = 128) + TriesInMemory uint64 `hcl:"triesinmemory,optional" toml:"triesinmemory,optional"` // Time after which the Merkle Patricia Trie is stored to disc from memory TrieTimeout time.Duration `hcl:"-,optional" toml:"-"` TrieTimeoutRaw string `hcl:"timeout,optional" toml:"timeout,optional"` @@ -454,8 +459,9 @@ func DefaultConfig() *Config { }, }, Heimdall: &HeimdallConfig{ - URL: "http://localhost:1317", - Without: false, + URL: "http://localhost:1317", + Without: false, + GRPCAddress: "", }, SyncMode: "full", GcMode: "full", @@ -550,6 +556,7 @@ func DefaultConfig() *Config { NoPrefetch: false, Preimages: false, TxLookupLimit: 2350000, + TriesInMemory: 128, TrieTimeout: 60 * time.Minute, }, Accounts: &AccountsConfig{ @@ -695,6 +702,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (* n.HeimdallURL = c.Heimdall.URL n.WithoutHeimdall = c.Heimdall.Without + n.HeimdallgRPCAddress = c.Heimdall.GRPCAddress // gas price oracle { diff --git a/internal/cli/server/config_legacy.go b/internal/cli/server/config_legacy.go index 9411b8290d..ccc05eb4a7 100644 --- a/internal/cli/server/config_legacy.go +++ b/internal/cli/server/config_legacy.go @@ -2,13 +2,13 @@ package server import ( "fmt" - "io/ioutil" + "os" "github.com/BurntSushi/toml" ) func readLegacyConfig(path string) (*Config, error) { - data, err := ioutil.ReadFile(path) + data, err := os.ReadFile(path) tomlData := string(data) if err != nil { diff --git a/internal/cli/server/flags.go b/internal/cli/server/flags.go index a53e1c3e46..30cdb92b04 100644 --- a/internal/cli/server/flags.go +++ b/internal/cli/server/flags.go @@ -92,6 +92,12 @@ func (c *Command) Flags() *flagset.Flagset { Value: &c.cliConfig.Heimdall.Without, Default: c.cliConfig.Heimdall.Without, }) + f.StringFlag(&flagset.StringFlag{ + Name: "bor.heimdallgRPC", + Usage: "Address of Heimdall gRPC service", + Value: &c.cliConfig.Heimdall.GRPCAddress, + Default: c.cliConfig.Heimdall.GRPCAddress, + }) // txpool options f.SliceStringFlag(&flagset.SliceStringFlag{ @@ -304,6 +310,13 @@ func (c *Command) Flags() *flagset.Flagset { Default: c.cliConfig.Cache.Preimages, Group: "Cache", }) + f.Uint64Flag(&flagset.Uint64Flag{ + Name: "cache.triesinmemory", + Usage: "Number of block states (tries) to keep in memory (default = 128)", + Value: &c.cliConfig.Cache.TriesInMemory, + Default: c.cliConfig.Cache.TriesInMemory, + Group: "Cache", + }) f.Uint64Flag(&flagset.Uint64Flag{ Name: "txlookuplimit", Usage: "Number of recent blocks to maintain transactions index for (default = about 56 days, 0 = entire chain)", diff --git a/internal/cli/server/helper.go b/internal/cli/server/helper.go index 3a232d3185..97c49dcad3 100644 --- a/internal/cli/server/helper.go +++ b/internal/cli/server/helper.go @@ -2,76 +2,36 @@ package server import ( "fmt" - "io/ioutil" - "math/rand" - "net" "os" - "sync/atomic" - "time" + + "github.com/ethereum/go-ethereum/common/network" ) -var maxPortCheck int32 = 100 - -// findAvailablePort returns the next available port starting from `from` -func findAvailablePort(from int32, count int32) (int32, error) { - if count == maxPortCheck { - return 0, fmt.Errorf("no available port found") - } - - port := atomic.AddInt32(&from, 1) - addr := fmt.Sprintf("localhost:%d", port) - - count++ - - lis, err := net.Listen("tcp", addr) - if err == nil { - lis.Close() - return port, nil - } else { - return findAvailablePort(from, count) - } -} - func CreateMockServer(config *Config) (*Server, error) { if config == nil { config = DefaultConfig() } - // find available port for grpc server - rand.Seed(time.Now().UnixNano()) - - var ( - from int32 = 60000 // the min port to start checking from - to int32 = 61000 // the max port to start checking from - ) - - //nolint: gosec - port, err := findAvailablePort(rand.Int31n(to-from+1)+from, 0) + // get grpc port and listener + grpcPort, gRPCListener, err := network.FindAvailablePort() if err != nil { return nil, err } - // grpc port - config.GRPC.Addr = fmt.Sprintf(":%d", port) + // The test uses grpc port from config so setting it here. + config.GRPC.Addr = fmt.Sprintf(":%d", grpcPort) // datadir - datadir, _ := ioutil.TempDir("/tmp", "bor-cli-test") - config.DataDir = datadir - - // find available port for http server - from = 8545 - to = 9545 - - //nolint: gosec - port, err = findAvailablePort(rand.Int31n(to-from+1)+from, 0) + datadir, err := os.MkdirTemp("", "bor-cli-test") if err != nil { return nil, err } - config.JsonRPC.Http.Port = uint64(port) + config.DataDir = datadir + config.JsonRPC.Http.Port = 0 // It will choose a free/available port // start the server - return NewServer(config) + return NewServer(config, WithGRPCListener(gRPCListener)) } func CloseMockServer(server *Server) { diff --git a/internal/cli/server/server.go b/internal/cli/server/server.go index 70187d6985..f0cea4de06 100644 --- a/internal/cli/server/server.go +++ b/internal/cli/server/server.go @@ -23,8 +23,8 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/consensus/beacon" - "github.com/ethereum/go-ethereum/consensus/bor" + "github.com/ethereum/go-ethereum/consensus/beacon" //nolint:typecheck + "github.com/ethereum/go-ethereum/consensus/bor" //nolint:typecheck "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/tracers" @@ -54,7 +54,22 @@ type Server struct { tracerAPI *tracers.API } -func NewServer(config *Config) (*Server, error) { +type serverOption func(srv *Server, config *Config) error + +func WithGRPCAddress() serverOption { + return func(srv *Server, config *Config) error { + return srv.gRPCServerByAddress(config.GRPC.Addr) + } +} + +func WithGRPCListener(lis net.Listener) serverOption { + return func(srv *Server, _ *Config) error { + return srv.gRPCServerByListener(lis) + } +} + +//nolint:gocognit +func NewServer(config *Config, opts ...serverOption) (*Server, error) { srv := &Server{ config: config, } @@ -62,12 +77,17 @@ func NewServer(config *Config) (*Server, error) { // start the logger setupLogger(config.LogLevel) - if err := srv.setupGRPCServer(config.GRPC.Addr); err != nil { - return nil, err + var err error + + for _, opt := range opts { + err = opt(srv, config) + if err != nil { + return nil, err + } } // load the chain genesis - if err := config.loadChain(); err != nil { + if err = config.loadChain(); err != nil { return nil, err } @@ -155,7 +175,6 @@ func NewServer(config *Config) (*Server, error) { wallet, err := accountManager.Find(accounts.Account{Address: eb}) if wallet == nil || err != nil { log.Error("Etherbase account unavailable locally", "err", err) - return nil, fmt.Errorf("signer missing: %v", err) } @@ -221,8 +240,13 @@ func NewServer(config *Config) (*Server, error) { } func (s *Server) Stop() { - s.node.Close() - s.grpcServer.Stop() + if s.node != nil { + s.node.Close() + } + + if s.grpcServer != nil { + s.grpcServer.Stop() + } // shutdown the tracer if s.tracer != nil { @@ -351,22 +375,26 @@ func (s *Server) setupMetrics(config *TelemetryConfig, serviceName string) error return nil } -func (s *Server) setupGRPCServer(addr string) error { - s.grpcServer = grpc.NewServer(s.withLoggingUnaryInterceptor()) - proto.RegisterBorServer(s.grpcServer, s) - +func (s *Server) gRPCServerByAddress(addr string) error { lis, err := net.Listen("tcp", addr) if err != nil { return err } + return s.gRPCServerByListener(lis) +} + +func (s *Server) gRPCServerByListener(listener net.Listener) error { + s.grpcServer = grpc.NewServer(s.withLoggingUnaryInterceptor()) + proto.RegisterBorServer(s.grpcServer, s) + go func() { - if err := s.grpcServer.Serve(lis); err != nil { + if err := s.grpcServer.Serve(listener); err != nil { log.Error("failed to serve grpc server", "err", err) } }() - log.Info("GRPC Server started", "addr", addr) + log.Info("GRPC Server started", "addr", listener.Addr()) return nil } diff --git a/internal/cli/server/service.go b/internal/cli/server/service.go index de240d5461..37c1dc802f 100644 --- a/internal/cli/server/service.go +++ b/internal/cli/server/service.go @@ -8,9 +8,8 @@ import ( "reflect" "strings" - gproto "github.com/golang/protobuf/proto" //nolint:staticcheck,typecheck - "github.com/golang/protobuf/ptypes/empty" - grpc_net_conn "github.com/mitchellh/go-grpc-net-conn" + grpc_net_conn "github.com/JekaMas/go-grpc-net-conn" + empty "google.golang.org/protobuf/types/known/emptypb" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -38,10 +37,11 @@ func sendStreamDebugFile(stream proto.Bor_DebugPprofServer, headers map[string]s } // Wrap our conn around the response. - encoder := grpc_net_conn.SimpleEncoder(func(msg gproto.Message) *[]byte { - return &msg.(*proto.DebugFileResponse_Input).Data + encoder := grpc_net_conn.SimpleEncoder(func(msg *proto.DebugFileResponse_Input) *[]byte { + return &msg.Data }) - conn := &grpc_net_conn.Conn{ + + conn := &grpc_net_conn.Conn[*proto.DebugFileResponse_Input, *proto.DebugFileResponse_Input]{ Stream: stream, Request: &proto.DebugFileResponse_Input{}, Encode: grpc_net_conn.ChunkedEncoder(encoder, chunkSize), diff --git a/internal/cli/status.go b/internal/cli/status.go index 2a8b7d7470..05e0313872 100644 --- a/internal/cli/status.go +++ b/internal/cli/status.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/internal/cli/server/proto" - "github.com/golang/protobuf/ptypes/empty" + empty "google.golang.org/protobuf/types/known/emptypb" ) // StatusCommand is the command to output the status of the client diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 59b6feba52..082dfea66f 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -25,6 +25,8 @@ import ( "time" "github.com/davecgh/go-spew/spew" + "github.com/tyler-smith/go-bip39" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -42,12 +44,12 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" - "github.com/tyler-smith/go-bip39" ) // PublicEthereumAPI provides an API to access Ethereum related information. @@ -669,6 +671,7 @@ func (s *PublicBlockChainAPI) GetTransactionReceiptsByBlock(ctx context.Context, "contractAddress": nil, "logs": receipt.Logs, "logsBloom": receipt.Bloom, + "type": hexutil.Uint(tx.Type()), } // Assign receipt status or post state. @@ -680,9 +683,11 @@ func (s *PublicBlockChainAPI) GetTransactionReceiptsByBlock(ctx context.Context, if receipt.Logs == nil { fields["logs"] = [][]*types.Log{} } - if borReceipt != nil { + + if borReceipt != nil && idx == len(receipts)-1 { fields["transactionHash"] = txHash } + // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation if receipt.ContractAddress != (common.Address{}) { fields["contractAddress"] = receipt.ContractAddress @@ -814,14 +819,29 @@ func (s *PublicBlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.H return nil } +// getAuthor: returns the author of the Block +func (s *PublicBlockChainAPI) getAuthor(head *types.Header) *common.Address { + // get author using Author() function from: /consensus/clique/clique.go + // In Production: get author using Author() function from: /consensus/bor/bor.go + author, err := s.b.Engine().Author(head) + // make sure we don't send error to the user, return 0x0 instead + if err != nil { + add := common.HexToAddress("0x0000000000000000000000000000000000000000") + return &add + } + // change the coinbase (0x0) with the miner address + return &author +} + // GetBlockByNumber returns the requested canonical block. -// * When blockNr is -1 the chain head is returned. -// * When blockNr is -2 the pending chain head is returned. -// * When fullTx is true all transactions in the block are returned, otherwise -// only the transaction hash is returned. +// - When blockNr is -1 the chain head is returned. +// - When blockNr is -2 the pending chain head is returned. +// - When fullTx is true all transactions in the block are returned, otherwise +// only the transaction hash is returned. func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { block, err := s.b.BlockByNumber(ctx, number) if block != nil && err == nil { + response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) if err == nil && number == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields @@ -830,6 +850,12 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B } } + if err == nil && number != rpc.PendingBlockNumber { + author := s.getAuthor(block.Header()) + + response["miner"] = author + } + // append marshalled bor transaction if err == nil && response != nil { response = s.appendRPCMarshalBorTransaction(ctx, block, response, fullTx) @@ -848,6 +874,10 @@ func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Ha response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) // append marshalled bor transaction if err == nil && response != nil { + author := s.getAuthor(block.Header()) + + response["miner"] = author + return s.appendRPCMarshalBorTransaction(ctx, block, response, fullTx), err } return response, err @@ -1303,7 +1333,7 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { // RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // transaction hashes. -func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) (map[string]interface{}, error) { +func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig, db ethdb.Database) (map[string]interface{}, error) { fields := RPCMarshalHeader(block.Header()) fields["size"] = hexutil.Uint64(block.Size()) @@ -1313,7 +1343,7 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param } if fullTx { formatTx = func(tx *types.Transaction) (interface{}, error) { - return newRPCTransactionFromBlockHash(block, tx.Hash(), config), nil + return newRPCTransactionFromBlockHash(block, tx.Hash(), config, db), nil } } txs := block.Transactions() @@ -1347,7 +1377,7 @@ func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *type // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires // a `PublicBlockchainAPI`. func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields, err := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig()) + fields, err := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig(), s.b.ChainDb()) if err != nil { return nil, err } @@ -1440,8 +1470,18 @@ func newRPCPendingTransaction(tx *types.Transaction, current *types.Header, conf } // newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *params.ChainConfig) *RPCTransaction { +func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *params.ChainConfig, db ethdb.Database) *RPCTransaction { txs := b.Transactions() + + borReceipt := rawdb.ReadBorReceipt(db, b.Hash(), b.NumberU64()) + if borReceipt != nil { + tx, _, _, _ := rawdb.ReadBorTransaction(db, borReceipt.TxHash) + + if tx != nil { + txs = append(txs, tx) + } + } + if index >= uint64(len(txs)) { return nil } @@ -1459,10 +1499,10 @@ func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.By } // newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. -func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash, config *params.ChainConfig) *RPCTransaction { +func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash, config *params.ChainConfig, db ethdb.Database) *RPCTransaction { for idx, tx := range b.Transactions() { if tx.Hash() == hash { - return newRPCTransactionFromBlockIndex(b, uint64(idx), config) + return newRPCTransactionFromBlockIndex(b, uint64(idx), config, db) } } return nil @@ -1575,6 +1615,26 @@ type PublicTransactionPoolAPI struct { signer types.Signer } +// returns block transactions along with state-sync transaction if present +// nolint: unparam +func (api *PublicTransactionPoolAPI) getAllBlockTransactions(ctx context.Context, block *types.Block) (types.Transactions, bool) { + txs := block.Transactions() + + stateSyncPresent := false + + borReceipt := rawdb.ReadBorReceipt(api.b.ChainDb(), block.Hash(), block.NumberU64()) + if borReceipt != nil { + txHash := types.GetDerivedBorTxHash(types.BorReceiptKey(block.Number().Uint64(), block.Hash())) + if txHash != (common.Hash{}) { + borTx, _, _, _, _ := api.b.GetBorBlockTransactionWithBlockHash(ctx, txHash, block.Hash()) + txs = append(txs, borTx) + stateSyncPresent = true + } + } + + return txs, stateSyncPresent +} + // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI { // The signer used by the API should always be the 'latest' known one because we expect @@ -1586,7 +1646,8 @@ func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransa // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - n := hexutil.Uint(len(block.Transactions())) + txs, _ := s.getAllBlockTransactions(ctx, block) + n := hexutil.Uint(len(txs)) return &n } return nil @@ -1595,7 +1656,8 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context. // GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - n := hexutil.Uint(len(block.Transactions())) + txs, _ := s.getAllBlockTransactions(ctx, block) + n := hexutil.Uint(len(txs)) return &n } return nil @@ -1604,7 +1666,7 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Co // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) + return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig(), s.b.ChainDb()) } return nil } @@ -1612,7 +1674,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx conte // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) + return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig(), s.b.ChainDb()) } return nil } diff --git a/internal/testlog/testlog.go b/internal/testlog/testlog.go index 684339f16d..a5836b8446 100644 --- a/internal/testlog/testlog.go +++ b/internal/testlog/testlog.go @@ -26,12 +26,13 @@ import ( // Handler returns a log handler which logs to the unit test log of t. func Handler(t *testing.T, level log.Lvl) log.Handler { - return log.LvlFilterHandler(level, &handler{t, log.TerminalFormat(false)}) + return log.LvlFilterHandler(level, &handler{t, log.TerminalFormat(false), level}) } type handler struct { t *testing.T fmt log.Format + lvl log.Lvl } func (h *handler) Log(r *log.Record) error { @@ -39,6 +40,10 @@ func (h *handler) Log(r *log.Record) error { return nil } +func (h *handler) Level() log.Lvl { + return h.lvl +} + // logger implements log.Logger such that all output goes to the unit test log via // t.Logf(). All methods in between logger.Trace, logger.Debug, etc. are marked as test // helpers, so the file and line number in unit test output correspond to the call site @@ -59,6 +64,9 @@ func (h *bufHandler) Log(r *log.Record) error { h.buf = append(h.buf, r) return nil } +func (h *bufHandler) Level() log.Lvl { + return log.LvlTrace +} // Logger returns a logger which logs to the unit test log of t. func Logger(t *testing.T, level log.Lvl) log.Logger { diff --git a/les/client.go b/les/client.go index 87d4f00dad..58944658c9 100644 --- a/les/client.go +++ b/les/client.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/downloader/whitelist" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" @@ -145,7 +146,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { } // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with // indexers already set but not started yet - if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint); err != nil { + if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, checkpoint, whitelist.NewService(10)); err != nil { return nil, err } leth.chainReader = leth.blockchain diff --git a/les/handler_test.go b/les/handler_test.go index aba45764b3..3ceabdf8ec 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -316,7 +316,7 @@ func TestGetStaleCodeLes4(t *testing.T) { testGetStaleCode(t, 4) } func testGetStaleCode(t *testing.T, protocol int) { netconfig := testnetConfig{ - blocks: core.TriesInMemory + 4, + blocks: int(core.DefaultCacheConfig.TriesInMemory) + 4, protocol: protocol, nopruning: true, } @@ -430,7 +430,7 @@ func TestGetStaleProofLes4(t *testing.T) { testGetStaleProof(t, 4) } func testGetStaleProof(t *testing.T, protocol int) { netconfig := testnetConfig{ - blocks: core.TriesInMemory + 4, + blocks: int(core.DefaultCacheConfig.TriesInMemory) + 4, protocol: protocol, nopruning: true, } diff --git a/les/peer.go b/les/peer.go index 499429739d..46a88cfff7 100644 --- a/les/peer.go +++ b/les/peer.go @@ -1058,7 +1058,7 @@ func (p *clientPeer) Handshake(td *big.Int, head common.Hash, headNum uint64, ge // If local ethereum node is running in archive mode, advertise ourselves we have // all version state data. Otherwise only recent state is available. - stateRecent := uint64(core.TriesInMemory - blockSafetyMargin) + stateRecent := core.DefaultCacheConfig.TriesInMemory - blockSafetyMargin if server.archiveMode { stateRecent = 0 } diff --git a/les/server_requests.go b/les/server_requests.go index bab5f733d5..3595a6ab38 100644 --- a/les/server_requests.go +++ b/les/server_requests.go @@ -297,7 +297,7 @@ func handleGetCode(msg Decoder) (serveRequestFn, uint64, uint64, error) { // Refuse to search stale state data in the database since looking for // a non-exist key is kind of expensive. local := bc.CurrentHeader().Number.Uint64() - if !backend.ArchiveMode() && header.Number.Uint64()+core.TriesInMemory <= local { + if !backend.ArchiveMode() && header.Number.Uint64()+core.DefaultCacheConfig.TriesInMemory <= local { p.Log().Debug("Reject stale code request", "number", header.Number.Uint64(), "head", local) p.bumpInvalid() continue @@ -396,7 +396,7 @@ func handleGetProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) { // Refuse to search stale state data in the database since looking for // a non-exist key is kind of expensive. local := bc.CurrentHeader().Number.Uint64() - if !backend.ArchiveMode() && header.Number.Uint64()+core.TriesInMemory <= local { + if !backend.ArchiveMode() && header.Number.Uint64()+core.DefaultCacheConfig.TriesInMemory <= local { p.Log().Debug("Reject stale trie request", "number", header.Number.Uint64(), "head", local) p.bumpInvalid() continue diff --git a/les/test_helper.go b/les/test_helper.go index 480d249dca..1e6fb6653f 100644 --- a/les/test_helper.go +++ b/les/test_helper.go @@ -203,7 +203,7 @@ func newTestClientHandler(backend *backends.SimulatedBackend, odr *LesOdr, index oracle *checkpointoracle.CheckpointOracle ) genesis := gspec.MustCommit(db) - chain, _ := light.NewLightChain(odr, gspec.Config, engine, nil) + chain, _ := light.NewLightChain(odr, gspec.Config, engine, nil, nil) if indexers != nil { checkpointConfig := ¶ms.CheckpointOracleConfig{ Address: crypto.CreateAddress(bankAddr, 0), @@ -377,7 +377,7 @@ func (p *testPeer) handshakeWithClient(t *testing.T, td *big.Int, head common.Ha sendList = sendList.add("serveHeaders", nil) sendList = sendList.add("serveChainSince", uint64(0)) sendList = sendList.add("serveStateSince", uint64(0)) - sendList = sendList.add("serveRecentState", uint64(core.TriesInMemory-4)) + sendList = sendList.add("serveRecentState", core.DefaultCacheConfig.TriesInMemory-4) sendList = sendList.add("txRelay", nil) sendList = sendList.add("flowControl/BL", testBufLimit) sendList = sendList.add("flowControl/MRR", testBufRecharge) diff --git a/light/lightchain.go b/light/lightchain.go index ee4146a2d8..98ffa216c6 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -26,6 +26,9 @@ import ( "sync/atomic" "time" + lru "github.com/hashicorp/golang-lru" + + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core" @@ -37,7 +40,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - lru "github.com/hashicorp/golang-lru" ) var ( @@ -81,7 +83,7 @@ type LightChain struct { // NewLightChain returns a fully initialised light chain using information // available in the database. It initialises the default Ethereum header // validator. -func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, checkpoint *params.TrustedCheckpoint) (*LightChain, error) { +func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, checkpoint *params.TrustedCheckpoint, checker ethereum.ChainValidator) (*LightChain, error) { bodyCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit) blockCache, _ := lru.New(blockCacheLimit) @@ -96,7 +98,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. blockCache: blockCache, engine: engine, } - bc.forker = core.NewForkChoice(bc, nil) + bc.forker = core.NewForkChoice(bc, nil, checker) var err error bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.engine, bc.getProcInterrupt) if err != nil { diff --git a/light/lightchain_test.go b/light/lightchain_test.go index 8600e56345..4747fc58c6 100644 --- a/light/lightchain_test.go +++ b/light/lightchain_test.go @@ -56,7 +56,7 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) { db := rawdb.NewMemoryDatabase() gspec := core.Genesis{Config: params.TestChainConfig} genesis := gspec.MustCommit(db) - blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker(), nil) + blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker(), nil, nil) // Create and inject the requested chain if n == 0 { @@ -76,7 +76,7 @@ func newTestLightChain() *LightChain { Config: params.TestChainConfig, } gspec.MustCommit(db) - lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), nil) + lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), nil, nil) if err != nil { panic(err) } @@ -347,7 +347,7 @@ func TestReorgBadHeaderHashes(t *testing.T) { defer func() { delete(core.BadHashes, headers[3].Hash()) }() // Create a new LightChain and check that it rolled back the state. - ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), nil) + ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), nil, nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } diff --git a/light/odr_test.go b/light/odr_test.go index fdf657a82e..9f4b42e675 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -261,14 +261,14 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { ) gspec.MustCommit(ldb) // Assemble the test environment - blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil) + blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil) gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { t.Fatal(err) } odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig} - lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil) + lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil, nil) if err != nil { t.Fatal(err) } diff --git a/light/trie_test.go b/light/trie_test.go index e8294cc2a2..24cf6ec48e 100644 --- a/light/trie_test.go +++ b/light/trie_test.go @@ -44,7 +44,8 @@ func TestNodeIterator(t *testing.T) { genesis = gspec.MustCommit(fulldb) ) gspec.MustCommit(lightdb) - blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil) + + blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil) gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) diff --git a/light/txpool_test.go b/light/txpool_test.go index cc2651d29a..a078a18f1a 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -91,7 +91,7 @@ func TestTxPool(t *testing.T) { ) gspec.MustCommit(ldb) // Assemble the test environment - blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil) + blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil) gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen) if _, err := blockchain.InsertChain(gchain); err != nil { panic(err) @@ -103,7 +103,7 @@ func TestTxPool(t *testing.T) { discard: make(chan int, 1), mined: make(chan int, 1), } - lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil) + lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil, nil) txPermanent = 50 pool := NewTxPool(params.TestChainConfig, lightchain, relay) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) diff --git a/log/handler.go b/log/handler.go index 4ad433334e..6e89858f4b 100644 --- a/log/handler.go +++ b/log/handler.go @@ -17,18 +17,26 @@ import ( // them to achieve the logging structure that suits your applications. type Handler interface { Log(r *Record) error + Level() Lvl } // FuncHandler returns a Handler that logs records with the given // function. -func FuncHandler(fn func(r *Record) error) Handler { - return funcHandler(fn) +func FuncHandler(fn func(r *Record) error, lvl Lvl) Handler { + return funcHandler{fn, lvl} } -type funcHandler func(r *Record) error +type funcHandler struct { + log func(r *Record) error + lvl Lvl +} func (h funcHandler) Log(r *Record) error { - return h(r) + return h.log(r) +} + +func (h funcHandler) Level() Lvl { + return h.lvl } // StreamHandler writes log records to an io.Writer @@ -42,7 +50,7 @@ func StreamHandler(wr io.Writer, fmtr Format) Handler { h := FuncHandler(func(r *Record) error { _, err := wr.Write(fmtr.Format(r)) return err - }) + }, LvlTrace) return LazyHandler(SyncHandler(h)) } @@ -55,7 +63,7 @@ func SyncHandler(h Handler) Handler { defer mu.Unlock() mu.Lock() return h.Log(r) - }) + }, h.Level()) } // FileHandler returns a handler which writes log records to the give file @@ -99,7 +107,7 @@ func CallerFileHandler(h Handler) Handler { return FuncHandler(func(r *Record) error { r.Ctx = append(r.Ctx, "caller", fmt.Sprint(r.Call)) return h.Log(r) - }) + }, h.Level()) } // CallerFuncHandler returns a Handler that adds the calling function name to @@ -108,7 +116,7 @@ func CallerFuncHandler(h Handler) Handler { return FuncHandler(func(r *Record) error { r.Ctx = append(r.Ctx, "fn", formatCall("%+n", r.Call)) return h.Log(r) - }) + }, h.Level()) } // This function is here to please go vet on Go < 1.8. @@ -128,29 +136,28 @@ func CallerStackHandler(format string, h Handler) Handler { r.Ctx = append(r.Ctx, "stack", fmt.Sprintf(format, s)) } return h.Log(r) - }) + }, h.Level()) } // FilterHandler returns a Handler that only writes records to the // wrapped Handler if the given function evaluates true. For example, // to only log records where the 'err' key is not nil: // -// logger.SetHandler(FilterHandler(func(r *Record) bool { -// for i := 0; i < len(r.Ctx); i += 2 { -// if r.Ctx[i] == "err" { -// return r.Ctx[i+1] != nil -// } -// } -// return false -// }, h)) -// +// logger.SetHandler(FilterHandler(func(r *Record) bool { +// for i := 0; i < len(r.Ctx); i += 2 { +// if r.Ctx[i] == "err" { +// return r.Ctx[i+1] != nil +// } +// } +// return false +// }, h)) func FilterHandler(fn func(r *Record) bool, h Handler) Handler { return FuncHandler(func(r *Record) error { if fn(r) { return h.Log(r) } return nil - }) + }, h.Level()) } // MatchFilterHandler returns a Handler that only writes records @@ -158,8 +165,7 @@ func FilterHandler(fn func(r *Record) bool, h Handler) Handler { // context matches the value. For example, to only log records // from your ui package: // -// log.MatchFilterHandler("pkg", "app/ui", log.StdoutHandler) -// +// log.MatchFilterHandler("pkg", "app/ui", log.StdoutHandler) func MatchFilterHandler(key string, value interface{}, h Handler) Handler { return FilterHandler(func(r *Record) (pass bool) { switch key { @@ -185,8 +191,7 @@ func MatchFilterHandler(key string, value interface{}, h Handler) Handler { // level to the wrapped Handler. For example, to only // log Error/Crit records: // -// log.LvlFilterHandler(log.LvlError, log.StdoutHandler) -// +// log.LvlFilterHandler(log.LvlError, log.StdoutHandler) func LvlFilterHandler(maxLvl Lvl, h Handler) Handler { return FilterHandler(func(r *Record) (pass bool) { return r.Lvl <= maxLvl @@ -198,10 +203,9 @@ func LvlFilterHandler(maxLvl Lvl, h Handler) Handler { // to different locations. For example, to log to a file and // standard error: // -// log.MultiHandler( -// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()), -// log.StderrHandler) -// +// log.MultiHandler( +// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()), +// log.StderrHandler) func MultiHandler(hs ...Handler) Handler { return FuncHandler(func(r *Record) error { for _, h := range hs { @@ -209,7 +213,7 @@ func MultiHandler(hs ...Handler) Handler { h.Log(r) } return nil - }) + }, LvlDebug) } // FailoverHandler writes all log records to the first handler @@ -219,10 +223,10 @@ func MultiHandler(hs ...Handler) Handler { // to writing to a file if the network fails, and then to // standard out if the file write fails: // -// log.FailoverHandler( -// log.Must.NetHandler("tcp", ":9090", log.JSONFormat()), -// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()), -// log.StdoutHandler) +// log.FailoverHandler( +// log.Must.NetHandler("tcp", ":9090", log.JSONFormat()), +// log.Must.FileHandler("/var/log/app.log", log.LogfmtFormat()), +// log.StdoutHandler) // // All writes that do not go to the first handler will add context with keys of // the form "failover_err_{idx}" which explain the error encountered while @@ -239,17 +243,17 @@ func FailoverHandler(hs ...Handler) Handler { } return err - }) + }, LvlTrace) } // ChannelHandler writes all records to the given channel. // It blocks if the channel is full. Useful for async processing // of log messages, it's used by BufferedHandler. -func ChannelHandler(recs chan<- *Record) Handler { +func ChannelHandler(recs chan<- *Record, lvl Lvl) Handler { return FuncHandler(func(r *Record) error { recs <- r return nil - }) + }, lvl) } // BufferedHandler writes all records to a buffered @@ -264,7 +268,8 @@ func BufferedHandler(bufSize int, h Handler) Handler { _ = h.Log(m) } }() - return ChannelHandler(recs) + + return ChannelHandler(recs, h.Level()) } // LazyHandler writes all values to the wrapped handler after evaluating @@ -297,7 +302,7 @@ func LazyHandler(h Handler) Handler { } return h.Log(r) - }) + }, h.Level()) } func evaluateLazy(lz Lazy) (interface{}, error) { @@ -333,7 +338,7 @@ func evaluateLazy(lz Lazy) (interface{}, error) { func DiscardHandler() Handler { return FuncHandler(func(r *Record) error { return nil - }) + }, LvlDiscard) } // Must provides the following Handler creation functions diff --git a/log/handler_glog.go b/log/handler_glog.go index 9b1d4efaf4..67376d3d41 100644 --- a/log/handler_glog.go +++ b/log/handler_glog.go @@ -82,14 +82,14 @@ func (h *GlogHandler) Verbosity(level Lvl) { // // For instance: // -// pattern="gopher.go=3" -// sets the V level to 3 in all Go files named "gopher.go" +// pattern="gopher.go=3" +// sets the V level to 3 in all Go files named "gopher.go" // -// pattern="foo=3" -// sets V to 3 in all files of any packages whose import path ends in "foo" +// pattern="foo=3" +// sets V to 3 in all files of any packages whose import path ends in "foo" // -// pattern="foo/*=3" -// sets V to 3 in all files of any packages whose import path contains "foo" +// pattern="foo/*=3" +// sets V to 3 in all files of any packages whose import path contains "foo" func (h *GlogHandler) Vmodule(ruleset string) error { var filter []pattern for _, rule := range strings.Split(ruleset, ",") { @@ -230,3 +230,7 @@ func (h *GlogHandler) Log(r *Record) error { } return nil } + +func (h *GlogHandler) Level() Lvl { + return Lvl(atomic.LoadUint32(&h.level)) +} diff --git a/log/handler_go119.go b/log/handler_go119.go new file mode 100644 index 0000000000..843dfd83b0 --- /dev/null +++ b/log/handler_go119.go @@ -0,0 +1,27 @@ +//+go:build go1.19 + +package log + +import "sync/atomic" + +// swapHandler wraps another handler that may be swapped out +// dynamically at runtime in a thread-safe fashion. +type swapHandler struct { + handler atomic.Pointer[Handler] +} + +func (h *swapHandler) Log(r *Record) error { + return (*h.handler.Load()).Log(r) +} + +func (h *swapHandler) Swap(newHandler Handler) { + h.handler.Store(&newHandler) +} + +func (h *swapHandler) Get() Handler { + return *h.handler.Load() +} + +func (h *swapHandler) Level() Lvl { + return (*h.handler.Load()).Level() +} diff --git a/log/handler_go14.go b/log/handler_go14.go index d0cb14aa06..c02a9abd16 100644 --- a/log/handler_go14.go +++ b/log/handler_go14.go @@ -1,5 +1,4 @@ -//go:build go1.4 -// +build go1.4 +//go:build !go1.19 package log diff --git a/log/logger.go b/log/logger.go index 276d6969e2..2b96681a82 100644 --- a/log/logger.go +++ b/log/logger.go @@ -18,7 +18,8 @@ const skipLevel = 2 type Lvl int const ( - LvlCrit Lvl = iota + LvlDiscard Lvl = -1 + LvlCrit Lvl = iota LvlError LvlWarn LvlInfo @@ -131,6 +132,10 @@ type logger struct { } func (l *logger) write(msg string, lvl Lvl, ctx []interface{}, skip int) { + if l.h.Level() < lvl { + return + } + l.h.Log(&Record{ Time: time.Now(), Lvl: lvl, diff --git a/log/syslog.go b/log/syslog.go index 451d831b6d..cfa7c8cc1b 100644 --- a/log/syslog.go +++ b/log/syslog.go @@ -45,7 +45,7 @@ func sharedSyslog(fmtr Format, sysWr *syslog.Writer, err error) (Handler, error) s := strings.TrimSpace(string(fmtr.Format(r))) return syslogFn(s) - }) + }, LvlTrace) return LazyHandler(&closingHandler{sysWr, h}), nil } diff --git a/miner/fake_miner.go b/miner/fake_miner.go index cbe0d9f54c..3ca2f5be77 100644 --- a/miner/fake_miner.go +++ b/miner/fake_miner.go @@ -47,7 +47,7 @@ func NewBorDefaultMiner(t *testing.T) *DefaultBorMiner { ethAPI.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() spanner := bor.NewMockSpanner(ctrl) - spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any()).Return([]*valset.Validator{ + spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{ { ID: 0, Address: common.Address{0x1}, @@ -84,7 +84,7 @@ func createBorMiner(t *testing.T, ethAPIMock api.Caller, spanner bor.Spanner, he engine := NewFakeBor(t, chainDB, chainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock) // Create Ethereum backend - bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("can't create new chain %v", err) } @@ -118,7 +118,12 @@ func createBorMiner(t *testing.T, ethAPIMock api.Caller, spanner bor.Spanner, he return miner, mux, cleanup } -func NewDBForFakes(t *testing.T) (ethdb.Database, *core.Genesis, *params.ChainConfig) { +type TensingObject interface { + Helper() + Fatalf(format string, args ...any) +} + +func NewDBForFakes(t TensingObject) (ethdb.Database, *core.Genesis, *params.ChainConfig) { t.Helper() memdb := memorydb.New() @@ -133,11 +138,14 @@ func NewDBForFakes(t *testing.T) (ethdb.Database, *core.Genesis, *params.ChainCo chainConfig.Bor.Period = map[string]uint64{ "0": 1, } + chainConfig.Bor.Sprint = map[string]uint64{ + "0": 64, + } return chainDB, genesis, chainConfig } -func NewFakeBor(t *testing.T, chainDB ethdb.Database, chainConfig *params.ChainConfig, ethAPIMock api.Caller, spanner bor.Spanner, heimdallClientMock bor.IHeimdallClient, contractMock bor.GenesisContract) consensus.Engine { +func NewFakeBor(t TensingObject, chainDB ethdb.Database, chainConfig *params.ChainConfig, ethAPIMock api.Caller, spanner bor.Spanner, heimdallClientMock bor.IHeimdallClient, contractMock bor.GenesisContract) consensus.Engine { t.Helper() if chainConfig.Bor == nil { @@ -203,7 +211,7 @@ var ( // Test accounts testBankKey, _ = crypto.GenerateKey() - testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) + TestBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) testBankFunds = big.NewInt(1000000000000000000) testUserKey, _ = crypto.GenerateKey() diff --git a/miner/test_backend.go b/miner/test_backend.go new file mode 100644 index 0000000000..29da747ae0 --- /dev/null +++ b/miner/test_backend.go @@ -0,0 +1,182 @@ +package miner + +import ( + "crypto/rand" + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/bor" + "github.com/ethereum/go-ethereum/consensus/clique" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/params" +) + +const ( + // testCode is the testing contract binary code which will initialises some + // variables in constructor + testCode = "0x60806040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005534801561003457600080fd5b5060fc806100436000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80630c4dae8814603757806398a213cf146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055507fe9e44f9f7da8c559de847a3232b57364adc0354f15a2cd8dc636d54396f9587a6000546040518082815260200191505060405180910390a15056fea265627a7a723058208ae31d9424f2d0bc2a3da1a5dd659db2d71ec322a17db8f87e19e209e3a1ff4a64736f6c634300050a0032" + + // testGas is the gas required for contract deployment. + testGas = 144109 +) + +func init() { + signer := types.LatestSigner(params.TestChainConfig) + + tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{ + ChainID: params.TestChainConfig.ChainID, + Nonce: 0, + To: &testUserAddress, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: big.NewInt(params.InitialBaseFee), + }) + + pendingTxs = append(pendingTxs, tx1) + + tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{ + Nonce: 1, + To: &testUserAddress, + Value: big.NewInt(1000), + Gas: params.TxGas, + GasPrice: big.NewInt(params.InitialBaseFee), + }) + + newTxs = append(newTxs, tx2) +} + +// testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. +type testWorkerBackend struct { + DB ethdb.Database + txPool *core.TxPool + chain *core.BlockChain + Genesis *core.Genesis + uncleBlock *types.Block +} + +func newTestWorkerBackend(t TensingObject, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend { + var gspec = core.Genesis{ + Config: chainConfig, + Alloc: core.GenesisAlloc{TestBankAddress: {Balance: testBankFunds}}, + GasLimit: 30_000_000, + } + + switch e := engine.(type) { + case *bor.Bor: + gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) + copy(gspec.ExtraData[32:32+common.AddressLength], TestBankAddress.Bytes()) + e.Authorize(TestBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { + return crypto.Sign(crypto.Keccak256(data), testBankKey) + }) + case *clique.Clique: + gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) + copy(gspec.ExtraData[32:32+common.AddressLength], TestBankAddress.Bytes()) + e.Authorize(TestBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { + return crypto.Sign(crypto.Keccak256(data), testBankKey) + }) + case *ethash.Ethash: + default: + t.Fatalf("unexpected consensus engine type: %T", engine) + } + + genesis := gspec.MustCommit(db) + + chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil, nil) + txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) + + // Generate a small n-block chain and an uncle block for it + if n > 0 { + blocks, _ := core.GenerateChain(chainConfig, genesis, engine, db, n, func(i int, gen *core.BlockGen) { + gen.SetCoinbase(TestBankAddress) + }) + if _, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("failed to insert origin chain: %v", err) + } + } + + parent := genesis + if n > 0 { + parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) + } + + blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) { + gen.SetCoinbase(testUserAddress) + }) + + return &testWorkerBackend{ + DB: db, + chain: chain, + txPool: txpool, + Genesis: &gspec, + uncleBlock: blocks[0], + } +} + +func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } +func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool } +func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { + return nil, errors.New("not supported") +} + +func (b *testWorkerBackend) newRandomUncle() (*types.Block, error) { + var parent *types.Block + + cur := b.chain.CurrentBlock() + + if cur.NumberU64() == 0 { + parent = b.chain.Genesis() + } else { + parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash()) + } + + var err error + + blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.DB, 1, func(i int, gen *core.BlockGen) { + var addr = make([]byte, common.AddressLength) + + _, err = rand.Read(addr) + if err != nil { + return + } + + gen.SetCoinbase(common.BytesToAddress(addr)) + }) + + return blocks[0], err +} + +func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { + var tx *types.Transaction + + gasPrice := big.NewInt(10 * params.InitialBaseFee) + + if creation { + tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(TestBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey) + } else { + tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(TestBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey) + } + + return tx +} + +func NewTestWorker(t TensingObject, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*worker, *testWorkerBackend, func()) { + backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) + backend.txPool.AddLocals(pendingTxs) + + //nolint:staticcheck + w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false) + + w.setEtherbase(TestBankAddress) + + return w, backend, w.close +} diff --git a/miner/worker.go b/miner/worker.go index 9fcb2140ca..797e7ea980 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -17,6 +17,7 @@ package miner import ( + "context" "errors" "fmt" "math/big" @@ -25,8 +26,12 @@ import ( "time" mapset "github.com/deckarep/golang-set" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/tracing" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" @@ -144,6 +149,8 @@ func (env *environment) discard() { // task contains all information for consensus engine sealing and result submitting. type task struct { + //nolint:containedctx + ctx context.Context receipts []*types.Receipt state *state.StateDB block *types.Block @@ -158,6 +165,8 @@ const ( // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. type newWorkReq struct { + //nolint:containedctx + ctx context.Context interrupt *int32 noempty bool timestamp int64 @@ -165,6 +174,8 @@ type newWorkReq struct { // getWorkReq represents a request for getting a new sealing work with provided parameters. type getWorkReq struct { + //nolint:containedctx + ctx context.Context params *generateParams err error result chan *types.Block @@ -248,6 +259,7 @@ type worker struct { resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. } +//nolint:staticcheck func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(header *types.Header) bool, init bool) *worker { worker := &worker{ config: config, @@ -286,9 +298,12 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus recommit = minRecommitInterval } + ctx := tracing.WithTracer(context.Background(), otel.GetTracerProvider().Tracer("MinerWorker")) + worker.wg.Add(4) - go worker.mainLoop() - go worker.newWorkLoop(recommit) + + go worker.mainLoop(ctx) + go worker.newWorkLoop(ctx, recommit) go worker.resultLoop() go worker.taskLoop() @@ -418,7 +433,9 @@ func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) t } // newWorkLoop is a standalone goroutine to submit new sealing work upon received events. -func (w *worker) newWorkLoop(recommit time.Duration) { +// +//nolint:gocognit +func (w *worker) newWorkLoop(ctx context.Context, recommit time.Duration) { defer w.wg.Done() var ( interrupt *int32 @@ -432,12 +449,16 @@ func (w *worker) newWorkLoop(recommit time.Duration) { // commit aborts in-flight transaction execution with given signal and resubmits a new one. commit := func(noempty bool, s int32) { + // we close spans only by the place we created them + ctx, span := tracing.Trace(ctx, "worker.newWorkLoop.commit") + tracing.EndSpan(span) + if interrupt != nil { atomic.StoreInt32(interrupt, s) } interrupt = new(int32) select { - case w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp}: + case w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp, ctx: ctx}: case <-w.exitCh: return } @@ -446,6 +467,9 @@ func (w *worker) newWorkLoop(recommit time.Duration) { } // clearPending cleans the stale pending tasks. clearPending := func(number uint64) { + _, span := tracing.Trace(ctx, "worker.newWorkLoop.clearPending") + tracing.EndSpan(span) + w.pendingMu.Lock() for h, t := range w.pendingTasks { if t.block.NumberU64()+staleThreshold <= number { @@ -518,7 +542,8 @@ func (w *worker) newWorkLoop(recommit time.Duration) { // mainLoop is responsible for generating and submitting sealing work based on // the received event. It can support two modes: automatically generate task and // submit it or return task according to given parameters for various proposes. -func (w *worker) mainLoop() { +// nolint: gocognit +func (w *worker) mainLoop(ctx context.Context) { defer w.wg.Done() defer w.txsSub.Unsubscribe() defer w.chainHeadSub.Unsubscribe() @@ -535,10 +560,10 @@ func (w *worker) mainLoop() { for { select { case req := <-w.newWorkCh: - w.commitWork(req.interrupt, req.noempty, req.timestamp) + w.commitWork(req.ctx, req.interrupt, req.noempty, req.timestamp) case req := <-w.getWorkCh: - block, err := w.generateWork(req.params) + block, err := w.generateWork(req.ctx, req.params) if err != nil { req.err = err req.result <- nil @@ -566,7 +591,10 @@ func (w *worker) mainLoop() { if w.isRunning() && w.current != nil && len(w.current.uncles) < 2 { start := time.Now() if err := w.commitUncle(w.current, ev.Block.Header()); err == nil { - w.commit(w.current.copy(), nil, true, start) + commitErr := w.commit(ctx, w.current.copy(), nil, true, start) + if commitErr != nil { + log.Error("error while committing work for mining", "err", commitErr) + } } } @@ -613,7 +641,7 @@ func (w *worker) mainLoop() { // submit sealing work here since all empty submission will be rejected // by clique. Of course the advance sealing(empty submission) is disabled. if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 { - w.commitWork(nil, true, time.Now().Unix()) + w.commitWork(ctx, nil, true, time.Now().Unix()) } } atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) @@ -669,7 +697,7 @@ func (w *worker) taskLoop() { w.pendingTasks[sealHash] = task w.pendingMu.Unlock() - if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { + if err := w.engine.Seal(task.ctx, w.chain, task.block, w.resultCh, stopCh); err != nil { log.Warn("Block sealing failed", "err", err) w.pendingMu.Lock() delete(w.pendingTasks, sealHash) @@ -693,10 +721,12 @@ func (w *worker) resultLoop() { if block == nil { continue } + // Short circuit when receiving duplicate result caused by resubmitting. if w.chain.HasBlock(block.Hash(), block.NumberU64()) { continue } + oldBlock := w.chain.GetBlockByNumber(block.NumberU64()) if oldBlock != nil { oldBlockAuthor, _ := w.chain.Engine().Author(oldBlock.Header()) @@ -706,49 +736,72 @@ func (w *worker) resultLoop() { continue } } + var ( sealhash = w.engine.SealHash(block.Header()) hash = block.Hash() ) + w.pendingMu.RLock() task, exist := w.pendingTasks[sealhash] w.pendingMu.RUnlock() + if !exist { log.Error("Block found but no relative pending task", "number", block.Number(), "sealhash", sealhash, "hash", hash) continue } + // Different block could share same sealhash, deep copy here to prevent write-write conflict. var ( receipts = make([]*types.Receipt, len(task.receipts)) logs []*types.Log + err error ) - for i, taskReceipt := range task.receipts { - receipt := new(types.Receipt) - receipts[i] = receipt - *receipt = *taskReceipt - // add block location fields - receipt.BlockHash = hash - receipt.BlockNumber = block.Number() - receipt.TransactionIndex = uint(i) + tracing.Exec(task.ctx, "resultLoop", func(ctx context.Context, span trace.Span) { + for i, taskReceipt := range task.receipts { + receipt := new(types.Receipt) + receipts[i] = receipt + *receipt = *taskReceipt - // Update the block hash in all logs since it is now available and not when the - // receipt/log of individual transactions were created. - receipt.Logs = make([]*types.Log, len(taskReceipt.Logs)) - for i, taskLog := range taskReceipt.Logs { - log := new(types.Log) - receipt.Logs[i] = log - *log = *taskLog - log.BlockHash = hash + // add block location fields + receipt.BlockHash = hash + receipt.BlockNumber = block.Number() + receipt.TransactionIndex = uint(i) + + // Update the block hash in all logs since it is now available and not when the + // receipt/log of individual transactions were created. + receipt.Logs = make([]*types.Log, len(taskReceipt.Logs)) + for i, taskLog := range taskReceipt.Logs { + log := new(types.Log) + receipt.Logs[i] = log + *log = *taskLog + log.BlockHash = hash + } + logs = append(logs, receipt.Logs...) } - logs = append(logs, receipt.Logs...) - } - // Commit block and state to database. - _, err := w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true) + + // Commit block and state to database. + tracing.ElapsedTime(ctx, span, "WriteBlockAndSetHead time taken", func(_ context.Context, _ trace.Span) { + _, err = w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true) + }) + + tracing.SetAttributes( + span, + attribute.String("hash", hash.String()), + attribute.Int("number", int(block.Number().Uint64())), + attribute.Int("txns", block.Transactions().Len()), + attribute.Int("gas used", int(block.GasUsed())), + attribute.Int("elapsed", int(time.Since(task.createdAt).Milliseconds())), + attribute.Bool("error", err != nil), + ) + }) + if err != nil { log.Error("Failed writing block to chain", "err", err) continue } + log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, "elapsed", common.PrettyDuration(time.Since(task.createdAt))) @@ -757,7 +810,6 @@ func (w *worker) resultLoop() { // Insert the block into the set of pending ones to resultLoop for confirmations w.unconfirmed.Insert(block.NumberU64(), block.Hash()) - case <-w.exitCh: return } @@ -1068,78 +1120,176 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { // fillTransactions retrieves the pending transactions from the txpool and fills them // into the given sealing block. The transaction selection and ordering strategy can // be customized with the plugin in the future. -func (w *worker) fillTransactions(interrupt *int32, env *environment) { +func (w *worker) fillTransactions(ctx context.Context, interrupt *int32, env *environment) { + ctx, span := tracing.StartSpan(ctx, "fillTransactions") + defer tracing.EndSpan(span) + // Split the pending transactions into locals and remotes // Fill the block with all available pending transactions. - pending := w.eth.TxPool().Pending(true) - localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending - for _, account := range w.eth.TxPool().Locals() { - if txs := remoteTxs[account]; len(txs) > 0 { - delete(remoteTxs, account) - localTxs[account] = txs + + var ( + localTxsCount int + remoteTxsCount int + localTxs = make(map[common.Address]types.Transactions) + remoteTxs map[common.Address]types.Transactions + ) + + tracing.Exec(ctx, "worker.SplittingTransactions", func(ctx context.Context, span trace.Span) { + pending := w.eth.TxPool().Pending(true) + remoteTxs = pending + + for _, account := range w.eth.TxPool().Locals() { + if txs := remoteTxs[account]; len(txs) > 0 { + delete(remoteTxs, account) + localTxs[account] = txs + } } - } - if len(localTxs) > 0 { - txs := types.NewTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) - if w.commitTransactions(env, txs, interrupt) { + + localTxsCount = len(localTxs) + remoteTxsCount = len(remoteTxs) + + tracing.SetAttributes( + span, + attribute.Int("len of local txs", localTxsCount), + attribute.Int("len of remote txs", remoteTxsCount), + ) + }) + + var ( + localEnvTCount int + remoteEnvTCount int + committed bool + ) + + if localTxsCount > 0 { + var txs *types.TransactionsByPriceAndNonce + + tracing.Exec(ctx, "worker.LocalTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) { + txs = types.NewTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) + + tracing.SetAttributes( + span, + attribute.Int("len of tx local Heads", txs.GetTxs()), + ) + }) + + tracing.Exec(ctx, "worker.LocalCommitTransactions", func(ctx context.Context, span trace.Span) { + committed = w.commitTransactions(env, txs, interrupt) + }) + + if committed { return } + + localEnvTCount = env.tcount } - if len(remoteTxs) > 0 { - txs := types.NewTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee) - if w.commitTransactions(env, txs, interrupt) { + + if remoteTxsCount > 0 { + var txs *types.TransactionsByPriceAndNonce + + tracing.Exec(ctx, "worker.RemoteTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) { + txs = types.NewTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee) + + tracing.SetAttributes( + span, + attribute.Int("len of tx remote Heads", txs.GetTxs()), + ) + }) + + tracing.Exec(ctx, "worker.RemoteCommitTransactions", func(ctx context.Context, span trace.Span) { + committed = w.commitTransactions(env, txs, interrupt) + }) + + if committed { return } + + remoteEnvTCount = env.tcount } + + tracing.SetAttributes( + span, + attribute.Int("len of final local txs ", localEnvTCount), + attribute.Int("len of final remote txs", remoteEnvTCount), + ) } // generateWork generates a sealing block based on the given parameters. -func (w *worker) generateWork(params *generateParams) (*types.Block, error) { +func (w *worker) generateWork(ctx context.Context, params *generateParams) (*types.Block, error) { work, err := w.prepareWork(params) if err != nil { return nil, err } defer work.discard() - w.fillTransactions(nil, work) - return w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts) + w.fillTransactions(ctx, nil, work) + + return w.engine.FinalizeAndAssemble(ctx, w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts) } // commitWork generates several new sealing tasks based on the parent block // and submit them to the sealer. -func (w *worker) commitWork(interrupt *int32, noempty bool, timestamp int64) { +func (w *worker) commitWork(ctx context.Context, interrupt *int32, noempty bool, timestamp int64) { start := time.Now() - // Set the coinbase if the worker is running or it's required - var coinbase common.Address - if w.isRunning() { - if w.coinbase == (common.Address{}) { - log.Error("Refusing to mine without etherbase") - return + var ( + work *environment + err error + ) + + tracing.Exec(ctx, "worker.prepareWork", func(ctx context.Context, span trace.Span) { + // Set the coinbase if the worker is running or it's required + var coinbase common.Address + if w.isRunning() { + if w.coinbase == (common.Address{}) { + log.Error("Refusing to mine without etherbase") + return + } + + coinbase = w.coinbase // Use the preset address as the fee recipient } - coinbase = w.coinbase // Use the preset address as the fee recipient - } - work, err := w.prepareWork(&generateParams{ - timestamp: uint64(timestamp), - coinbase: coinbase, + + work, err = w.prepareWork(&generateParams{ + timestamp: uint64(timestamp), + coinbase: coinbase, + }) }) + if err != nil { return } + + ctx, span := tracing.StartSpan(ctx, "commitWork") + defer tracing.EndSpan(span) + + tracing.SetAttributes( + span, + attribute.Int("number", int(work.header.Number.Uint64())), + ) + // Create an empty block based on temporary copied state for // sealing in advance without waiting block execution finished. if !noempty && atomic.LoadUint32(&w.noempty) == 0 { - w.commit(work.copy(), nil, false, start) + err = w.commit(ctx, work.copy(), nil, false, start) + if err != nil { + return + } } + // Fill pending transactions from the txpool - w.fillTransactions(interrupt, work) - w.commit(work.copy(), w.fullTaskHook, true, start) + w.fillTransactions(ctx, interrupt, work) + + err = w.commit(ctx, work.copy(), w.fullTaskHook, true, start) + if err != nil { + return + } // Swap out the old work with the new one, terminating any leftover // prefetcher processes in the mean time and starting a new one. if w.current != nil { w.current.discard() } + w.current = work } @@ -1147,22 +1297,38 @@ func (w *worker) commitWork(interrupt *int32, noempty bool, timestamp int64) { // and commits new work if consensus engine is running. // Note the assumption is held that the mutation is allowed to the passed env, do // the deep copy first. -func (w *worker) commit(env *environment, interval func(), update bool, start time.Time) error { +func (w *worker) commit(ctx context.Context, env *environment, interval func(), update bool, start time.Time) error { if w.isRunning() { + ctx, span := tracing.StartSpan(ctx, "commit") + defer tracing.EndSpan(span) + if interval != nil { interval() } + // Create a local environment copy, avoid the data race with snapshot state. // https://github.com/ethereum/go-ethereum/issues/24299 env := env.copy() - block, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, env.txs, env.unclelist(), env.receipts) + + block, err := w.engine.FinalizeAndAssemble(ctx, w.chain, env.header, env.state, env.txs, env.unclelist(), env.receipts) + + tracing.SetAttributes( + span, + attribute.Int("number", int(block.Number().Uint64())), + attribute.String("hash", block.Hash().String()), + attribute.String("sealhash", w.engine.SealHash(block.Header()).String()), + attribute.Int("len of env.txs", len(env.txs)), + attribute.Bool("error", err != nil), + ) + if err != nil { return err } + // If we're post merge, just ignore if !w.isTTDReached(block.Header()) { select { - case w.taskCh <- &task{receipts: env.receipts, state: env.state, block: block, createdAt: time.Now()}: + case w.taskCh <- &task{ctx: ctx, receipts: env.receipts, state: env.state, block: block, createdAt: time.Now()}: w.unconfirmed.Shift(block.NumberU64() - 1) log.Info("Commit new sealing work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), "uncles", len(env.uncles), "txs", env.tcount, @@ -1177,11 +1343,14 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti if update { w.updateSnapshot(env) } + return nil } // getSealingBlock generates the sealing block based on the given parameters. func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash) (*types.Block, error) { + ctx := tracing.WithTracer(context.Background(), otel.GetTracerProvider().Tracer("getSealingBlock")) + req := &getWorkReq{ params: &generateParams{ timestamp: timestamp, @@ -1193,13 +1362,16 @@ func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase noExtra: true, }, result: make(chan *types.Block, 1), + ctx: ctx, } + select { case w.getWorkCh <- req: block := <-req.result if block == nil { return nil, req.err } + return block, nil case <-w.exitCh: return nil, errors.New("miner closed") diff --git a/miner/worker_test.go b/miner/worker_test.go index 6dae391c88..011895c854 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -17,16 +17,13 @@ package miner import ( - "errors" "math/big" - "math/rand" "sync/atomic" "testing" "time" "github.com/golang/mock/gomock" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/bor" @@ -36,169 +33,12 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "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/core/vm" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/tests/bor/mocks" ) -const ( - // testCode is the testing contract binary code which will initialises some - // variables in constructor - testCode = "0x60806040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005534801561003457600080fd5b5060fc806100436000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80630c4dae8814603757806398a213cf146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055507fe9e44f9f7da8c559de847a3232b57364adc0354f15a2cd8dc636d54396f9587a6000546040518082815260200191505060405180910390a15056fea265627a7a723058208ae31d9424f2d0bc2a3da1a5dd659db2d71ec322a17db8f87e19e209e3a1ff4a64736f6c634300050a0032" - - // testGas is the gas required for contract deployment. - testGas = 144109 -) - -func init() { - signer := types.LatestSigner(params.TestChainConfig) - - tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{ - ChainID: params.TestChainConfig.ChainID, - Nonce: 0, - To: &testUserAddress, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: big.NewInt(params.InitialBaseFee), - }) - - pendingTxs = append(pendingTxs, tx1) - - tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{ - Nonce: 1, - To: &testUserAddress, - Value: big.NewInt(1000), - Gas: params.TxGas, - GasPrice: big.NewInt(params.InitialBaseFee), - }) - - newTxs = append(newTxs, tx2) - - rand.Seed(time.Now().UnixNano()) -} - -// testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing. -type testWorkerBackend struct { - db ethdb.Database - txPool *core.TxPool - chain *core.BlockChain - testTxFeed event.Feed - genesis *core.Genesis - uncleBlock *types.Block -} - -func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend { - var gspec = core.Genesis{ - Config: chainConfig, - Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}, - } - - switch e := engine.(type) { - case *bor.Bor: - gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) - copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) - e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { - return crypto.Sign(crypto.Keccak256(data), testBankKey) - }) - case *clique.Clique: - gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength) - copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes()) - e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) { - return crypto.Sign(crypto.Keccak256(data), testBankKey) - }) - case *ethash.Ethash: - default: - t.Fatalf("unexpected consensus engine type: %T", engine) - } - - genesis := gspec.MustCommit(db) - - chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil, nil) - txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain) - - // Generate a small n-block chain and an uncle block for it - if n > 0 { - blocks, _ := core.GenerateChain(chainConfig, genesis, engine, db, n, func(i int, gen *core.BlockGen) { - gen.SetCoinbase(testBankAddress) - }) - if _, err := chain.InsertChain(blocks); err != nil { - t.Fatalf("failed to insert origin chain: %v", err) - } - } - - parent := genesis - if n > 0 { - parent = chain.GetBlockByHash(chain.CurrentBlock().ParentHash()) - } - - blocks, _ := core.GenerateChain(chainConfig, parent, engine, db, 1, func(i int, gen *core.BlockGen) { - gen.SetCoinbase(testUserAddress) - }) - - return &testWorkerBackend{ - db: db, - chain: chain, - txPool: txpool, - genesis: &gspec, - uncleBlock: blocks[0], - } -} - -func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain } -func (b *testWorkerBackend) TxPool() *core.TxPool { return b.txPool } -func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) { - return nil, errors.New("not supported") -} - -func (b *testWorkerBackend) newRandomUncle() *types.Block { - var parent *types.Block - - cur := b.chain.CurrentBlock() - - if cur.NumberU64() == 0 { - parent = b.chain.Genesis() - } else { - parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash()) - } - - blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.db, 1, func(i int, gen *core.BlockGen) { - var addr = make([]byte, common.AddressLength) - - rand.Read(addr) - gen.SetCoinbase(common.BytesToAddress(addr)) - }) - - return blocks[0] -} - -func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { - var tx *types.Transaction - - gasPrice := big.NewInt(10 * params.InitialBaseFee) - - if creation { - tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, gasPrice, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey) - } else { - tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, gasPrice, nil), types.HomesteadSigner{}, testBankKey) - } - - return tx -} - -func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*worker, *testWorkerBackend) { - backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) - backend.txPool.AddLocals(pendingTxs) - w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil, false) - w.setEtherbase(testBankAddress) - - return w, backend -} - func TestGenerateBlockAndImportEthash(t *testing.T) { t.Parallel() @@ -235,10 +75,10 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool, isBor bool) { ethAPIMock.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() spanner := bor.NewMockSpanner(ctrl) - spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any()).Return([]*valset.Validator{ + spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{ { ID: 0, - Address: testBankAddress, + Address: TestBankAddress, VotingPower: 100, ProposerPriority: 0, }, @@ -267,14 +107,14 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool, isBor bool) { chainConfig.LondonBlock = big.NewInt(0) - w, b := newTestWorker(t, chainConfig, engine, db, 0) + w, b, _ := NewTestWorker(t, chainConfig, engine, db, 0) defer w.close() // This test chain imports the mined blocks. db2 := rawdb.NewMemoryDatabase() - b.genesis.MustCommit(db2) + b.Genesis.MustCommit(db2) - chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil, nil) defer chain.Stop() // Ignore empty commit here for less noise. @@ -289,11 +129,35 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool, isBor bool) { // Start mining! w.start() + var ( + err error + uncle *types.Block + ) + for i := 0; i < 5; i++ { - b.txPool.AddLocal(b.newRandomTx(true)) - b.txPool.AddLocal(b.newRandomTx(false)) - w.postSideBlock(core.ChainSideEvent{Block: b.newRandomUncle()}) - w.postSideBlock(core.ChainSideEvent{Block: b.newRandomUncle()}) + err = b.txPool.AddLocal(b.newRandomTx(true)) + if err != nil { + t.Fatal("while adding a local transaction", err) + } + + err = b.txPool.AddLocal(b.newRandomTx(false)) + if err != nil { + t.Fatal("while adding a remote transaction", err) + } + + uncle, err = b.newRandomUncle() + if err != nil { + t.Fatal("while making an uncle block", err) + } + + w.postSideBlock(core.ChainSideEvent{Block: uncle}) + + uncle, err = b.newRandomUncle() + if err != nil { + t.Fatal("while making an uncle block", err) + } + + w.postSideBlock(core.ChainSideEvent{Block: uncle}) select { case ev := <-sub.Chan(): @@ -317,7 +181,7 @@ func TestEmptyWorkClique(t *testing.T) { func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { defer engine.Close() - w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) + w, _, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) defer w.close() var ( @@ -371,7 +235,7 @@ func TestStreamUncleBlock(t *testing.T) { ethash := ethash.NewFaker() defer ethash.Close() - w, b := newTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 1) + w, b, _ := NewTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 1) defer w.close() var taskCh = make(chan struct{}) @@ -433,7 +297,7 @@ func TestRegenerateMiningBlockClique(t *testing.T) { func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { defer engine.Close() - w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) + w, b, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) defer w.close() var taskCh = make(chan struct{}, 3) @@ -504,7 +368,7 @@ func TestAdjustIntervalClique(t *testing.T) { func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { defer engine.Close() - w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) + w, _, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) defer w.close() w.skipSealHook = func(task *task) bool { @@ -612,7 +476,7 @@ func TestGetSealingWorkPostMerge(t *testing.T) { func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, postMerge bool) { defer engine.Close() - w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) + w, b, _ := NewTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) defer w.close() w.setExtra([]byte{0x01, 0x02}) @@ -747,3 +611,106 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co } } } + +func BenchmarkBorMining(b *testing.B) { + chainConfig := params.BorUnittestChainConfig + + ctrl := gomock.NewController(b) + defer ctrl.Finish() + + ethAPIMock := api.NewMockCaller(ctrl) + ethAPIMock.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + + spanner := bor.NewMockSpanner(ctrl) + spanner.EXPECT().GetCurrentValidators(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*valset.Validator{ + { + ID: 0, + Address: TestBankAddress, + VotingPower: 100, + ProposerPriority: 0, + }, + }, nil).AnyTimes() + + heimdallClientMock := mocks.NewMockIHeimdallClient(ctrl) + heimdallClientMock.EXPECT().Close().Times(1) + + contractMock := bor.NewMockGenesisContract(ctrl) + + db, _, _ := NewDBForFakes(b) + + engine := NewFakeBor(b, db, chainConfig, ethAPIMock, spanner, heimdallClientMock, contractMock) + defer engine.Close() + + chainConfig.LondonBlock = big.NewInt(0) + + w, back, _ := NewTestWorker(b, chainConfig, engine, db, 0) + defer w.close() + + // This test chain imports the mined blocks. + db2 := rawdb.NewMemoryDatabase() + back.Genesis.MustCommit(db2) + + chain, _ := core.NewBlockChain(db2, nil, back.chain.Config(), engine, vm.Config{}, nil, nil, nil) + defer chain.Stop() + + // Ignore empty commit here for less noise. + w.skipSealHook = func(task *task) bool { + return len(task.receipts) == 0 + } + + // fulfill tx pool + const ( + totalGas = testGas + params.TxGas + totalBlocks = 10 + ) + + var err error + + txInBlock := int(back.Genesis.GasLimit/totalGas) + 1 + + // a bit risky + for i := 0; i < 2*totalBlocks*txInBlock; i++ { + err = back.txPool.AddLocal(back.newRandomTx(true)) + if err != nil { + b.Fatal("while adding a local transaction", err) + } + + err = back.txPool.AddLocal(back.newRandomTx(false)) + if err != nil { + b.Fatal("while adding a remote transaction", err) + } + } + + // Wait for mined blocks. + sub := w.mux.Subscribe(core.NewMinedBlockEvent{}) + defer sub.Unsubscribe() + + b.ResetTimer() + + prev := uint64(time.Now().Unix()) + + // Start mining! + w.start() + + blockPeriod, ok := back.Genesis.Config.Bor.Period["0"] + if !ok { + blockPeriod = 1 + } + + for i := 0; i < totalBlocks; i++ { + select { + case ev := <-sub.Chan(): + block := ev.Data.(core.NewMinedBlockEvent).Block + + if _, err := chain.InsertChain([]*types.Block{block}); err != nil { + b.Fatalf("failed to insert new mined block %d: %v", block.NumberU64(), err) + } + + b.Log("block", block.NumberU64(), "time", block.Time()-prev, "txs", block.Transactions().Len(), "gasUsed", block.GasUsed(), "gasLimit", block.GasLimit()) + + prev = block.Time() + case <-time.After(time.Duration(blockPeriod) * time.Second): + b.Fatalf("timeout") + } + } +} diff --git a/node/node.go b/node/node.go index 7c540306db..e12bcf6675 100644 --- a/node/node.go +++ b/node/node.go @@ -20,6 +20,7 @@ import ( crand "crypto/rand" "errors" "fmt" + "net" "net/http" "os" "path/filepath" @@ -27,6 +28,8 @@ import ( "strings" "sync" + "github.com/prometheus/tsdb/fileutil" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -36,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" - "github.com/prometheus/tsdb/fileutil" ) // Node is a container on which services can be registered. @@ -466,6 +468,12 @@ func (n *Node) startRPC() error { if err := initHttp(n.http, open, n.config.HTTPPort); err != nil { return err } + + defer func() { + if n.http.listener != nil { + n.config.HTTPPort = n.http.listener.Addr().(*net.TCPAddr).Port + } + }() } // Configure WebSocket. if n.config.WSHost != "" { @@ -473,6 +481,12 @@ func (n *Node) startRPC() error { if err := initWS(open, n.config.WSPort); err != nil { return err } + + defer func() { + if n.ws.listener != nil { + n.config.WSPort = n.ws.listener.Addr().(*net.TCPAddr).Port + } + }() } // Configure authenticated API if len(open) != len(all) { @@ -480,16 +494,19 @@ func (n *Node) startRPC() error { if err != nil { return err } - if err := initAuth(all, n.config.AuthPort, jwtSecret); err != nil { + + if err = initAuth(all, n.config.AuthPort, jwtSecret); err != nil { return err } } + // Start the servers for _, server := range servers { if err := server.start(); err != nil { return err } } + return nil } diff --git a/node/rpcstack.go b/node/rpcstack.go index d9c41cca57..eabf1dcae7 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -29,9 +29,10 @@ import ( "sync" "sync/atomic" + "github.com/rs/cors" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" - "github.com/rs/cors" ) // httpConfig is the JSON-RPC/HTTP configuration. diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index e36912f010..e5e81dbb99 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -562,7 +562,7 @@ func startLocalhostV4(t *testing.T, cfg Config) *UDPv4 { cfg.Log.SetHandler(log.FuncHandler(func(r *log.Record) error { t.Logf("%s %s", lprefix, lfmt.Format(r)) return nil - })) + }, log.LvlTrace)) // Listen. socket, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IP{127, 0, 0, 1}}) diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index f061f5ab41..1cc5fc03e0 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -83,7 +83,7 @@ func startLocalhostV5(t *testing.T, cfg Config) *UDPv5 { cfg.Log.SetHandler(log.FuncHandler(func(r *log.Record) error { t.Logf("%s %s", lprefix, lfmt.Format(r)) return nil - })) + }, log.LvlTrace)) // Listen. socket, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IP{127, 0, 0, 1}}) diff --git a/packaging/templates/package_scripts/control b/packaging/templates/package_scripts/control index ed0ff46c06..faa6df2712 100644 --- a/packaging/templates/package_scripts/control +++ b/packaging/templates/package_scripts/control @@ -1,5 +1,5 @@ Source: bor -Version: 0.3.0 +Version: 0.3.1 Section: develop Priority: standard Maintainer: Polygon diff --git a/packaging/templates/package_scripts/control.arm64 b/packaging/templates/package_scripts/control.arm64 index 2c624a4c45..e0590d7c6a 100644 --- a/packaging/templates/package_scripts/control.arm64 +++ b/packaging/templates/package_scripts/control.arm64 @@ -1,5 +1,5 @@ Source: bor -Version: 0.3.0 +Version: 0.3.1 Section: develop Priority: standard Maintainer: Polygon diff --git a/packaging/templates/package_scripts/control.profile.amd64 b/packaging/templates/package_scripts/control.profile.amd64 index 087dabb1f6..0be61b7427 100644 --- a/packaging/templates/package_scripts/control.profile.amd64 +++ b/packaging/templates/package_scripts/control.profile.amd64 @@ -1,5 +1,5 @@ Source: bor-profile -Version: 0.3.0 +Version: 0.3.1 Section: develop Priority: standard Maintainer: Polygon diff --git a/packaging/templates/package_scripts/control.profile.arm64 b/packaging/templates/package_scripts/control.profile.arm64 index 9de0c50253..29d8328b8a 100644 --- a/packaging/templates/package_scripts/control.profile.arm64 +++ b/packaging/templates/package_scripts/control.profile.arm64 @@ -1,5 +1,5 @@ Source: bor-profile -Version: 0.3.0 +Version: 0.3.1 Section: develop Priority: standard Maintainer: Polygon diff --git a/packaging/templates/package_scripts/control.validator b/packaging/templates/package_scripts/control.validator index f3f5652a31..51b4d86ef5 100644 --- a/packaging/templates/package_scripts/control.validator +++ b/packaging/templates/package_scripts/control.validator @@ -1,5 +1,5 @@ Source: bor-profile -Version: 0.3.0 +Version: 0.3.1 Section: develop Priority: standard Maintainer: Polygon diff --git a/packaging/templates/package_scripts/control.validator.arm64 b/packaging/templates/package_scripts/control.validator.arm64 index 97712830ff..6813fba631 100644 --- a/packaging/templates/package_scripts/control.validator.arm64 +++ b/packaging/templates/package_scripts/control.validator.arm64 @@ -1,5 +1,5 @@ Source: bor-profile -Version: 0.3.0 +Version: 0.3.1 Section: develop Priority: standard Maintainer: Polygon diff --git a/params/config.go b/params/config.go index 980250a1ec..d97d6957fa 100644 --- a/params/config.go +++ b/params/config.go @@ -278,8 +278,12 @@ var ( Period: map[string]uint64{ "0": 2, }, - ProducerDelay: 6, - Sprint: 64, + ProducerDelay: map[string]uint64{ + "0": 6, + }, + Sprint: map[string]uint64{ + "0": 64, + }, BackupMultiplier: map[string]uint64{ "0": 2, }, @@ -310,8 +314,12 @@ var ( Period: map[string]uint64{ "0": 1, }, - ProducerDelay: 3, - Sprint: 32, + ProducerDelay: map[string]uint64{ + "0": 3, + }, + Sprint: map[string]uint64{ + "0": 32, + }, BackupMultiplier: map[string]uint64{ "0": 2, }, @@ -341,16 +349,25 @@ var ( BerlinBlock: big.NewInt(13996000), LondonBlock: big.NewInt(22640000), Bor: &BorConfig{ - JaipurBlock: 22770000, + JaipurBlock: big.NewInt(22770000), + DelhiBlock: big.NewInt(29638656), Period: map[string]uint64{ "0": 2, "25275000": 5, + "29638656": 2, + }, + ProducerDelay: map[string]uint64{ + "0": 6, + "29638656": 4, + }, + Sprint: map[string]uint64{ + "0": 64, + "29638656": 16, }, - ProducerDelay: 6, - Sprint: 64, BackupMultiplier: map[string]uint64{ "0": 2, "25275000": 5, + "29638656": 2, }, ValidatorContract: "0x0000000000000000000000000000000000001000", StateReceiverContract: "0x0000000000000000000000000000000000001001", @@ -386,12 +403,16 @@ var ( BerlinBlock: big.NewInt(14750000), LondonBlock: big.NewInt(23850000), Bor: &BorConfig{ - JaipurBlock: 23850000, + JaipurBlock: big.NewInt(23850000), Period: map[string]uint64{ "0": 2, }, - ProducerDelay: 6, - Sprint: 64, + ProducerDelay: map[string]uint64{ + "0": 6, + }, + Sprint: map[string]uint64{ + "0": 64, + }, BackupMultiplier: map[string]uint64{ "0": 2, }, @@ -436,8 +457,10 @@ var ( // adding flags to the config to also have to set these fields. AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, &BorConfig{BurntContract: map[string]string{"0": "0x000000000000000000000000000000000000dead"}}} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil, &BorConfig{BurntContract: map[string]string{"0": "0x000000000000000000000000000000000000dead"}}} - TestRules = TestChainConfig.Rules(new(big.Int), false) + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil, &BorConfig{Sprint: map[string]uint64{ + "0": 4, + }, BurntContract: map[string]string{"0": "0x000000000000000000000000000000000000dead"}}} + TestRules = TestChainConfig.Rules(new(big.Int), false) ) // TrustedCheckpoint represents a set of post-processed trie roots (CHT and @@ -550,15 +573,16 @@ func (c *CliqueConfig) String() string { // BorConfig is the consensus engine configs for Matic bor based sealing. type BorConfig struct { Period map[string]uint64 `json:"period"` // Number of seconds between blocks to enforce - ProducerDelay uint64 `json:"producerDelay"` // Number of seconds delay between two producer interval - Sprint uint64 `json:"sprint"` // Epoch length to proposer + ProducerDelay map[string]uint64 `json:"producerDelay"` // Number of seconds delay between two producer interval + Sprint map[string]uint64 `json:"sprint"` // Epoch length to proposer BackupMultiplier map[string]uint64 `json:"backupMultiplier"` // Backup multiplier to determine the wiggle time ValidatorContract string `json:"validatorContract"` // Validator set contract StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract OverrideStateSyncRecords map[string]int `json:"overrideStateSyncRecords"` // override state records count BlockAlloc map[string]interface{} `json:"blockAlloc"` BurntContract map[string]string `json:"burntContract"` // governance contract where the token will be sent to and burnt in london fork - JaipurBlock uint64 `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on jaipur) + JaipurBlock *big.Int `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on jaipur) + DelhiBlock *big.Int `json:"delhiBlock"` // Delhi switch block (nil = no fork, 0 = already on delhi) } // String implements the stringer interface, returning the consensus engine details. @@ -566,6 +590,14 @@ func (b *BorConfig) String() string { return "bor" } +func (c *BorConfig) CalculateProducerDelay(number uint64) uint64 { + return c.calculateSprintSizeHelper(c.ProducerDelay, number) +} + +func (c *BorConfig) CalculateSprint(number uint64) uint64 { + return c.calculateSprintSizeHelper(c.Sprint, number) +} + func (c *BorConfig) CalculateBackupMultiplier(number uint64) uint64 { return c.calculateBorConfigHelper(c.BackupMultiplier, number) } @@ -574,8 +606,12 @@ func (c *BorConfig) CalculatePeriod(number uint64) uint64 { return c.calculateBorConfigHelper(c.Period, number) } -func (c *BorConfig) IsJaipur(number uint64) bool { - return number >= c.JaipurBlock +func (c *BorConfig) IsJaipur(number *big.Int) bool { + return isForked(c.JaipurBlock, number) +} + +func (c *BorConfig) IsDelhi(number *big.Int) bool { + return isForked(c.DelhiBlock, number) } func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uint64) uint64 { @@ -589,6 +625,7 @@ func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uin for i := 0; i < len(keys)-1; i++ { valUint, _ := strconv.ParseUint(keys[i], 10, 64) valUintNext, _ := strconv.ParseUint(keys[i+1], 10, 64) + if number > valUint && number < valUintNext { return field[keys[i]] } @@ -597,6 +634,26 @@ func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uin return field[keys[len(keys)-1]] } +func (c *BorConfig) calculateSprintSizeHelper(field map[string]uint64, number uint64) uint64 { + keys := make([]string, 0, len(field)) + for k := range field { + keys = append(keys, k) + } + + sort.Strings(keys) + + for i := 0; i < len(keys)-1; i++ { + valUint, _ := strconv.ParseUint(keys[i], 10, 64) + valUintNext, _ := strconv.ParseUint(keys[i+1], 10, 64) + + if number >= valUint && number < valUintNext { + return field[keys[i]] + } + } + + return field[keys[len(keys)-1]] +} + func (c *BorConfig) CalculateBurntContract(number uint64) string { keys := make([]string, 0, len(c.BurntContract)) for k := range c.BurntContract { diff --git a/params/protocol_params.go b/params/protocol_params.go index 5f154597a7..d468af5d3c 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -119,9 +119,11 @@ const ( // Introduced in Tangerine Whistle (Eip 150) CreateBySelfdestructGas uint64 = 25000 - BaseFeeChangeDenominator = 8 // Bounds the amount the base fee can change between blocks. - ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. - InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. + BaseFeeChangeDenominatorPreDelhi = 8 // Bounds the amount the base fee can change between blocks before Delhi Hard Fork. + BaseFeeChangeDenominatorPostDelhi = 16 // Bounds the amount the base fee can change between blocks after Delhi Hard Fork. + + ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. + InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. MaxCodeSize = 24576 // Maximum bytecode to permit for a contract @@ -168,3 +170,11 @@ var ( MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be. DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not. ) + +func BaseFeeChangeDenominator(borConfig *BorConfig, number *big.Int) uint64 { + if borConfig.IsDelhi(number) { + return BaseFeeChangeDenominatorPostDelhi + } else { + return BaseFeeChangeDenominatorPreDelhi + } +} diff --git a/params/version.go b/params/version.go index 83e04a66f8..64b58283bb 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 0 // Major version component of the current release - VersionMinor = 3 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release - VersionMeta = "beta" // Version metadata to append to the version string + VersionMajor = 0 // Major version component of the current release + VersionMinor = 3 // Minor version component of the current release + VersionPatch = 1 // Patch version component of the current release + VersionMeta = "mumbai" // Version metadata to append to the version string ) // Version holds the textual version string. @@ -43,7 +43,8 @@ var VersionWithMeta = func() string { // ArchiveVersion holds the textual version string used for Geth archives. // e.g. "1.8.11-dea1ce05" for stable releases, or -// "1.8.13-unstable-21c059b6" for unstable releases +// +// "1.8.13-unstable-21c059b6" for unstable releases func ArchiveVersion(gitCommit string) string { vsn := Version if VersionMeta != "stable" { diff --git a/rpc/types.go b/rpc/types.go index 46b08caf68..e4d40ab98f 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -61,9 +61,11 @@ type jsonWriter interface { type BlockNumber int64 const ( - PendingBlockNumber = BlockNumber(-2) - LatestBlockNumber = BlockNumber(-1) - EarliestBlockNumber = BlockNumber(0) + SafeBlockNumber = BlockNumber(-4) + FinalizedBlockNumber = BlockNumber(-3) + PendingBlockNumber = BlockNumber(-2) + LatestBlockNumber = BlockNumber(-1) + EarliestBlockNumber = BlockNumber(0) ) // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: diff --git a/tests/block_test.go b/tests/block_test.go index 591bff6e07..e2aa1efea7 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -49,12 +49,18 @@ func TestBlockchain(t *testing.T) { // test takes a lot for time and goes easily OOM because of sha3 calculation on a huge range, // using 4.6 TGas bt.skipLoad(`.*randomStatetest94.json.*`) + + // See POS-618 + bt.skipLoad(`.*ValidBlocks*`) + bt.skipLoad(`.*InvalidBlocks*`) + bt.skipLoad(`.*TransitionTests*`) + bt.walk(t, blockTestDir, func(t *testing.T, name string, test *BlockTest) { if err := bt.checkFailure(t, test.Run(false)); err != nil { - t.Errorf("test without snapshotter failed: %v", err) + t.Errorf("in 'block_test.go', test '%s' without snapshotter failed with error: '%v'", name, err) } if err := bt.checkFailure(t, test.Run(true)); err != nil { - t.Errorf("test with snapshotter failed: %v", err) + t.Errorf("in 'block_test.go', test '%s' with snapshotter failed with error: '%v'", name, err) } }) // There is also a LegacyTests folder, containing blockchain tests generated diff --git a/tests/block_test_util.go b/tests/block_test_util.go index d28f3a1237..487fd2d4d8 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -128,7 +128,8 @@ func (t *BlockTest) Run(snapshotter bool) error { cache.SnapshotLimit = 1 cache.SnapshotWait = true } - chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil, nil) + + chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil, nil, nil) if err != nil { return err } diff --git a/tests/bor/bor_api_test.go b/tests/bor/bor_api_test.go new file mode 100644 index 0000000000..50992d72d9 --- /dev/null +++ b/tests/bor/bor_api_test.go @@ -0,0 +1,255 @@ +//go:build integration + +package bor + +import ( + "context" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/stretchr/testify/assert" +) + +var ( + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addrr = crypto.PubkeyToAddress(key1.PublicKey) + stack, _ = node.New(&node.DefaultConfig) + backend, _ = eth.New(stack, ðconfig.Defaults) + db = backend.ChainDb() + hash1 = common.BytesToHash([]byte("topic1")) + hash2 = common.BytesToHash([]byte("topic2")) + hash3 = common.BytesToHash([]byte("topic3")) + hash4 = common.BytesToHash([]byte("topic4")) + hash5 = common.BytesToHash([]byte("topic5")) +) + +func duplicateInArray(arr []common.Hash) bool { + visited := make(map[common.Hash]bool, 0) + for i := 0; i < len(arr); i++ { + if visited[arr[i]] == true { + return true + } else { + visited[arr[i]] = true + } + } + + return false +} + +func areDifferentHashes(receipts []map[string]interface{}) bool { + addresses := []common.Hash{} + for i := 0; i < len(receipts); i++ { + addresses = append(addresses, receipts[i]["transactionHash"].(common.Hash)) + if duplicateInArray(addresses) { + return false + } + } + + return true +} + +// Test for GetTransactionReceiptsByBlock +func testGetTransactionReceiptsByBlock(t *testing.T, publicBlockchainAPI *ethapi.PublicBlockChainAPI) { + // check 1 : zero transactions + receiptsOut, err := publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(1)) + if err != nil { + t.Error(err) + } + + assert.Equal(t, 0, len(receiptsOut)) + + // check 2 : one transactions ( normal ) + receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(2)) + if err != nil { + t.Error(err) + } + + assert.Equal(t, 1, len(receiptsOut)) + assert.True(t, areDifferentHashes(receiptsOut)) + + // check 3 : two transactions ( both normal ) + receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(3)) + if err != nil { + t.Error(err) + } + + assert.Equal(t, 2, len(receiptsOut)) + assert.True(t, areDifferentHashes(receiptsOut)) + + // check 4 : two transactions ( one normal + one state-sync) + receiptsOut, err = publicBlockchainAPI.GetTransactionReceiptsByBlock(context.Background(), rpc.BlockNumberOrHashWithNumber(4)) + if err != nil { + t.Error(err) + } + + assert.Equal(t, 2, len(receiptsOut)) + assert.True(t, areDifferentHashes(receiptsOut)) + +} + +// Test for GetTransactionByBlockNumberAndIndex +func testGetTransactionByBlockNumberAndIndex(t *testing.T, publicTransactionPoolAPI *ethapi.PublicTransactionPoolAPI) { + // check 1 : False ( no transaction ) + tx := publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(1), 0) + assert.Nil(t, tx) + + // check 2 : Normal Transaction + tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(2), 0) + assert.Equal(t, common.HexToAddress("0x24"), *tx.To) + + // check 3 : Normal Transaction + tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(3), 0) + assert.Equal(t, common.HexToAddress("0x992"), *tx.To) + + // check 4 : Normal Transaction + tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(3), 1) + assert.Equal(t, common.HexToAddress("0x993"), *tx.To) + + // check 5 : Normal Transaction + tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(4), 0) + assert.Equal(t, common.HexToAddress("0x1000"), *tx.To) + + // check 5 : Normal Transaction + tx = publicTransactionPoolAPI.GetTransactionByBlockNumberAndIndex(context.Background(), rpc.BlockNumber(4), 1) + assert.Equal(t, common.HexToAddress("0x0"), *tx.To) +} + +// This Testcase tests functions for RPC API calls. +// NOTE : Changes to this function might affect the child testcases. +func TestAPIs(t *testing.T) { + + defer func() { + if err := stack.Close(); err != nil { + t.Error(err) + } + }() + + genesis := core.GenesisBlockForTesting(db, addrr, big.NewInt(1000000)) + testBorConfig := params.TestChainConfig.Bor + + chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 6, func(i int, gen *core.BlockGen) { + switch i { + + case 1: // 1 normal transaction on block 2 + receipt := types.NewReceipt(nil, false, 0) + receipt.Logs = []*types.Log{ + { + Address: addrr, + Topics: []common.Hash{hash1}, + }, + } + gen.AddUncheckedReceipt(receipt) + gen.AddUncheckedTx(types.NewTransaction(24, common.HexToAddress("0x24"), big.NewInt(24), 24, gen.BaseFee(), nil)) + + case 2: // 2 normal transactions on block 3 + receipt := types.NewReceipt(nil, false, 0) + receipt.Logs = []*types.Log{ + { + Address: addrr, + Topics: []common.Hash{hash2}, + }, + } + gen.AddUncheckedReceipt(receipt) + gen.AddUncheckedTx(types.NewTransaction(992, common.HexToAddress("0x992"), big.NewInt(992), 992, gen.BaseFee(), nil)) + + receipt2 := types.NewReceipt(nil, false, 0) + receipt2.Logs = []*types.Log{ + { + Address: addrr, + Topics: []common.Hash{hash3}, + }, + } + gen.AddUncheckedReceipt(receipt2) + gen.AddUncheckedTx(types.NewTransaction(993, common.HexToAddress("0x993"), big.NewInt(993), 993, gen.BaseFee(), nil)) + + case 3: // 1 normal transaction, 1 state-sync transaction on block 4 + receipt := types.NewReceipt(nil, false, 0) + receipt.Logs = []*types.Log{ + { + Address: addrr, + Topics: []common.Hash{hash4}, + }, + } + gen.AddUncheckedReceipt(receipt) + gen.AddUncheckedTx(types.NewTransaction(1000, common.HexToAddress("0x1000"), big.NewInt(1000), 1000, gen.BaseFee(), nil)) + + // state-sync transaction + receipt2 := types.NewReceipt(nil, false, 0) + receipt2.Logs = []*types.Log{ + { + Address: addrr, + Topics: []common.Hash{hash5}, + }, + } + gen.AddUncheckedReceipt(receipt2) + // not adding unchecked tx as it will be added as a state-sync tx later + + } + }) + + for i, block := range chain { + // write the block to database + rawdb.WriteBlock(db, block) + rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) + rawdb.WriteHeadBlockHash(db, block.Hash()) + + blockBatch := db.NewBatch() + + if i%int(testBorConfig.CalculateSprint(block.NumberU64())-1) != 0 { + // if it is not sprint start write all the transactions as normal transactions. + rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i]) + } else { + // check for blocks with receipts. Since in state-sync block, we have 1 normal txn and 1 state-sync txn. + if len(receipts[i]) > 0 { + // We write receipts for the normal transaction. + rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i][:1]) + + // write the state-sync receipts to database => receipts[i][1:] => receipts[i][1] + // State sync logs don't have tx index, tx hash and other necessary fields, DeriveFieldsForBorLogs will fill those fields for websocket subscriptions + // DeriveFieldsForBorLogs argurments: + // 1. State-sync logs + // 2. Block Hash + // 3. Block Number + // 4. Transactions in the block(except state-sync) i.e. 1 in our case + // 5. AllLogs -(minus) StateSyncLogs ; since we only have state-sync tx, it will be 1 + types.DeriveFieldsForBorLogs(receipts[i][1].Logs, block.Hash(), block.NumberU64(), uint(1), uint(1)) + + rawdb.WriteBorReceipt(blockBatch, block.Hash(), block.NumberU64(), &types.ReceiptForStorage{ + Status: types.ReceiptStatusSuccessful, // make receipt status successful + Logs: receipts[i][1].Logs, + }) + + rawdb.WriteBorTxLookupEntry(blockBatch, block.Hash(), block.NumberU64()) + + } + + } + + if err := blockBatch.Write(); err != nil { + t.Error("Failed to write block into disk", "err", err) + } + } + + // Testing GetTransactionReceiptsByBlock + publicBlockchainAPI := backend.PublicBlockChainAPI() + testGetTransactionReceiptsByBlock(t, publicBlockchainAPI) + + // Testing GetTransactionByBlockNumberAndIndex + nonceLock := new(ethapi.AddrLocker) + publicTransactionPoolAPI := ethapi.NewPublicTransactionPoolAPI(backend.APIBackend, nonceLock) + testGetTransactionByBlockNumberAndIndex(t, publicTransactionPoolAPI) + +} diff --git a/tests/bor/bor_filter_test.go b/tests/bor/bor_filter_test.go new file mode 100644 index 0000000000..8a22d99a44 --- /dev/null +++ b/tests/bor/bor_filter_test.go @@ -0,0 +1,199 @@ +//go:build integration + +package bor + +import ( + "context" + "fmt" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/filters" + "github.com/ethereum/go-ethereum/params" +) + +func TestBorFilters(t *testing.T) { + t.Parallel() + + var ( + db = rawdb.NewMemoryDatabase() + backend = &filters.TestBackend{DB: db} + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr = crypto.PubkeyToAddress(key1.PublicKey) + + hash1 = common.BytesToHash([]byte("topic1")) + hash2 = common.BytesToHash([]byte("topic2")) + hash3 = common.BytesToHash([]byte("topic3")) + hash4 = common.BytesToHash([]byte("topic4")) + hash5 = common.BytesToHash([]byte("topic5")) + ) + + defer db.Close() + + genesis := core.GenesisBlockForTesting(db, addr, big.NewInt(1000000)) + testBorConfig := params.TestChainConfig.Bor + testBorConfig.Sprint = map[string]uint64{ + "0": 4, + "8": 2, + } + + chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 1000, func(i int, gen *core.BlockGen) { + switch i { + case 7: //state-sync tx at block 8 + receipt := types.NewReceipt(nil, false, 0) + receipt.Logs = []*types.Log{ + { + Address: addr, + Topics: []common.Hash{hash1}, + }, + } + gen.AddUncheckedReceipt(receipt) + gen.AddUncheckedTx(types.NewTransaction(8, common.HexToAddress("0x8"), big.NewInt(8), 8, gen.BaseFee(), nil)) + + case 23: //state-sync tx at block 24 + receipt := types.NewReceipt(nil, false, 0) + receipt.Logs = []*types.Log{ + { + Address: addr, + Topics: []common.Hash{hash2}, + }, + } + gen.AddUncheckedReceipt(receipt) + gen.AddUncheckedTx(types.NewTransaction(24, common.HexToAddress("0x24"), big.NewInt(24), 24, gen.BaseFee(), nil)) + + case 991: //state-sync tx at block 992 + receipt := types.NewReceipt(nil, false, 0) + receipt.Logs = []*types.Log{ + { + Address: addr, + Topics: []common.Hash{hash3}, + }, + } + gen.AddUncheckedReceipt(receipt) + gen.AddUncheckedTx(types.NewTransaction(992, common.HexToAddress("0x992"), big.NewInt(992), 992, gen.BaseFee(), nil)) + + case 993: //state-sync tx at block 994 + receipt := types.NewReceipt(nil, false, 0) + receipt.Logs = []*types.Log{ + { + Address: addr, + Topics: []common.Hash{hash4}, + }, + } + gen.AddUncheckedReceipt(receipt) + gen.AddUncheckedTx(types.NewTransaction(994, common.HexToAddress("0x994"), big.NewInt(994), 994, gen.BaseFee(), nil)) + + case 999: //state-sync tx at block 1000 + receipt := types.NewReceipt(nil, false, 0) + receipt.Logs = []*types.Log{ + { + Address: addr, + Topics: []common.Hash{hash5}, + }, + } + gen.AddUncheckedReceipt(receipt) + gen.AddUncheckedTx(types.NewTransaction(1000, common.HexToAddress("0x1000"), big.NewInt(1000), 1000, gen.BaseFee(), nil)) + } + }) + + for i, block := range chain { + // write the block to database + rawdb.WriteBlock(db, block) + rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64()) + rawdb.WriteHeadBlockHash(db, block.Hash()) + + blockBatch := db.NewBatch() + + // since all the transactions are state-sync, we will not include them as normal receipts + rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), []*types.Receipt{}) + + // check for blocks with receipts. Since the only receipt is state-sync, we can check the length of receipts + if len(receipts[i]) > 0 { + // write the state-sync receipts to database + // State sync logs don't have tx index, tx hash and other necessary fields, DeriveFieldsForBorLogs will fill those fields for websocket subscriptions + // DeriveFieldsForBorLogs argurments: + // 1. State-sync logs + // 2. Block Hash + // 3. Block Number + // 4. Transactions in the block(except state-sync) i.e. 0 in our case + // 5. AllLogs - StateSyncLogs ; since we only have state-sync tx, it will be 0 + types.DeriveFieldsForBorLogs(receipts[i][0].Logs, block.Hash(), block.NumberU64(), uint(0), uint(0)) + + rawdb.WriteBorReceipt(blockBatch, block.Hash(), block.NumberU64(), &types.ReceiptForStorage{ + Status: types.ReceiptStatusSuccessful, // make receipt status successful + Logs: receipts[i][0].Logs, + }) + + rawdb.WriteBorTxLookupEntry(blockBatch, block.Hash(), block.NumberU64()) + } + + if err := blockBatch.Write(); err != nil { + fmt.Println("Failed to write block into disk", "err", err) + } + } + + filter := filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4, hash5}}) + + logs, _ := filter.Logs(context.Background()) + if len(logs) != 5 { + t.Error("expected 5 log, got", len(logs)) + } + + filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}) + logs, _ = filter.Logs(context.Background()) + + if len(logs) != 1 { + t.Error("expected 1 log, got", len(logs)) + } + + if len(logs) > 0 && logs[0].Topics[0] != hash3 { + t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) + } + + filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 992, -1, []common.Address{addr}, [][]common.Hash{{hash3}}) + logs, _ = filter.Logs(context.Background()) + + if len(logs) != 1 { + t.Error("expected 1 log, got", len(logs)) + } + + if len(logs) > 0 && logs[0].Topics[0] != hash3 { + t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) + } + + filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 1, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2}}) + + logs, _ = filter.Logs(context.Background()) + if len(logs) != 2 { + t.Error("expected 2 log, got", len(logs)) + } + + failHash := common.BytesToHash([]byte("fail")) + filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, -1, nil, [][]common.Hash{{failHash}}) + + logs, _ = filter.Logs(context.Background()) + if len(logs) != 0 { + t.Error("expected 0 log, got", len(logs)) + } + + failAddr := common.BytesToAddress([]byte("failmenow")) + filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, -1, []common.Address{failAddr}, nil) + + logs, _ = filter.Logs(context.Background()) + if len(logs) != 0 { + t.Error("expected 0 log, got", len(logs)) + } + + filter = filters.NewBorBlockLogsRangeFilter(backend, testBorConfig, 0, -1, nil, [][]common.Hash{{failHash}, {hash1}}) + + logs, _ = filter.Logs(context.Background()) + if len(logs) != 0 { + t.Error("expected 0 log, got", len(logs)) + } +} diff --git a/tests/bor/bor_sprint_length_change_test.go b/tests/bor/bor_sprint_length_change_test.go new file mode 100644 index 0000000000..fed05751d4 --- /dev/null +++ b/tests/bor/bor_sprint_length_change_test.go @@ -0,0 +1,855 @@ +package bor + +import ( + "crypto/ecdsa" + "encoding/csv" + "encoding/json" + "fmt" + "io/ioutil" // nolint: staticcheck + _log "log" + "math/big" + "os" + "sync" + "testing" + "time" + + "gotest.tools/assert" + + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/fdlimit" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/downloader" + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/miner" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/params" +) + +var ( + + // Only this account is a validator for the 0th span + keySprintLength, _ = crypto.HexToECDSA(privKeySprintLength) + + // This account is one the validators for 1st span (0-indexed) + keySprintLength2, _ = crypto.HexToECDSA(privKeySprintLength2) + + keysSprintLength = []*ecdsa.PrivateKey{keySprintLength, keySprintLength2} +) + +const ( + privKeySprintLength = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" + privKeySprintLength2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3" +) + +// Sprint length change tests +func TestValidatorsBlockProduction(t *testing.T) { + t.Parallel() + + log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + + _, err := fdlimit.Raise(2048) + + if err != nil { + panic(err) + } + + // Generate a batch of accounts to seal and fund with + faucets := make([]*ecdsa.PrivateKey, 128) + for i := 0; i < len(faucets); i++ { + faucets[i], _ = crypto.GenerateKey() + } + + // Create an Ethash network based off of the Ropsten config + // Generate a batch of accounts to seal and fund with + genesis := InitGenesisSprintLength(t, faucets, "./testdata/genesis_sprint_length_change.json", 8) + + nodes := make([]*eth.Ethereum, 2) + enodes := make([]*enode.Node, 2) + + for i := 0; i < 2; i++ { + // Start the node and wait until it's up + stack, ethBackend, err := InitMinerSprintLength(genesis, keysSprintLength[i], true) + if err != nil { + panic(err) + } + defer stack.Close() + + for stack.Server().NodeInfo().Ports.Listener == 0 { + time.Sleep(250 * time.Millisecond) + } + // Connect the node to all the previous ones + for j, n := range enodes { + if j < i { + stack.Server().AddPeer(n) + } + } + // Start tracking the node and its enode + nodes[i] = ethBackend + enodes[i] = stack.Server().Self() + } + + // Iterate over all the nodes and start mining + time.Sleep(3 * time.Second) + + for _, node := range nodes { + if err := node.StartMining(1); err != nil { + panic(err) + } + } + + for { + // for block 0 to 7, the primary validator is node0 + // for block 8 to 15, the primary validator is node1 + // for block 16 to 19, the primary validator is node0 + // for block 20 to 23, the primary validator is node1 + blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader() + + if blockHeaderVal0.Number.Uint64() == 24 { + break + } + } + + // check block 7 miner ; expected author is node0 signer + blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(7) + blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(7) + authorVal0, err := nodes[0].Engine().Author(blockHeaderVal0) + + if err != nil { + log.Error("Error in getting author", "err", err) + } + + authorVal1, err := nodes[1].Engine().Author(blockHeaderVal1) + + if err != nil { + log.Error("Error in getting author", "err", err) + } + + // check both nodes have the same block 7 + assert.Equal(t, authorVal0, authorVal1) + + // check block mined by node0 + assert.Equal(t, authorVal0, nodes[0].AccountManager().Accounts()[0]) + + // check block 15 miner ; expected author is node1 signer + blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(15) + blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(15) + authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0) + + if err != nil { + log.Error("Error in getting author", "err", err) + } + + authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1) + + if err != nil { + log.Error("Error in getting author", "err", err) + } + + // check both nodes have the same block 15 + assert.Equal(t, authorVal0, authorVal1) + + // check block mined by node1 + assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0]) + + // check block 19 miner ; expected author is node0 signer + blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(19) + blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(19) + authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0) + + if err != nil { + log.Error("Error in getting author", "err", err) + } + + authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1) + + if err != nil { + log.Error("Error in getting author", "err", err) + } + + // check both nodes have the same block 19 + assert.Equal(t, authorVal0, authorVal1) + + // check block mined by node0 + assert.Equal(t, authorVal0, nodes[0].AccountManager().Accounts()[0]) + + // check block 23 miner ; expected author is node1 signer + blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(23) + blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(23) + authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0) + + if err != nil { + log.Error("Error in getting author", "err", err) + } + + authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1) + + if err != nil { + log.Error("Error in getting author", "err", err) + } + + // check both nodes have the same block 23 + assert.Equal(t, authorVal0, authorVal1) + + // check block mined by node1 + assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0]) +} + +func TestSprintLengths(t *testing.T) { + t.Parallel() + + testBorConfig := params.TestChainConfig.Bor + testBorConfig.Sprint = map[string]uint64{ + "0": 16, + "8": 4, + } + assert.Equal(t, testBorConfig.CalculateSprint(0), uint64(16)) + assert.Equal(t, testBorConfig.CalculateSprint(8), uint64(4)) + assert.Equal(t, testBorConfig.CalculateSprint(9), uint64(4)) +} + +func TestProducerDelay(t *testing.T) { + t.Parallel() + + testBorConfig := params.TestChainConfig.Bor + testBorConfig.ProducerDelay = map[string]uint64{ + "0": 16, + "8": 4, + } + assert.Equal(t, testBorConfig.CalculateProducerDelay(0), uint64(16)) + assert.Equal(t, testBorConfig.CalculateProducerDelay(8), uint64(4)) + assert.Equal(t, testBorConfig.CalculateProducerDelay(9), uint64(4)) +} + +var keys_21val = []map[string]string{ + { + "address": "0x5C3E1B893B9315a968fcC6bce9EB9F7d8E22edB3", + "priv_key": "c19fac8e538447124ad2408d9fbaeda2bb686fee763dca7a6bab58ea12442413", + "pub_key": "0x0495421933eda03dcc37f9186c24e255b569513aefae71e96d55d0db3df17502e24e86297b01a167fab9ce1174f06ee3110510ac242e39218bd964de5b345edbd6", + }, + { + "address": "0x73E033779C9030D4528d86FbceF5B02e97488921", + "priv_key": "61eb51cf8936309151ab7b931841ea033b6a09931f6a100b464fbbd74f3e0bd7", + "pub_key": "0x04f9a5e9bf76b45ac58f1b018ccba4b83b3531010cdadf42174c18a9db9879ef1dcb5d1254ce834bc108b110cd8d0186ed69a0387528a142bdb5936faf58bf98c9", + }, + { + "address": "0x751eC4877450B8a4D652d0D70197337FC38a42e6", + "priv_key": "6e7f48d012c9c0baadbdc88af32521e2e477fd6898a9b65e6abe19fd6652cb2e", + "pub_key": "0x0479db4c0b757bf0e5d9b8954b078ab7c0e91d6c19697904d23d07ea4853c8584382de91174929ba5c598214b8a991471ae051458ea787cdc15a4e435a55ef8059", + }, + { + "address": "0xA464DC4810Bc79B956810759e314d85BcE35cD1c", + "priv_key": "3efcf3f7014a6257f4a443119851414111820c681b27525dab3f35e72e28e51e", + "pub_key": "0x040180920306bf598ea050e258f2c7e50804a77a64f5a11705e08d18ee71eb0a80fafc95d0a42b92371ded042edda16c1f0b5f2fef7c4113ad66c59a71c29d977e", + }, + { + "address": "0xb005bc07015170266Bd430f3EC1322938603be20", + "priv_key": "17cd9b38c2b3a639c7d97ccbf2bb6c7140ab8f625aec4c249bc8e4cfd3bf9a96", + "pub_key": "0x04435a70d343aa569e6f3386c73e39a1aa6f88c30e5943baedda9618b55cc944a2de1d114aff6d0e9fa002bebc780b04ef6c1b8a06bbf0d41c10d1efa55390f198", + }, + { + "address": "0xE8d02Da3dFeeB3e755472D95D666BD6821D92129", + "priv_key": "45c9ef66361a2283cef14184f128c41949103b791aa622ead3c0bc844648b835", + "pub_key": "0x04a14651ddc80467eb589d72d95153fa695e4cb2e4bb99edeb912e840d309d61313b6f4676081b099f29e6598ecf98cb7b44bb862d019920718b558f27ba94ca51", + }, + { + "address": "0xF93B54Cf36E917f625B48e1e3C9F93BC2344Fb06", + "priv_key": "93788a1305605808df1f9a96b5e1157da191680cf08bc15e077138f517563cd5", + "pub_key": "0x045eee11dceccd9cccc371ca3d96d74c848e785223f1e5df4d1a7f08efdfeb90bd8f0035342a9c26068cf6c7ab395ca3ceea555541325067fc187c375390efa57d", + }, +} + +func getTestSprintLengthReorgCases2Nodes() []map[string]interface{} { + sprintSizes := []uint64{64} + faultyNodes := [][]uint64{{0, 1}, {1, 2}, {0, 2}} + reorgsLengthTests := make([]map[string]interface{}, 0) + + for i := uint64(0); i < uint64(len(sprintSizes)); i++ { + maxReorgLength := sprintSizes[i] * 4 + for j := uint64(20); j <= maxReorgLength; j = j + 8 { + maxStartBlock := sprintSizes[i] - 1 + for k := sprintSizes[i] / 2; k <= maxStartBlock; k = k + 4 { + for l := uint64(0); l < uint64(len(faultyNodes)); l++ { + if j+k < sprintSizes[i] { + continue + } + + reorgsLengthTest := map[string]interface{}{ + "reorgLength": j, + "startBlock": k, + "sprintSize": sprintSizes[i], + "faultyNodes": faultyNodes[l], // node 1(index) is primary validator of the first sprint + } + reorgsLengthTests = append(reorgsLengthTests, reorgsLengthTest) + } + } + } + } + // reorgsLengthTests := []map[string]uint64{ + // { + // "reorgLength": 3, + // "startBlock": 7, + // "sprintSize": 8, + // "faultyNode": 1, + // }, + // } + return reorgsLengthTests +} + +func getTestSprintLengthReorgCases() []map[string]uint64 { + sprintSizes := []uint64{64, 32, 16, 8} + faultyNodes := []uint64{0, 1} + reorgsLengthTests := make([]map[string]uint64, 0) + + for i := uint64(0); i < uint64(len(sprintSizes)); i++ { + maxReorgLength := sprintSizes[i] * 4 + for j := uint64(3); j <= maxReorgLength; j = j + 4 { + maxStartBlock := sprintSizes[i] - 1 + for k := sprintSizes[i] / 2; k <= maxStartBlock; k = k + 4 { + for l := uint64(0); l < uint64(len(faultyNodes)); l++ { + if j+k < sprintSizes[i] { + continue + } + + reorgsLengthTest := map[string]uint64{ + "reorgLength": j, + "startBlock": k, + "sprintSize": sprintSizes[i], + "faultyNode": faultyNodes[l], // node 1(index) is primary validator of the first sprint + } + reorgsLengthTests = append(reorgsLengthTests, reorgsLengthTest) + } + } + } + } + // reorgsLengthTests := []map[string]uint64{ + // { + // "reorgLength": 3, + // "startBlock": 7, + // "sprintSize": 8, + // "faultyNode": 1, + // }, + // } + return reorgsLengthTests +} + +func SprintLengthReorgIndividual(t *testing.T, index int, tt map[string]uint64) (uint64, uint64, uint64, uint64, uint64, uint64) { + t.Helper() + + log.Warn("Case ----- ", "Index", index, "InducedReorgLength", tt["reorgLength"], "BlockStart", tt["startBlock"], "SprintSize", tt["sprintSize"], "DisconnectedNode", tt["faultyNode"]) + observerOldChainLength, faultyOldChainLength := SetupValidatorsAndTest(t, tt) + + if observerOldChainLength > 0 { + log.Warn("Observer", "Old Chain length", observerOldChainLength) + } + + if faultyOldChainLength > 0 { + log.Warn("Faulty", "Old Chain length", faultyOldChainLength) + } + + return tt["reorgLength"], tt["startBlock"], tt["sprintSize"], tt["faultyNode"], faultyOldChainLength, observerOldChainLength +} + +func SprintLengthReorgIndividual2Nodes(t *testing.T, index int, tt map[string]interface{}) (uint64, uint64, uint64, []uint64, uint64, uint64) { + t.Helper() + + log.Warn("Case ----- ", "Index", index, "InducedReorgLength", tt["reorgLength"], "BlockStart", tt["startBlock"], "SprintSize", tt["sprintSize"], "DisconnectedNode", tt["faultyNodes"]) + observerOldChainLength, faultyOldChainLength := SetupValidatorsAndTest2Nodes(t, tt) + + if observerOldChainLength > 0 { + log.Warn("Observer", "Old Chain length", observerOldChainLength) + } + + if faultyOldChainLength > 0 { + log.Warn("Faulty", "Old Chain length", faultyOldChainLength) + } + + fNodes, _ := tt["faultyNodes"].([]uint64) + + return tt["reorgLength"].(uint64), tt["startBlock"].(uint64), tt["sprintSize"].(uint64), fNodes, faultyOldChainLength, observerOldChainLength +} + +func TestSprintLengthReorg2Nodes(t *testing.T) { + t.Skip() + t.Parallel() + + log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + + _, err := fdlimit.Raise(2048) + + if err != nil { + panic(err) + } + + reorgsLengthTests := getTestSprintLengthReorgCases2Nodes() + f, err := os.Create("sprintReorg2Nodes.csv") + + defer func() { + err = f.Close() + + if err != nil { + panic(err) + } + }() + + if err != nil { + _log.Fatalln("failed to open file", err) + } + + w := csv.NewWriter(f) + err = w.Write([]string{"Induced Reorg Length", "Start Block", "Sprint Size", "Disconnected Node Ids", "Disconnected Node Id's Reorg Length", "Observer Node Id's Reorg Length"}) + w.Flush() + + if err != nil { + panic(err) + } + + var wg sync.WaitGroup + + for index, tt := range reorgsLengthTests { + if index%4 == 0 { + wg.Wait() + } + + wg.Add(1) + + go SprintLengthReorgIndividual2NodesHelper(t, index, tt, w, &wg) + } +} + +func TestSprintLengthReorg(t *testing.T) { + t.Skip() + t.Parallel() + + reorgsLengthTests := getTestSprintLengthReorgCases() + f, err := os.Create("sprintReorg.csv") + + defer func() { + err = f.Close() + + if err != nil { + panic(err) + } + }() + + if err != nil { + _log.Fatalln("failed to open file", err) + } + + w := csv.NewWriter(f) + err = w.Write([]string{"Induced Reorg Length", "Start Block", "Sprint Size", "Disconnected Node Id", "Disconnected Node Id's Reorg Length", "Observer Node Id's Reorg Length"}) + w.Flush() + + if err != nil { + panic(err) + } + + var wg sync.WaitGroup + + for index, tt := range reorgsLengthTests { + if index%4 == 0 { + wg.Wait() + } + + wg.Add(1) + + go SprintLengthReorgIndividualHelper(t, index, tt, w, &wg) + } +} + +func SprintLengthReorgIndividualHelper(t *testing.T, index int, tt map[string]uint64, w *csv.Writer, wg *sync.WaitGroup) { + t.Helper() + + r1, r2, r3, r4, r5, r6 := SprintLengthReorgIndividual(t, index, tt) + err := w.Write([]string{fmt.Sprint(r1), fmt.Sprint(r2), fmt.Sprint(r3), fmt.Sprint(r4), fmt.Sprint(r5), fmt.Sprint(r6)}) + + if err != nil { + panic(err) + } + + w.Flush() + (*wg).Done() +} + +func SprintLengthReorgIndividual2NodesHelper(t *testing.T, index int, tt map[string]interface{}, w *csv.Writer, wg *sync.WaitGroup) { + t.Helper() + + r1, r2, r3, r4, r5, r6 := SprintLengthReorgIndividual2Nodes(t, index, tt) + err := w.Write([]string{fmt.Sprint(r1), fmt.Sprint(r2), fmt.Sprint(r3), fmt.Sprint(r4), fmt.Sprint(r5), fmt.Sprint(r6)}) + + if err != nil { + panic(err) + } + + w.Flush() + (*wg).Done() +} + +// nolint: gocognit +func SetupValidatorsAndTest(t *testing.T, tt map[string]uint64) (uint64, uint64) { + t.Helper() + + log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + + _, err := fdlimit.Raise(2048) + + if err != nil { + panic(err) + } + + // Generate a batch of accounts to seal and fund with + faucets := make([]*ecdsa.PrivateKey, 128) + for i := 0; i < len(faucets); i++ { + faucets[i], _ = crypto.GenerateKey() + } + + // Create an Ethash network based off of the Ropsten config + // Generate a batch of accounts to seal and fund with + genesis := InitGenesisSprintLength(t, faucets, "./testdata/genesis_7val.json", tt["sprintSize"]) + + nodes := make([]*eth.Ethereum, len(keys_21val)) + enodes := make([]*enode.Node, len(keys_21val)) + stacks := make([]*node.Node, len(keys_21val)) + + pkeys_21val := make([]*ecdsa.PrivateKey, len(keys_21val)) + + for index, signerdata := range keys_21val { + pkeys_21val[index], _ = crypto.HexToECDSA(signerdata["priv_key"]) + } + + for i := 0; i < len(keys_21val); i++ { + // Start the node and wait until it's up + stack, ethBackend, err := InitMinerSprintLength(genesis, pkeys_21val[i], true) + if err != nil { + panic(err) + } + defer stack.Close() + + for stack.Server().NodeInfo().Ports.Listener == 0 { + time.Sleep(250 * time.Millisecond) + } + // Connect the node to all the previous ones + for j, n := range enodes { + if j < i { + stack.Server().AddPeer(n) + } + } + // Start tracking the node and its enode + stacks[i] = stack + nodes[i] = ethBackend + enodes[i] = stack.Server().Self() + } + + // Iterate over all the nodes and start mining + time.Sleep(3 * time.Second) + + for _, node := range nodes { + if err := node.StartMining(1); err != nil { + panic(err) + } + } + + chain2HeadChObserver := make(chan core.Chain2HeadEvent, 64) + chain2HeadChFaulty := make(chan core.Chain2HeadEvent, 64) + + var observerOldChainLength, faultyOldChainLength uint64 + + faultyProducerIndex := tt["faultyNode"] // node causing reorg :: faulty :: + subscribedNodeIndex := 6 // node on different partition, produces 7th sprint but our testcase does not run till 7th sprint. :: observer :: + + nodes[subscribedNodeIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChObserver) + nodes[faultyProducerIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChFaulty) + + stacks[faultyProducerIndex].Server().NoDiscovery = true + + for { + blockHeaderObserver := nodes[subscribedNodeIndex].BlockChain().CurrentHeader() + blockHeaderFaulty := nodes[faultyProducerIndex].BlockChain().CurrentHeader() + + log.Warn("Current Observer block", "number", blockHeaderObserver.Number, "hash", blockHeaderObserver.Hash()) + log.Warn("Current Faulty block", "number", blockHeaderFaulty.Number, "hash", blockHeaderFaulty.Hash()) + + if blockHeaderFaulty.Number.Uint64() == tt["startBlock"] { + stacks[faultyProducerIndex].Server().MaxPeers = 0 + + for _, enode := range enodes { + stacks[faultyProducerIndex].Server().RemovePeer(enode) + } + } + + if blockHeaderObserver.Number.Uint64() >= tt["startBlock"] && blockHeaderObserver.Number.Uint64() < tt["startBlock"]+tt["reorgLength"] { + for _, enode := range enodes { + stacks[faultyProducerIndex].Server().RemovePeer(enode) + } + } + + if blockHeaderObserver.Number.Uint64() == tt["startBlock"]+tt["reorgLength"] { + stacks[faultyProducerIndex].Server().NoDiscovery = false + stacks[faultyProducerIndex].Server().MaxPeers = 100 + + for _, enode := range enodes { + stacks[faultyProducerIndex].Server().AddPeer(enode) + } + } + + if blockHeaderFaulty.Number.Uint64() >= 255 { + break + } + + select { + case ev := <-chain2HeadChObserver: + if ev.Type == core.Chain2HeadReorgEvent { + if len(ev.OldChain) > 1 { + observerOldChainLength = uint64(len(ev.OldChain)) + return observerOldChainLength, 0 + } + } + + case ev := <-chain2HeadChFaulty: + if ev.Type == core.Chain2HeadReorgEvent { + if len(ev.OldChain) > 1 { + faultyOldChainLength = uint64(len(ev.OldChain)) + return 0, faultyOldChainLength + } + } + + default: + time.Sleep(500 * time.Millisecond) + } + } + + return 0, 0 +} + +// nolint: gocognit +func SetupValidatorsAndTest2Nodes(t *testing.T, tt map[string]interface{}) (uint64, uint64) { + t.Helper() + + log.Root().SetHandler(log.LvlFilterHandler(3, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + + _, err := fdlimit.Raise(2048) + + if err != nil { + panic(err) + } + + // Generate a batch of accounts to seal and fund with + faucets := make([]*ecdsa.PrivateKey, 128) + for i := 0; i < len(faucets); i++ { + faucets[i], _ = crypto.GenerateKey() + } + + // Create an Ethash network based off of the Ropsten config + // Generate a batch of accounts to seal and fund with + genesis := InitGenesisSprintLength(t, faucets, "./testdata/genesis_7val.json", tt["sprintSize"].(uint64)) + + nodes := make([]*eth.Ethereum, len(keys_21val)) + enodes := make([]*enode.Node, len(keys_21val)) + stacks := make([]*node.Node, len(keys_21val)) + + pkeys_21val := make([]*ecdsa.PrivateKey, len(keys_21val)) + + for index, signerdata := range keys_21val { + pkeys_21val[index], _ = crypto.HexToECDSA(signerdata["priv_key"]) + } + + for i := 0; i < len(keys_21val); i++ { + // Start the node and wait until it's up + stack, ethBackend, err := InitMinerSprintLength(genesis, pkeys_21val[i], true) + if err != nil { + panic(err) + } + defer stack.Close() + + for stack.Server().NodeInfo().Ports.Listener == 0 { + time.Sleep(250 * time.Millisecond) + } + // Connect the node to all the previous ones + for j, n := range enodes { + if j < i { + stack.Server().AddPeer(n) + } + } + // Start tracking the node and its enode + stacks[i] = stack + nodes[i] = ethBackend + enodes[i] = stack.Server().Self() + } + + // Iterate over all the nodes and start mining + time.Sleep(3 * time.Second) + + for _, node := range nodes { + if err := node.StartMining(1); err != nil { + panic(err) + } + } + + chain2HeadChObserver := make(chan core.Chain2HeadEvent, 64) + chain2HeadChFaulty := make(chan core.Chain2HeadEvent, 64) + + var observerOldChainLength, faultyOldChainLength uint64 + + faultyProducerIndex := tt["faultyNodes"].([]uint64)[0] // node causing reorg :: faulty :: + subscribedNodeIndex := 6 // node on different partition, produces 7th sprint but our testcase does not run till 7th sprint. :: observer :: + + nodes[subscribedNodeIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChObserver) + nodes[faultyProducerIndex].BlockChain().SubscribeChain2HeadEvent(chain2HeadChFaulty) + + stacks[faultyProducerIndex].Server().NoDiscovery = true + + for { + blockHeaderObserver := nodes[subscribedNodeIndex].BlockChain().CurrentHeader() + blockHeaderFaulty := nodes[faultyProducerIndex].BlockChain().CurrentHeader() + + log.Warn("Current Observer block", "number", blockHeaderObserver.Number, "hash", blockHeaderObserver.Hash()) + log.Warn("Current Faulty block", "number", blockHeaderFaulty.Number, "hash", blockHeaderFaulty.Hash()) + + if blockHeaderObserver.Number.Uint64() >= tt["startBlock"].(uint64) && blockHeaderObserver.Number.Uint64() < tt["startBlock"].(uint64)+tt["reorgLength"].(uint64) { + for _, n := range tt["faultyNodes"].([]uint64) { + stacks[n].Server().MaxPeers = 1 + + for _, enode := range enodes { + stacks[n].Server().RemovePeer(enode) + } + + for _, m := range tt["faultyNodes"].([]uint64) { + stacks[m].Server().AddPeer(enodes[n]) + } + } + } + + if blockHeaderObserver.Number.Uint64() == tt["startBlock"].(uint64)+tt["reorgLength"].(uint64) { + stacks[faultyProducerIndex].Server().NoDiscovery = false + stacks[faultyProducerIndex].Server().MaxPeers = 100 + + for _, enode := range enodes { + stacks[faultyProducerIndex].Server().AddPeer(enode) + } + } + + if blockHeaderFaulty.Number.Uint64() >= 255 { + break + } + + select { + case ev := <-chain2HeadChObserver: + if ev.Type == core.Chain2HeadReorgEvent { + if len(ev.OldChain) > 1 { + observerOldChainLength = uint64(len(ev.OldChain)) + return observerOldChainLength, 0 + } + } + + case ev := <-chain2HeadChFaulty: + if ev.Type == core.Chain2HeadReorgEvent { + if len(ev.OldChain) > 1 { + faultyOldChainLength = uint64(len(ev.OldChain)) + return 0, faultyOldChainLength + } + } + + default: + time.Sleep(500 * time.Millisecond) + } + } + + return 0, 0 +} + +func InitGenesisSprintLength(t *testing.T, faucets []*ecdsa.PrivateKey, fileLocation string, sprintSize uint64) *core.Genesis { + t.Helper() + + // sprint size = 8 in genesis + genesisData, err := ioutil.ReadFile(fileLocation) + if err != nil { + t.Fatalf("%s", err) + } + + genesis := &core.Genesis{} + + if err := json.Unmarshal(genesisData, genesis); err != nil { + t.Fatalf("%s", err) + } + + genesis.Config.ChainID = big.NewInt(15001) + genesis.Config.EIP150Hash = common.Hash{} + genesis.Config.Bor.Sprint["0"] = sprintSize + + return genesis +} + +func InitMinerSprintLength(genesis *core.Genesis, privKey *ecdsa.PrivateKey, withoutHeimdall bool) (*node.Node, *eth.Ethereum, error) { + // Define the basic configurations for the Ethereum node + datadir, _ := ioutil.TempDir("", "") + + config := &node.Config{ + Name: "geth", + Version: params.Version, + DataDir: datadir, + P2P: p2p.Config{ + ListenAddr: "0.0.0.0:0", + NoDiscovery: true, + MaxPeers: 25, + }, + UseLightweightKDF: true, + } + // Create the node and configure a full Ethereum node on it + stack, err := node.New(config) + if err != nil { + return nil, nil, err + } + + ethBackend, err := eth.New(stack, ðconfig.Config{ + Genesis: genesis, + NetworkId: genesis.Config.ChainID.Uint64(), + SyncMode: downloader.FullSync, + DatabaseCache: 256, + DatabaseHandles: 256, + TxPool: core.DefaultTxPoolConfig, + GPO: ethconfig.Defaults.GPO, + Ethash: ethconfig.Defaults.Ethash, + Miner: miner.Config{ + Etherbase: crypto.PubkeyToAddress(privKey.PublicKey), + GasCeil: genesis.GasLimit * 11 / 10, + GasPrice: big.NewInt(1), + Recommit: time.Second, + }, + WithoutHeimdall: withoutHeimdall, + }) + + if err != nil { + return nil, nil, err + } + + // register backend to account manager with keystore for signing + keydir := stack.KeyStoreDir() + + n, p := keystore.StandardScryptN, keystore.StandardScryptP + kStore := keystore.NewKeyStore(keydir, n, p) + + _, err = kStore.ImportECDSA(privKey, "") + + if err != nil { + return nil, nil, err + } + + acc := kStore.Accounts()[0] + err = kStore.Unlock(acc, "") + + if err != nil { + return nil, nil, err + } + + // proceed to authorize the local account manager in any case + ethBackend.AccountManager().AddBackend(kStore) + + err = stack.Start() + + return stack, ethBackend, err +} diff --git a/tests/bor/bor_test.go b/tests/bor/bor_test.go index 243b0182bb..d059956e6a 100644 --- a/tests/bor/bor_test.go +++ b/tests/bor/bor_test.go @@ -4,32 +4,365 @@ package bor import ( + "context" + "crypto/ecdsa" "encoding/hex" "io" "math/big" + "os" + "sync" "testing" "time" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golang.org/x/crypto/sha3" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/consensus/bor" "github.com/ethereum/go-ethereum/consensus/bor/clerk" "github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint" - "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" + "github.com/ethereum/go-ethereum/consensus/bor/valset" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/tests/bor/mocks" ) +var ( + // addr1 = 0x71562b71999873DB5b286dF957af199Ec94617F7 + pkey1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + // addr2 = 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791 + pkey2, _ = crypto.HexToECDSA("9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3") +) + +func TestValidatorWentOffline(t *testing.T) { + + log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + fdlimit.Raise(2048) + + // Generate a batch of accounts to seal and fund with + faucets := make([]*ecdsa.PrivateKey, 128) + for i := 0; i < len(faucets); i++ { + faucets[i], _ = crypto.GenerateKey() + } + + // Create an Ethash network based off of the Ropsten config + // Generate a batch of accounts to seal and fund with + genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8) + + var ( + stacks []*node.Node + nodes []*eth.Ethereum + enodes []*enode.Node + ) + for i := 0; i < 2; i++ { + // Start the node and wait until it's up + stack, ethBackend, err := InitMiner(genesis, keys[i], true) + if err != nil { + panic(err) + } + defer stack.Close() + + for stack.Server().NodeInfo().Ports.Listener == 0 { + time.Sleep(250 * time.Millisecond) + } + // Connect the node to all the previous ones + for _, n := range enodes { + stack.Server().AddPeer(n) + } + // Start tracking the node and its enode + stacks = append(stacks, stack) + nodes = append(nodes, ethBackend) + enodes = append(enodes, stack.Server().Self()) + } + + // Iterate over all the nodes and start mining + time.Sleep(3 * time.Second) + for _, node := range nodes { + if err := node.StartMining(1); err != nil { + panic(err) + } + } + + for { + + // for block 1 to 8, the primary validator is node0 + // for block 9 to 16, the primary validator is node1 + // for block 17 to 24, the primary validator is node0 + // for block 25 to 32, the primary validator is node1 + blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader() + + // we remove peer connection between node0 and node1 + if blockHeaderVal0.Number.Uint64() == 9 { + stacks[0].Server().RemovePeer(enodes[1]) + } + + // here, node1 is the primary validator, node0 will sign out-of-turn + + // we add peer connection between node1 and node0 + if blockHeaderVal0.Number.Uint64() == 14 { + stacks[0].Server().AddPeer(enodes[1]) + } + + // reorg happens here, node1 has higher difficulty, it will replace blocks by node0 + + if blockHeaderVal0.Number.Uint64() == 30 { + + break + } + + } + + // check block 10 miner ; expected author is node1 signer + blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(10) + blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(10) + authorVal0, err := nodes[0].Engine().Author(blockHeaderVal0) + if err != nil { + log.Error("Error in getting author", "err", err) + } + authorVal1, err := nodes[1].Engine().Author(blockHeaderVal1) + if err != nil { + log.Error("Error in getting author", "err", err) + } + + // check both nodes have the same block 10 + assert.Equal(t, authorVal0, authorVal1) + + // check node0 has block mined by node1 + assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0]) + + // check node1 has block mined by node1 + assert.Equal(t, authorVal1, nodes[1].AccountManager().Accounts()[0]) + + // check block 11 miner ; expected author is node1 signer + blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(11) + blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(11) + authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0) + if err != nil { + log.Error("Error in getting author", "err", err) + } + authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1) + if err != nil { + log.Error("Error in getting author", "err", err) + } + + // check both nodes have the same block 11 + assert.Equal(t, authorVal0, authorVal1) + + // check node0 has block mined by node1 + assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0]) + + // check node1 has block mined by node1 + assert.Equal(t, authorVal1, nodes[1].AccountManager().Accounts()[0]) + + // check block 12 miner ; expected author is node1 signer + blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(12) + blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(12) + authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0) + if err != nil { + log.Error("Error in getting author", "err", err) + } + authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1) + if err != nil { + log.Error("Error in getting author", "err", err) + } + + // check both nodes have the same block 12 + assert.Equal(t, authorVal0, authorVal1) + + // check node0 has block mined by node1 + assert.Equal(t, authorVal0, nodes[1].AccountManager().Accounts()[0]) + + // check node1 has block mined by node1 + assert.Equal(t, authorVal1, nodes[1].AccountManager().Accounts()[0]) + + // check block 17 miner ; expected author is node0 signer + blockHeaderVal0 = nodes[0].BlockChain().GetHeaderByNumber(17) + blockHeaderVal1 = nodes[1].BlockChain().GetHeaderByNumber(17) + authorVal0, err = nodes[0].Engine().Author(blockHeaderVal0) + if err != nil { + log.Error("Error in getting author", "err", err) + } + authorVal1, err = nodes[1].Engine().Author(blockHeaderVal1) + if err != nil { + log.Error("Error in getting author", "err", err) + } + + // check both nodes have the same block 17 + assert.Equal(t, authorVal0, authorVal1) + + // check node0 has block mined by node1 + assert.Equal(t, authorVal0, nodes[0].AccountManager().Accounts()[0]) + + // check node1 has block mined by node1 + assert.Equal(t, authorVal1, nodes[0].AccountManager().Accounts()[0]) +} + +func TestForkWithBlockTime(t *testing.T) { + + cases := []struct { + name string + sprint map[string]uint64 + blockTime map[string]uint64 + change uint64 + producerDelay map[string]uint64 + forkExpected bool + }{ + { + name: "No fork after 2 sprints with producer delay = max block time", + sprint: map[string]uint64{ + "0": 128, + }, + blockTime: map[string]uint64{ + "0": 5, + "128": 2, + "256": 8, + }, + change: 2, + producerDelay: map[string]uint64{ + "0": 8, + }, + forkExpected: false, + }, + { + name: "No Fork after 1 sprint producer delay = max block time", + sprint: map[string]uint64{ + "0": 64, + }, + blockTime: map[string]uint64{ + "0": 5, + "64": 2, + }, + change: 1, + producerDelay: map[string]uint64{ + "0": 5, + }, + forkExpected: false, + }, + { + name: "Fork after 4 sprints with producer delay < max block time", + sprint: map[string]uint64{ + "0": 16, + }, + blockTime: map[string]uint64{ + "0": 2, + "64": 5, + }, + change: 4, + producerDelay: map[string]uint64{ + "0": 4, + }, + forkExpected: true, + }, + } + + // Create an Ethash network based off of the Ropsten config + // Generate a batch of accounts to seal and fund with + faucets := make([]*ecdsa.PrivateKey, 128) + for i := 0; i < len(faucets); i++ { + faucets[i], _ = crypto.GenerateKey() + } + genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8) + + for _, test := range cases { + t.Run(test.name, func(t *testing.T) { + + genesis.Config.Bor.Sprint = test.sprint + genesis.Config.Bor.Period = test.blockTime + genesis.Config.Bor.BackupMultiplier = test.blockTime + genesis.Config.Bor.ProducerDelay = test.producerDelay + + stacks, nodes, _ := setupMiner(t, 2, genesis) + + defer func() { + for _, stack := range stacks { + stack.Close() + } + }() + + // Iterate over all the nodes and start mining + for _, node := range nodes { + if err := node.StartMining(1); err != nil { + t.Fatal("Error occured while starting miner", "node", node, "error", err) + } + } + var wg sync.WaitGroup + blockHeaders := make([]*types.Header, 2) + ticker := time.NewTicker(time.Duration(test.blockTime["0"]) * time.Second) + defer ticker.Stop() + + for i := 0; i < 2; i++ { + wg.Add(1) + + go func(i int) { + defer wg.Done() + + for range ticker.C { + blockHeaders[i] = nodes[i].BlockChain().GetHeaderByNumber(test.sprint["0"]*test.change + 10) + if blockHeaders[i] != nil { + break + } + } + + }(i) + } + + wg.Wait() + + // Before the end of sprint + blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(test.sprint["0"] - 1) + blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(test.sprint["0"] - 1) + assert.Equal(t, blockHeaderVal0.Hash(), blockHeaderVal1.Hash()) + assert.Equal(t, blockHeaderVal0.Time, blockHeaderVal1.Time) + + author0, err := nodes[0].Engine().Author(blockHeaderVal0) + if err != nil { + t.Error("Error occured while fetching author", "err", err) + } + author1, err := nodes[1].Engine().Author(blockHeaderVal1) + if err != nil { + t.Error("Error occured while fetching author", "err", err) + } + assert.Equal(t, author0, author1) + + // After the end of sprint + author2, err := nodes[0].Engine().Author(blockHeaders[0]) + if err != nil { + t.Error("Error occured while fetching author", "err", err) + } + author3, err := nodes[1].Engine().Author(blockHeaders[1]) + if err != nil { + t.Error("Error occured while fetching author", "err", err) + } + + if test.forkExpected { + assert.NotEqual(t, blockHeaders[0].Hash(), blockHeaders[1].Hash()) + assert.NotEqual(t, blockHeaders[0].Time, blockHeaders[1].Time) + assert.NotEqual(t, author2, author3) + } else { + assert.Equal(t, blockHeaders[0].Hash(), blockHeaders[1].Hash()) + assert.Equal(t, blockHeaders[0].Time, blockHeaders[1].Time) + assert.Equal(t, author2, author3) + } + }) + + } + +} + func TestInsertingSpanSizeBlocks(t *testing.T) { init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) chain := init.ethereum.BlockChain() @@ -38,14 +371,14 @@ func TestInsertingSpanSizeBlocks(t *testing.T) { defer _bor.Close() - h, heimdallSpan, ctrl := getMockedHeimdallClient(t) + _, currentSpan := loadSpanFromFile(t) + + h, ctrl := getMockedHeimdallClient(t, currentSpan) defer ctrl.Finish() - _, span := loadSpanFromFile(t) - h.EXPECT().Close().AnyTimes() - h.EXPECT().FetchLatestCheckpoint().Return(&checkpoint.Checkpoint{ - Proposer: span.SelectedProducers[0].Address, + h.EXPECT().FetchCheckpoint(gomock.Any(), int64(-1)).Return(&checkpoint.Checkpoint{ + Proposer: currentSpan.SelectedProducers[0].Address, StartBlock: big.NewInt(0), EndBlock: big.NewInt(int64(spanSize)), }, nil).AnyTimes() @@ -56,21 +389,23 @@ func TestInsertingSpanSizeBlocks(t *testing.T) { block := init.genesis.ToBlock(db) // to := int64(block.Header().Time) + currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)} + // Insert sprintSize # of blocks so that span is fetched at the start of a new sprint for i := uint64(1); i <= spanSize; i++ { - block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators) insertNewBlock(t, chain, block) } - validators, err := _bor.GetCurrentValidators(block.Hash(), spanSize) // check validator set at the first block of new span + validators, err := _bor.GetCurrentValidators(context.Background(), block.Hash(), spanSize) // check validator set at the first block of new span if err != nil { t.Fatalf("%s", err) } - assert.Equal(t, 3, len(validators)) + require.Equal(t, 3, len(validators)) for i, validator := range validators { - assert.Equal(t, validator.Address.Bytes(), heimdallSpan.SelectedProducers[i].Address.Bytes()) - assert.Equal(t, validator.VotingPower, heimdallSpan.SelectedProducers[i].VotingPower) + require.Equal(t, validator.Address.Bytes(), currentSpan.SelectedProducers[i].Address.Bytes()) + require.Equal(t, validator.VotingPower, currentSpan.SelectedProducers[i].VotingPower) } } @@ -85,27 +420,29 @@ func TestFetchStateSyncEvents(t *testing.T) { // A. Insert blocks for 0th sprint db := init.ethereum.ChainDb() block := init.genesis.ToBlock(db) + + // B.1 Mock /bor/span/1 + res, _ := loadSpanFromFile(t) + + currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)} + // Insert sprintSize # of blocks so that span is fetched at the start of a new sprint for i := uint64(1); i < sprintSize; i++ { - block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + if IsSpanEnd(i) { + currentValidators = res.Result.ValidatorSet.Validators + } + + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators) insertNewBlock(t, chain, block) } // B. Before inserting 1st block of the next sprint, mock heimdall deps - // B.1 Mock /bor/span/1 - res, _ := loadSpanFromFile(t) - ctrl := gomock.NewController(t) defer ctrl.Finish() h := mocks.NewMockIHeimdallClient(ctrl) h.EXPECT().Close().AnyTimes() - h.EXPECT().Span(uint64(1)).Return(&res.Result, nil).AnyTimes() - h.EXPECT().FetchLatestCheckpoint().Return(&checkpoint.Checkpoint{ - StartBlock: big.NewInt(1), - EndBlock: big.NewInt(2), - RootHash: common.Hash{}, - }, nil).AnyTimes() + h.EXPECT().Span(gomock.Any(), uint64(1)).Return(&res.Result, nil).AnyTimes() // B.2 Mock State Sync events fromID := uint64(1) @@ -117,10 +454,10 @@ func TestFetchStateSyncEvents(t *testing.T) { sample.Time = time.Unix(to-int64(eventCount+1), 0) // last event.Time will be just < to eventRecords := generateFakeStateSyncEvents(sample, eventCount) - h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes() + h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes() _bor.SetHeimdallClient(h) - block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators) insertNewBlock(t, chain, block) } @@ -135,17 +472,15 @@ func TestFetchStateSyncEvents_2(t *testing.T) { // Mock /bor/span/1 res, _ := loadSpanFromFile(t) + // add the block producer + res.Result.ValidatorSet.Validators = append(res.Result.ValidatorSet.Validators, valset.NewValidator(addr, 4500)) + ctrl := gomock.NewController(t) defer ctrl.Finish() h := mocks.NewMockIHeimdallClient(ctrl) h.EXPECT().Close().AnyTimes() - h.EXPECT().Span(uint64(1)).Return(&res.Result, nil).AnyTimes() - h.EXPECT().FetchLatestCheckpoint().Return(&checkpoint.Checkpoint{ - StartBlock: big.NewInt(1), - EndBlock: big.NewInt(2), - RootHash: common.Hash{}, - }, nil).AnyTimes() + h.EXPECT().Span(gomock.Any(), uint64(1)).Return(&res.Result, nil).AnyTimes() // Mock State Sync events // at # sprintSize, events are fetched for [fromID, (block-sprint).Time) @@ -164,21 +499,30 @@ func TestFetchStateSyncEvents_2(t *testing.T) { buildStateEvent(sample, 6, 4), // id = 6, time = 4 } - h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes() + h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes() _bor.SetHeimdallClient(h) // Insert blocks for 0th sprint db := init.ethereum.ChainDb() block := init.genesis.ToBlock(db) + + var currentValidators []*valset.Validator + for i := uint64(1); i <= sprintSize; i++ { - block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + if IsSpanEnd(i) { + currentValidators = res.Result.ValidatorSet.Validators + } else { + currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)} + } + + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, currentValidators) insertNewBlock(t, chain, block) } lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize) // state 6 was not written - assert.Equal(t, uint64(4), lastStateID.Uint64()) + require.Equal(t, uint64(4), lastStateID.Uint64()) // fromID = uint64(5) @@ -188,15 +532,21 @@ func TestFetchStateSyncEvents_2(t *testing.T) { buildStateEvent(sample, 5, 7), buildStateEvent(sample, 6, 4), } - h.EXPECT().StateSyncEvents(fromID, to).Return(eventRecords, nil).AnyTimes() + h.EXPECT().StateSyncEvents(gomock.Any(), fromID, to).Return(eventRecords, nil).AnyTimes() for i := sprintSize + 1; i <= spanSize; i++ { - block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + if IsSpanEnd(i) { + currentValidators = res.Result.ValidatorSet.Validators + } else { + currentValidators = []*valset.Validator{valset.NewValidator(addr, 10)} + } + + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators) insertNewBlock(t, chain, block) } lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize) - assert.Equal(t, uint64(6), lastStateID.Uint64()) + require.Equal(t, uint64(6), lastStateID.Uint64()) } func TestOutOfTurnSigning(t *testing.T) { @@ -207,17 +557,29 @@ func TestOutOfTurnSigning(t *testing.T) { defer _bor.Close() - h, _, ctrl := getMockedHeimdallClient(t) + _, heimdallSpan := loadSpanFromFile(t) + proposer := valset.NewValidator(addr, 10) + heimdallSpan.ValidatorSet.Validators = append(heimdallSpan.ValidatorSet.Validators, proposer) + + // add the block producer + h, ctrl := getMockedHeimdallClient(t, heimdallSpan) defer ctrl.Finish() h.EXPECT().Close().AnyTimes() + _bor.SetHeimdallClient(h) db := init.ethereum.ChainDb() block := init.genesis.ToBlock(db) + setDifficulty := func(header *types.Header) { + if IsSprintStart(header.Number.Uint64()) { + header.Difficulty = big.NewInt(int64(len(heimdallSpan.ValidatorSet.Validators))) + } + } + for i := uint64(1); i < spanSize; i++ { - block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, heimdallSpan.ValidatorSet.Validators, setDifficulty) insertNewBlock(t, chain, block) } @@ -225,34 +587,50 @@ func TestOutOfTurnSigning(t *testing.T) { // This account is one the out-of-turn validators for 1st (0-indexed) span signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9" signerKey, _ := hex.DecodeString(signer) - key, _ = crypto.HexToECDSA(signer) - addr = crypto.PubkeyToAddress(key.PublicKey) + newKey, _ := crypto.HexToECDSA(signer) + newAddr := crypto.PubkeyToAddress(newKey.PublicKey) expectedSuccessionNumber := 2 - block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor) - _, err := chain.InsertChain([]*types.Block{block}) - assert.Equal(t, - *err.(*bor.BlockTooSoonError), - bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber}) + parentTime := block.Time() - expectedDifficulty := uint64(3 - expectedSuccessionNumber) // len(validators) - succession + setParentTime := func(header *types.Header) { + header.Time = parentTime + 1 + } + + const turn = 1 + + setDifficulty = func(header *types.Header) { + header.Difficulty = big.NewInt(int64(len(heimdallSpan.ValidatorSet.Validators)) - turn) + } + + block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor, nil, heimdallSpan.ValidatorSet.Validators, setParentTime, setDifficulty) + _, err := chain.InsertChain([]*types.Block{block}) + require.Equal(t, + bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber}, + *err.(*bor.BlockTooSoonError)) + + expectedDifficulty := uint64(len(heimdallSpan.ValidatorSet.Validators) - expectedSuccessionNumber - turn) // len(validators) - succession header := block.Header() - header.Time += (bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) - - bor.CalcProducerDelay(header.Number.Uint64(), 0, init.genesis.Config.Bor)) + + diff := bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) + header.Time += diff + sign(t, header, signerKey, init.genesis.Config.Bor) + block = types.NewBlockWithHeader(header) _, err = chain.InsertChain([]*types.Block{block}) - assert.Equal(t, - *err.(*bor.WrongDifficultyError), - bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: addr.Bytes()}) + require.NotNil(t, err) + require.Equal(t, + bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: newAddr.Bytes()}, + *err.(*bor.WrongDifficultyError)) header.Difficulty = new(big.Int).SetUint64(expectedDifficulty) sign(t, header, signerKey, init.genesis.Config.Bor) block = types.NewBlockWithHeader(header) _, err = chain.InsertChain([]*types.Block{block}) - assert.Nil(t, err) + require.Nil(t, err) } func TestSignerNotFound(t *testing.T) { @@ -263,7 +641,9 @@ func TestSignerNotFound(t *testing.T) { defer _bor.Close() - h, _, ctrl := getMockedHeimdallClient(t) + _, heimdallSpan := loadSpanFromFile(t) + + h, ctrl := getMockedHeimdallClient(t, heimdallSpan) defer ctrl.Finish() h.EXPECT().Close().AnyTimes() @@ -274,64 +654,21 @@ func TestSignerNotFound(t *testing.T) { block := init.genesis.ToBlock(db) // random signer account that is not a part of the validator set - signer := "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b" + const signer = "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b" signerKey, _ := hex.DecodeString(signer) - key, _ = crypto.HexToECDSA(signer) - addr = crypto.PubkeyToAddress(key.PublicKey) + newKey, _ := crypto.HexToECDSA(signer) + newAddr := crypto.PubkeyToAddress(newKey.PublicKey) + + _bor.Authorize(newAddr, func(account accounts.Account, s string, data []byte) ([]byte, error) { + return crypto.Sign(crypto.Keccak256(data), newKey) + }) + + block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor, nil, heimdallSpan.ValidatorSet.Validators) - block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor) _, err := chain.InsertChain([]*types.Block{block}) - assert.Equal(t, + require.Equal(t, *err.(*bor.UnauthorizedSignerError), - bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()}) -} - -func getMockedHeimdallClient(t *testing.T) (*mocks.MockIHeimdallClient, *span.HeimdallSpan, *gomock.Controller) { - ctrl := gomock.NewController(t) - h := mocks.NewMockIHeimdallClient(ctrl) - - _, heimdallSpan := loadSpanFromFile(t) - - h.EXPECT().Span(uint64(1)).Return(heimdallSpan, nil).AnyTimes() - - h.EXPECT().StateSyncEvents(gomock.Any(), gomock.Any()). - Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes() - - // h.EXPECT().FetchLatestCheckpoint().Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes() - - return h, heimdallSpan, ctrl -} - -func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime { - events := make([]*clerk.EventRecordWithTime, count) - event := *sample - event.ID = 1 - events[0] = &clerk.EventRecordWithTime{} - *events[0] = event - for i := 1; i < count; i++ { - event.ID = uint64(i) - event.Time = event.Time.Add(1 * time.Second) - events[i] = &clerk.EventRecordWithTime{} - *events[i] = event - } - return events -} - -func buildStateEvent(sample *clerk.EventRecordWithTime, id uint64, timeStamp int64) *clerk.EventRecordWithTime { - event := *sample - event.ID = id - event.Time = time.Unix(timeStamp, 0) - return &event -} - -func getSampleEventRecord(t *testing.T) *clerk.EventRecordWithTime { - eventRecords := stateSyncEventsPayload(t) - eventRecords.Result[0].Time = time.Unix(1, 0) - return eventRecords.Result[0] -} - -func getEventRecords(t *testing.T) []*clerk.EventRecordWithTime { - return stateSyncEventsPayload(t).Result + bor.UnauthorizedSignerError{Number: 0, Signer: newAddr.Bytes()}) } // TestEIP1559Transition tests the following: @@ -361,7 +698,7 @@ func TestEIP1559Transition(t *testing.T) { addr3 = crypto.PubkeyToAddress(key3.PublicKey) funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) gspec = &core.Genesis{ - Config: params.BorTestChainConfig, + Config: params.BorUnittestChainConfig, Alloc: core.GenesisAlloc{ addr1: {Balance: funds}, addr2: {Balance: funds}, @@ -413,7 +750,7 @@ func TestEIP1559Transition(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -443,7 +780,7 @@ func TestEIP1559Transition(t *testing.T) { } // check burnt contract balance - actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64()))) + actual = state.GetBalance(common.HexToAddress(params.BorUnittestChainConfig.Bor.CalculateBurntContract(block.NumberU64()))) expected = new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee()) burntContractBalance := expected if actual.Cmp(expected) != 0 { @@ -491,7 +828,7 @@ func TestEIP1559Transition(t *testing.T) { } // check burnt contract balance - actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64()))) + actual = state.GetBalance(common.HexToAddress(params.BorUnittestChainConfig.Bor.CalculateBurntContract(block.NumberU64()))) expected = new(big.Int).Add(burntContractBalance, new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee())) burntContractBalance = expected if actual.Cmp(expected) != 0 { @@ -549,7 +886,7 @@ func TestEIP1559Transition(t *testing.T) { state, _ = chain.State() // check burnt contract balance - actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64()))) + actual = state.GetBalance(common.HexToAddress(params.BorUnittestChainConfig.Bor.CalculateBurntContract(block.NumberU64()))) burntAmount := new(big.Int).Mul( block.BaseFee(), big.NewInt(int64(block.GasUsed())), @@ -560,25 +897,188 @@ func TestEIP1559Transition(t *testing.T) { } } -func newGwei(n int64) *big.Int { - return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei)) +// EIP1559 is not supported without EIP155. An error is expected +func TestEIP1559TransitionWithEIP155(t *testing.T) { + var ( + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") + + // Generate a canonical chain to act as the main dataset + db = rawdb.NewMemoryDatabase() + engine = ethash.NewFaker() + + // A sender who makes transactions, has some funds + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + key3, _ = crypto.HexToECDSA("225171aed3793cba1c029832886d69785b7e77a54a44211226b447aa2d16b058") + + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + addr3 = crypto.PubkeyToAddress(key3.PublicKey) + funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + gspec = &core.Genesis{ + Config: params.BorUnittestChainConfig, + Alloc: core.GenesisAlloc{ + addr1: {Balance: funds}, + addr2: {Balance: funds}, + addr3: {Balance: funds}, + // The address 0xAAAA sloads 0x00 and 0x01 + aa: { + Code: []byte{ + byte(vm.PC), + byte(vm.PC), + byte(vm.SLOAD), + byte(vm.SLOAD), + }, + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + } + ) + + genesis := gspec.MustCommit(db) + + // Use signer without chain ID + signer := types.HomesteadSigner{} + + _, _ = core.GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *core.BlockGen) { + b.SetCoinbase(common.Address{1}) + // One transaction to 0xAAAA + accesses := types.AccessList{types.AccessTuple{ + Address: aa, + StorageKeys: []common.Hash{{0}}, + }} + + txdata := &types.DynamicFeeTx{ + ChainID: gspec.Config.ChainID, + Nonce: 0, + To: &aa, + Gas: 30000, + GasFeeCap: newGwei(5), + GasTipCap: big.NewInt(2), + AccessList: accesses, + Data: []byte{}, + } + + var err error + + tx := types.NewTx(txdata) + tx, err = types.SignTx(tx, signer, key1) + + require.ErrorIs(t, err, types.ErrTxTypeNotSupported) + }) +} + +// it is up to a user to use protected transactions. so if a transaction is unprotected no errors related to chainID are expected. +// transactions are checked in 2 places: transaction pool and blockchain processor. +func TestTransitionWithoutEIP155(t *testing.T) { + var ( + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") + + // Generate a canonical chain to act as the main dataset + db = rawdb.NewMemoryDatabase() + engine = ethash.NewFaker() + + // A sender who makes transactions, has some funds + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + key3, _ = crypto.HexToECDSA("225171aed3793cba1c029832886d69785b7e77a54a44211226b447aa2d16b058") + + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + addr3 = crypto.PubkeyToAddress(key3.PublicKey) + funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + gspec = &core.Genesis{ + Config: params.BorUnittestChainConfig, + Alloc: core.GenesisAlloc{ + addr1: {Balance: funds}, + addr2: {Balance: funds}, + addr3: {Balance: funds}, + // The address 0xAAAA sloads 0x00 and 0x01 + aa: { + Code: []byte{ + byte(vm.PC), + byte(vm.PC), + byte(vm.SLOAD), + byte(vm.SLOAD), + }, + Nonce: 0, + Balance: big.NewInt(0), + }, + }, + } + ) + + genesis := gspec.MustCommit(db) + + // Use signer without chain ID + signer := types.HomesteadSigner{} + //signer := types.FrontierSigner{} + + blocks, _ := core.GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *core.BlockGen) { + b.SetCoinbase(common.Address{1}) + + txdata := &types.LegacyTx{ + Nonce: 0, + To: &aa, + Gas: 30000, + GasPrice: newGwei(5), + } + + var err error + + tx := types.NewTx(txdata) + tx, err = types.SignTx(tx, signer, key1) + + require.Nil(t, err) + require.False(t, tx.Protected()) + + from, err := types.Sender(types.EIP155Signer{}, tx) + require.Equal(t, addr1, from) + require.Nil(t, err) + + b.AddTx(tx) + }) + + diskdb := rawdb.NewMemoryDatabase() + gspec.MustCommit(diskdb) + + chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + + block := chain.GetBlockByNumber(1) + + require.Len(t, block.Transactions(), 1) } func TestJaipurFork(t *testing.T) { init := buildEthereumInstance(t, rawdb.NewMemoryDatabase()) chain := init.ethereum.BlockChain() engine := init.ethereum.Engine() + _bor := engine.(*bor.Bor) + defer _bor.Close() + db := init.ethereum.ChainDb() block := init.genesis.ToBlock(db) + + res, _ := loadSpanFromFile(t) + for i := uint64(1); i < sprintSize; i++ { - block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor) + block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor, nil, res.Result.ValidatorSet.Validators) insertNewBlock(t, chain, block) - if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock-1 { - assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor)) + + if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock.Uint64()-1 { + require.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor)) } - if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock { - assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor)) + + if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock.Uint64() { + require.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor)) } } } @@ -609,7 +1109,7 @@ func testEncodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig) header.MixDigest, header.Nonce, } - if c.IsJaipur(header.Number.Uint64()) { + if c.IsJaipur(header.Number) { if header.BaseFee != nil { enc = append(enc, header.BaseFee) } diff --git a/tests/bor/helper.go b/tests/bor/helper.go index a8a3ae4ea6..64d5c299ac 100644 --- a/tests/bor/helper.go +++ b/tests/bor/helper.go @@ -1,46 +1,74 @@ +//go:build integration + package bor import ( + "context" + "crypto/ecdsa" "encoding/hex" "encoding/json" + "fmt" "io/ioutil" "math/big" "sort" "testing" + "time" + "github.com/golang/mock/gomock" + + "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/consensus" "github.com/ethereum/go-ethereum/consensus/bor" - "github.com/ethereum/go-ethereum/consensus/bor/heimdall" + "github.com/ethereum/go-ethereum/consensus/bor/clerk" + "github.com/ethereum/go-ethereum/consensus/bor/heimdall" //nolint:typecheck "github.com/ethereum/go-ethereum/consensus/bor/heimdall/span" "github.com/ethereum/go-ethereum/consensus/bor/valset" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/downloader" + "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/miner" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/tests/bor/mocks" ) var ( + + // Only this account is a validator for the 0th span + key, _ = crypto.HexToECDSA(privKey) + addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7 + + // This account is one the validators for 1st span (0-indexed) + key2, _ = crypto.HexToECDSA(privKey2) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791 + + keys = []*ecdsa.PrivateKey{key, key2} +) + +const ( + privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" + privKey2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3" + // The genesis for tests was generated with following parameters extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal - // Only this account is a validator for the 0th span - privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" - key, _ = crypto.HexToECDSA(privKey) - addr = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7 + sprintSize uint64 = 4 + spanSize uint64 = 8 - // This account is one the validators for 1st span (0-indexed) - privKey2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3" - key2, _ = crypto.HexToECDSA(privKey2) - addr2 = crypto.PubkeyToAddress(key2.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791 - - validatorHeaderBytesLength = common.AddressLength + 20 // address + power - sprintSize uint64 = 4 - spanSize uint64 = 8 + validatorHeaderBytesLength = common.AddressLength + 20 // address + power ) type initializeData struct { @@ -48,9 +76,40 @@ type initializeData struct { ethereum *eth.Ethereum } -func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { +func setupMiner(t *testing.T, n int, genesis *core.Genesis) ([]*node.Node, []*eth.Ethereum, []*enode.Node) { t.Helper() + // Create an Ethash network based off of the Ropsten config + var ( + stacks []*node.Node + nodes []*eth.Ethereum + enodes []*enode.Node + ) + + for i := 0; i < n; i++ { + // Start the node and wait until it's up + stack, ethBackend, err := InitMiner(genesis, keys[i], true) + if err != nil { + t.Fatal("Error occured while initialising miner", "error", err) + } + + for stack.Server().NodeInfo().Ports.Listener == 0 { + time.Sleep(250 * time.Millisecond) + } + // Connect the node to all the previous ones + for _, n := range enodes { + stack.Server().AddPeer(n) + } + // Start tracking the node and its enode + stacks = append(stacks, stack) + nodes = append(nodes, ethBackend) + enodes = append(enodes, stack.Server().Self()) + } + + return stacks, nodes, enodes +} + +func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { genesisData, err := ioutil.ReadFile("./testdata/genesis.json") if err != nil { t.Fatalf("%s", err) @@ -64,6 +123,7 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { ethConf := ð.Config{ Genesis: gen, + BorLogs: true, } ethConf.Genesis.MustCommit(db) @@ -75,6 +135,10 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData { ethConf.Genesis.MustCommit(ethereum.ChainDb()) + ethereum.Engine().(*bor.Bor).Authorize(addr, func(account accounts.Account, s string, data []byte) ([]byte, error) { + return crypto.Sign(crypto.Keccak256(data), key) + }) + return &initializeData{ genesis: gen, ethereum: ethereum, @@ -89,33 +153,31 @@ func insertNewBlock(t *testing.T, chain *core.BlockChain, block *types.Block) { } } -func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *types.Block, signer []byte, borConfig *params.BorConfig) *types.Block { +type Option func(header *types.Header) + +func buildNextBlock(t *testing.T, _bor consensus.Engine, chain *core.BlockChain, parentBlock *types.Block, signer []byte, borConfig *params.BorConfig, txs []*types.Transaction, currentValidators []*valset.Validator, opts ...Option) *types.Block { t.Helper() - header := block.Header() - header.Number.Add(header.Number, big.NewInt(1)) + header := &types.Header{ + Number: big.NewInt(int64(parentBlock.Number().Uint64() + 1)), + Difficulty: big.NewInt(int64(parentBlock.Difficulty().Uint64())), + GasLimit: parentBlock.GasLimit(), + ParentHash: parentBlock.Hash(), + } number := header.Number.Uint64() if signer == nil { signer = getSignerKey(header.Number.Uint64()) } - header.ParentHash = block.Hash() - header.Time += bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig) + header.Time = parentBlock.Time() + bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig) header.Extra = make([]byte, 32+65) // vanity + extraSeal - currentValidators := []*valset.Validator{valset.NewValidator(addr, 10)} + isSpanStart := IsSpanStart(number) + isSprintEnd := IsSprintEnd(number) - isSpanEnd := (number+1)%spanSize == 0 - isSpanStart := number%spanSize == 0 - isSprintEnd := (header.Number.Uint64()+1)%sprintSize == 0 - - if isSpanEnd { - _, heimdallSpan := loadSpanFromFile(t) - // this is to stash the validator bytes in the header - currentValidators = heimdallSpan.ValidatorSet.Validators - } else if isSpanStart { - header.Difficulty = new(big.Int).SetInt64(3) + if isSpanStart { + header.Difficulty = new(big.Int).SetInt64(int64(len(currentValidators))) } if isSprintEnd { @@ -132,27 +194,89 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block * } if chain.Config().IsLondon(header.Number) { - header.BaseFee = misc.CalcBaseFee(chain.Config(), block.Header()) + header.BaseFee = misc.CalcBaseFee(chain.Config(), parentBlock.Header()) - if !chain.Config().IsLondon(block.Number()) { - parentGasLimit := block.GasLimit() * params.ElasticityMultiplier + if !chain.Config().IsLondon(parentBlock.Number()) { + parentGasLimit := parentBlock.GasLimit() * params.ElasticityMultiplier header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit) } } + for _, opt := range opts { + opt(header) + } + state, err := chain.State() if err != nil { t.Fatalf("%s", err) } - _, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil) - if err != nil { - t.Fatalf("%s", err) + b := &blockGen{header: header} + for _, tx := range txs { + b.addTxWithChain(chain, state, tx, addr) } - sign(t, header, signer, borConfig) + ctx := context.Background() - return types.NewBlockWithHeader(header) + // Finalize and seal the block + block, _ := _bor.FinalizeAndAssemble(ctx, chain, b.header, state, b.txs, nil, b.receipts) + + // Write state changes to db + root, err := state.Commit(chain.Config().IsEIP158(b.header.Number)) + if err != nil { + panic(fmt.Sprintf("state write error: %v", err)) + } + + if err := state.Database().TrieDB().Commit(root, false, nil); err != nil { + panic(fmt.Sprintf("trie write error: %v", err)) + } + + res := make(chan *types.Block, 1) + + err = _bor.Seal(ctx, chain, block, res, nil) + if err != nil { + // an error case - sign manually + sign(t, header, signer, borConfig) + return types.NewBlockWithHeader(header) + } + + return <-res +} + +type blockGen struct { + txs []*types.Transaction + receipts []*types.Receipt + gasPool *core.GasPool + header *types.Header +} + +func (b *blockGen) addTxWithChain(bc *core.BlockChain, statedb *state.StateDB, tx *types.Transaction, coinbase common.Address) { + if b.gasPool == nil { + b.setCoinbase(coinbase) + } + + statedb.Prepare(tx.Hash(), len(b.txs)) + + receipt, err := core.ApplyTransaction(bc.Config(), bc, &b.header.Coinbase, b.gasPool, statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) + if err != nil { + panic(err) + } + + b.txs = append(b.txs, tx) + b.receipts = append(b.receipts, receipt) +} + +func (b *blockGen) setCoinbase(addr common.Address) { + if b.gasPool != nil { + if len(b.txs) > 0 { + panic("coinbase must be set before adding transactions") + } + + panic("coinbase can only be set once") + } + + b.header.Coinbase = addr + b.gasPool = new(core.GasPool).AddGas(b.header.GasLimit) } func sign(t *testing.T, header *types.Header, signer []byte, c *params.BorConfig) { @@ -204,13 +328,172 @@ func loadSpanFromFile(t *testing.T) (*heimdall.SpanResponse, *span.HeimdallSpan) func getSignerKey(number uint64) []byte { signerKey := privKey - isSpanStart := number%spanSize == 0 - if isSpanStart { + if IsSpanStart(number) { // validator set in the new span has changed signerKey = privKey2 } - _key, _ := hex.DecodeString(signerKey) + newKey, _ := hex.DecodeString(signerKey) - return _key + return newKey +} + +func getMockedHeimdallClient(t *testing.T, heimdallSpan *span.HeimdallSpan) (*mocks.MockIHeimdallClient, *gomock.Controller) { + t.Helper() + + ctrl := gomock.NewController(t) + h := mocks.NewMockIHeimdallClient(ctrl) + + h.EXPECT().Span(gomock.Any(), uint64(1)).Return(heimdallSpan, nil).AnyTimes() + + h.EXPECT().StateSyncEvents(gomock.Any(), gomock.Any(), gomock.Any()). + Return([]*clerk.EventRecordWithTime{getSampleEventRecord(t)}, nil).AnyTimes() + + return h, ctrl +} + +func generateFakeStateSyncEvents(sample *clerk.EventRecordWithTime, count int) []*clerk.EventRecordWithTime { + events := make([]*clerk.EventRecordWithTime, count) + event := *sample + event.ID = 1 + events[0] = &clerk.EventRecordWithTime{} + *events[0] = event + + for i := 1; i < count; i++ { + event.ID = uint64(i) + event.Time = event.Time.Add(1 * time.Second) + events[i] = &clerk.EventRecordWithTime{} + *events[i] = event + } + + return events +} + +func buildStateEvent(sample *clerk.EventRecordWithTime, id uint64, timeStamp int64) *clerk.EventRecordWithTime { + event := *sample + event.ID = id + event.Time = time.Unix(timeStamp, 0) + + return &event +} + +func getSampleEventRecord(t *testing.T) *clerk.EventRecordWithTime { + t.Helper() + + eventRecords := stateSyncEventsPayload(t) + eventRecords.Result[0].Time = time.Unix(1, 0) + + return eventRecords.Result[0] +} + +func newGwei(n int64) *big.Int { + return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei)) +} + +func IsSpanEnd(number uint64) bool { + return (number+1)%spanSize == 0 +} + +func IsSpanStart(number uint64) bool { + return number%spanSize == 0 +} + +func IsSprintStart(number uint64) bool { + return number%sprintSize == 0 +} + +func IsSprintEnd(number uint64) bool { + return (number+1)%sprintSize == 0 +} + +func InitGenesis(t *testing.T, faucets []*ecdsa.PrivateKey, fileLocation string, sprintSize uint64) *core.Genesis { + t.Helper() + + // sprint size = 8 in genesis + genesisData, err := ioutil.ReadFile(fileLocation) + if err != nil { + t.Fatalf("%s", err) + } + + genesis := &core.Genesis{} + + if err := json.Unmarshal(genesisData, genesis); err != nil { + t.Fatalf("%s", err) + } + + genesis.Config.ChainID = big.NewInt(15001) + genesis.Config.EIP150Hash = common.Hash{} + genesis.Config.Bor.Sprint["0"] = sprintSize + + return genesis +} + +func InitMiner(genesis *core.Genesis, privKey *ecdsa.PrivateKey, withoutHeimdall bool) (*node.Node, *eth.Ethereum, error) { + // Define the basic configurations for the Ethereum node + datadir, _ := ioutil.TempDir("", "") + + config := &node.Config{ + Name: "geth", + Version: params.Version, + DataDir: datadir, + P2P: p2p.Config{ + ListenAddr: "0.0.0.0:0", + NoDiscovery: true, + MaxPeers: 25, + }, + UseLightweightKDF: true, + } + // Create the node and configure a full Ethereum node on it + stack, err := node.New(config) + if err != nil { + return nil, nil, err + } + + ethBackend, err := eth.New(stack, ðconfig.Config{ + Genesis: genesis, + NetworkId: genesis.Config.ChainID.Uint64(), + SyncMode: downloader.FullSync, + DatabaseCache: 256, + DatabaseHandles: 256, + TxPool: core.DefaultTxPoolConfig, + GPO: ethconfig.Defaults.GPO, + Ethash: ethconfig.Defaults.Ethash, + Miner: miner.Config{ + Etherbase: crypto.PubkeyToAddress(privKey.PublicKey), + GasCeil: genesis.GasLimit * 11 / 10, + GasPrice: big.NewInt(1), + Recommit: time.Second, + }, + WithoutHeimdall: withoutHeimdall, + }) + + if err != nil { + return nil, nil, err + } + + // register backend to account manager with keystore for signing + keydir := stack.KeyStoreDir() + + n, p := keystore.StandardScryptN, keystore.StandardScryptP + kStore := keystore.NewKeyStore(keydir, n, p) + + _, err = kStore.ImportECDSA(privKey, "") + + if err != nil { + return nil, nil, err + } + + acc := kStore.Accounts()[0] + err = kStore.Unlock(acc, "") + + if err != nil { + return nil, nil, err + } + + // proceed to authorize the local account manager in any case + ethBackend.AccountManager().AddBackend(kStore) + + err = stack.Start() + + return stack, ethBackend, err } diff --git a/tests/bor/mocks/IHeimdallClient.go b/tests/bor/mocks/IHeimdallClient.go index f770ed9fa8..15a09712f1 100644 --- a/tests/bor/mocks/IHeimdallClient.go +++ b/tests/bor/mocks/IHeimdallClient.go @@ -5,6 +5,7 @@ package mocks import ( + context "context" reflect "reflect" clerk "github.com/ethereum/go-ethereum/consensus/bor/clerk" @@ -48,47 +49,62 @@ func (mr *MockIHeimdallClientMockRecorder) Close() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockIHeimdallClient)(nil).Close)) } -// FetchLatestCheckpoint mocks base method. -func (m *MockIHeimdallClient) FetchLatestCheckpoint() (*checkpoint.Checkpoint, error) { +// FetchCheckpoint mocks base method. +func (m *MockIHeimdallClient) FetchCheckpoint(arg0 context.Context, arg1 int64) (*checkpoint.Checkpoint, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FetchLatestCheckpoint") + ret := m.ctrl.Call(m, "FetchCheckpoint", arg0, arg1) ret0, _ := ret[0].(*checkpoint.Checkpoint) ret1, _ := ret[1].(error) return ret0, ret1 } -// FetchLatestCheckpoint indicates an expected call of FetchLatestCheckpoint. -func (mr *MockIHeimdallClientMockRecorder) FetchLatestCheckpoint() *gomock.Call { +// FetchCheckpoint indicates an expected call of FetchCheckpoint. +func (mr *MockIHeimdallClientMockRecorder) FetchCheckpoint(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchLatestCheckpoint", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchLatestCheckpoint)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchCheckpoint", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchCheckpoint), arg0, arg1) +} + +// FetchCheckpointCount mocks base method. +func (m *MockIHeimdallClient) FetchCheckpointCount(arg0 context.Context) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchCheckpointCount", arg0) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchCheckpointCount indicates an expected call of FetchCheckpointCount. +func (mr *MockIHeimdallClientMockRecorder) FetchCheckpointCount(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchCheckpointCount", reflect.TypeOf((*MockIHeimdallClient)(nil).FetchCheckpointCount), arg0) } // Span mocks base method. -func (m *MockIHeimdallClient) Span(arg0 uint64) (*span.HeimdallSpan, error) { +func (m *MockIHeimdallClient) Span(arg0 context.Context, arg1 uint64) (*span.HeimdallSpan, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Span", arg0) + ret := m.ctrl.Call(m, "Span", arg0, arg1) ret0, _ := ret[0].(*span.HeimdallSpan) ret1, _ := ret[1].(error) return ret0, ret1 } // Span indicates an expected call of Span. -func (mr *MockIHeimdallClientMockRecorder) Span(arg0 interface{}) *gomock.Call { +func (mr *MockIHeimdallClientMockRecorder) Span(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Span", reflect.TypeOf((*MockIHeimdallClient)(nil).Span), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Span", reflect.TypeOf((*MockIHeimdallClient)(nil).Span), arg0, arg1) } // StateSyncEvents mocks base method. -func (m *MockIHeimdallClient) StateSyncEvents(arg0 uint64, arg1 int64) ([]*clerk.EventRecordWithTime, error) { +func (m *MockIHeimdallClient) StateSyncEvents(arg0 context.Context, arg1 uint64, arg2 int64) ([]*clerk.EventRecordWithTime, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StateSyncEvents", arg0, arg1) + ret := m.ctrl.Call(m, "StateSyncEvents", arg0, arg1, arg2) ret0, _ := ret[0].([]*clerk.EventRecordWithTime) ret1, _ := ret[1].(error) return ret0, ret1 } // StateSyncEvents indicates an expected call of StateSyncEvents. -func (mr *MockIHeimdallClientMockRecorder) StateSyncEvents(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockIHeimdallClientMockRecorder) StateSyncEvents(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateSyncEvents", reflect.TypeOf((*MockIHeimdallClient)(nil).StateSyncEvents), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateSyncEvents", reflect.TypeOf((*MockIHeimdallClient)(nil).StateSyncEvents), arg0, arg1, arg2) } diff --git a/tests/bor/testdata/genesis.json b/tests/bor/testdata/genesis.json index b5767b3ed3..cbae055a0a 100644 --- a/tests/bor/testdata/genesis.json +++ b/tests/bor/testdata/genesis.json @@ -15,11 +15,17 @@ "londonBlock": 1, "bor": { "jaipurBlock": 2, + "delhiBlock" :3, "period": { "0": 1 }, - "producerDelay": 4, - "sprint": 4, + "producerDelay": { + "0": 6 + }, + "sprint": { + "0": 4, + "32": 2 + }, "backupMultiplier": { "0": 1 }, @@ -52,6 +58,9 @@ }, "71562b71999873DB5b286dF957af199Ec94617F7": { "balance": "0x3635c9adc5dea00000" + }, + "9fB29AAc15b9A4B7F17c3385939b007540f4d791": { + "balance": "0x3635c9adc5dea00000" } }, "number": "0x0", diff --git a/tests/bor/testdata/genesis_21val.json b/tests/bor/testdata/genesis_21val.json new file mode 100644 index 0000000000..e2c604b1dc --- /dev/null +++ b/tests/bor/testdata/genesis_21val.json @@ -0,0 +1,126 @@ +{ + "config": { + "chainId": 1272, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "bor": { + "jaipurBlock": 0, + "delhiBlock" :0, + "period": { + "0": 1 + }, + "producerDelay": { + "0": 6 + }, + "sprint": { + "0": 32, + "200": 8 + }, + "backupMultiplier": { + "0": 1 + }, + "validatorContract": "0x0000000000000000000000000000000000001000", + "stateReceiverContract": "0x0000000000000000000000000000000000001001", + "burntContract": { + "0": "0x000000000000000000000000000000000000dead" + } + } + }, + "nonce": "0x0", + "timestamp": "0x5ce28211", + "extraData": "", + "gasLimit": "0x989680", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000001000": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a91908101906132a4565b610706565b60405161021e93929190613be3565b60405180910390f35b610241600480360361023c91908101906132a4565b61075d565b60405161024f929190613a04565b60405180910390f35b610272600480360361026d91908101906132cd565b610939565b60405161027f9190613a3b565b60405180910390f35b6102a2600480360361029d91908101906133ac565b610a91565b005b6102be60048036036102b991908101906132cd565b61112a565b6040516102cb9190613a3b565b60405180910390f35b6102dc611281565b6040516102e99190613b91565b60405180910390f35b61030c60048036036103079190810190613201565b611286565b6040516103199190613a56565b60405180910390f35b61033c600480360361033791908101906132a4565b611307565b6040516103499190613b91565b60405180910390f35b61035a611437565b60405161036791906139e9565b60405180910390f35b61038a6004803603610385919081019061323d565b61144f565b6040516103979190613a3b565b60405180910390f35b6103a861151a565b6040516103b59190613a56565b60405180910390f35b6103d860048036036103d39190810190613309565b611531565b6040516103e59190613b91565b60405180910390f35b610408600480360361040391908101906132cd565b611619565b6040516104159190613b76565b60405180910390f35b610426611781565b6040516104339190613b91565b60405180910390f35b61045660048036036104519190810190613186565b611791565b6040516104639190613a3b565b60405180910390f35b610486600480360361048191908101906131af565b6117ab565b6040516104939190613a56565b60405180910390f35b6104a4611829565b6040516104b393929190613be3565b60405180910390f35b6104c461189d565b6040516104d2929190613a04565b60405180910390f35b6104e36122ee565b6040516104f09190613b91565b60405180910390f35b610513600480360361050e9190810190613370565b6122f3565b60405161052293929190613bac565b60405180910390f35b61054560048036036105409190810190613186565b612357565b6040516105529190613a3b565b60405180910390f35b610563612371565b6040516105709190613a56565b60405180910390f35b610593600480360361058e91908101906132a4565b612388565b6040516105a09190613b91565b60405180910390f35b6105b16124b9565b6040516105be9190613a56565b60405180910390f35b6105cf6124d0565b6040516105de93929190613be3565b60405180910390f35b61060160048036036105fc91908101906132a4565b612531565b60405161060e9190613b91565b60405180910390f35b61061f612631565b60405161062d929190613a04565b60405180910390f35b610650600480360361064b91908101906132a4565b612645565b60405161065d9190613b91565b60405180910390f35b61066e612666565b60405161067b9190613c1a565b60405180910390f35b61069e60048036036106999190810190613370565b61266b565b6040516106ad93929190613bac565b60405180910390f35b6106be6126cf565b6040516106cb9190613b91565b60405180910390f35b6106ee60048036036106e991908101906132a4565b6126e1565b6040516106fd93929190613be3565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107795761077061189d565b91509150610934565b600061078484612531565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a90613b56565b60405180910390fd5b6000610b1d611781565b90506000811415610b3157610b3061270b565b5b610b45600182612a2c90919063ffffffff16565b8814610b86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7d90613ad6565b60405180910390fd5b868611610bc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbf90613b36565b60405180910390fd5b6000604060018989030181610bd957fe5b0614610c1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1190613b16565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a90613ab6565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610ccc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc390613af6565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d669190612f80565b506000600160008a815260200190815260200160002081610d879190612f80565b506060610ddf610dda87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a4b565b612a79565b905060008090505b8151811015610f51576060610e0e838381518110610e0157fe5b6020026020010151612a79565b90506000808c81526020019081526020016000208054809190600101610e349190612f80565b506040518060600160405280610e5d83600081518110610e5057fe5b6020026020010151612b56565b8152602001610e7f83600181518110610e7257fe5b6020026020010151612b56565b8152602001610ea183600281518110610e9457fe5b6020026020010151612bc7565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ed757fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610de7565b506060610fa9610fa486868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612a4b565b612a79565b905060008090505b815181101561111d576060610fd8838381518110610fcb57fe5b6020026020010151612a79565b9050600160008d81526020019081526020016000208054809190600101610fff9190612f80565b5060405180606001604052806110288360008151811061101b57fe5b6020026020010151612b56565b815260200161104a8360018151811061103d57fe5b6020026020010151612b56565b815260200161106c8360028151811061105f57fe5b6020026020010151612bc7565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e815260200190815260200160002083815481106110a357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fb1565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111fc578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611160565b50505050905060008090505b8151811015611274578373ffffffffffffffffffffffffffffffffffffffff1682828151811061123457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112675760019250505061127b565b8080600101915050611208565b5060009150505b92915050565b604081565b60006002600160f81b84846040516020016112a393929190613956565b6040516020818303038152906040526040516112bf9190613993565b602060405180830381855afa1580156112dc573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112ff91908101906131d8565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113d9578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061133d565b505050509050600080905060008090505b825181101561142c5761141d83828151811061140257fe5b60200260200101516020015183612a2c90919063ffffffff16565b915080806001019150506113ea565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161146657fe5b04029050600081111561147f5761147c876117ab565b91505b6000602190505b818111611509576000600182038801519050818801519550806000602081106114ab57fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114f0576114e98685611286565b93506114fd565b6114fa8487611286565b93505b50602181019050611486565b508782149450505050509392505050565b604051611526906139d4565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff16101561160c57606061156e868367ffffffffffffffff166041612bea565b905060006115858289612c7690919063ffffffff16565b905061158f612fb2565b6115998a83611619565b90506115a58a8361112a565b80156115dc57508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115fe578194506115fb816020015187612a2c90919063ffffffff16565b95505b505050604181019050611543565b5081925050509392505050565b611621612fb2565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116f1578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611655565b50505050905060008090505b8151811015611779578373ffffffffffffffffffffffffffffffffffffffff1682828151811061172957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561176c5781818151811061175d57fe5b60200260200101519250611779565b80806001019150506116fd565b505092915050565b600061178c43612531565b905090565b60006117a461179e611781565b8361112a565b9050919050565b60006002600060f81b836040516020016117c692919061392a565b6040516020818303038152906040526040516117e29190613993565b602060405180830381855afa1580156117ff573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525061182291908101906131d8565b9050919050565b60008060008061184a600161183c611781565b612a2c90919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b606080606060156040519080825280602002602001820160405280156118d25781602001602082028038833980820191505090505b50905073387d24252f81ef0d2f33c344986644a5acc794a2816000815181106118f757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073a73335da992875cf74359d966bba2f4471ce1cb78160018151811061195357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507354fa823e70dcd10a735f4202602a895d5978c27c816002815181106119af57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073f630f2c51e17becf5190bc95b5211cddb684855981600381518110611a0b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050730b02c2957afa5bc02ce7adc2d973d4d0a5d67aa881600481518110611a6757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050731be1047566f230c21edae22446713e7087a9e81c81600581518110611ac357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073316679e22d8acf5955e2562a4abf54fec109d1ed81600681518110611b1f57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507351ecfbe68aa337c720e6f17041ca6044d095849381600781518110611b7b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507340e910d1bcbd0dacef856594e02b176be3ee736b81600881518110611bd757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050733594cbcdd629a59ce16b581f7bf6ea1e49f8f63481600981518110611c3357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050735f2cbdee214afef14608a724559c870df563646381600a81518110611c8f57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507339539b6e7defa23482beb77f3559a9413d86167681600b81518110611ceb57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073433929e706f85f7a5b7e95c21043b221b18351b981600c81518110611d4757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073d0aeeb8cb9a457f6b6d2279eb48057291e65b44281600d81518110611da357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073909721f84066ab0c8fbf6e1309818a461d1c288181600e81518110611dff57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073f96a0ec13f0e3fea25270925b0ffb0896857f36681600f81518110611e5b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073cd297859cac13fb4cca55fd2c591ebf035ebfbd981601081518110611eb757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073f6a1a2d64b3835ac821acc07275cd5f4fff00a1f81601181518110611f1357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073c6f92b3c655de61c9b0178600617e6f5e5a0fa7e81601281518110611f6f57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507363ccd7e06399e4360993fe5ad27dfd3dee54b1cd81601381518110611fcb57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507309fa9bc378b41029c2858f9cc2ef8a1707dc38c98160148151811061202757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050606060156040519080825280602002602001820160405280156120935781602001602082028038833980820191505090505b509050612710816000815181106120a657fe5b602002602001018181525050612710816001815181106120c257fe5b602002602001018181525050612710816002815181106120de57fe5b602002602001018181525050612710816003815181106120fa57fe5b6020026020010181815250506127108160048151811061211657fe5b6020026020010181815250506127108160058151811061213257fe5b6020026020010181815250506127108160068151811061214e57fe5b6020026020010181815250506127108160078151811061216a57fe5b6020026020010181815250506127108160088151811061218657fe5b602002602001018181525050612710816009815181106121a257fe5b60200260200101818152505061271081600a815181106121be57fe5b60200260200101818152505061271081600b815181106121da57fe5b60200260200101818152505061271081600c815181106121f657fe5b60200260200101818152505061271081600d8151811061221257fe5b60200260200101818152505061271081600e8151811061222e57fe5b60200260200101818152505061271081600f8151811061224a57fe5b6020026020010181815250506127108160108151811061226657fe5b6020026020010181815250506127108160118151811061228257fe5b6020026020010181815250506127108160128151811061229e57fe5b602002602001018181525050612710816013815181106122ba57fe5b602002602001018181525050612710816014815181106122d657fe5b60200260200101818152505081819350935050509091565b60ff81565b6001602052816000526040600020818154811061230c57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b600061236a612364611781565b83610939565b9050919050565b60405161237d906139aa565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561245b578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050815260200190600101906123bf565b505050509050600080905060008090505b82518110156124ae5761249f83828151811061248457fe5b60200260200101516020015183612a2c90919063ffffffff16565b9150808060010191505061246c565b508092505050919050565b6040516124c5906139bf565b604051809103902081565b6000806000806124de611781565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b60008111156125f15761254e612fe9565b600260006003600185038154811061256257fe5b9060005260206000200154815260200190815260200160002060405180606001604052908160008201548152602001600182015481526020016002820154815250509050838160200151111580156125bf57506000816040015114155b80156125cf575080604001518411155b156125e25780600001519250505061262c565b5080806001900391505061253d565b50600060038054905011156126275760036001600380549050038154811061261557fe5b9060005260206000200154905061262c565b600090505b919050565b60608061263d4361075d565b915091509091565b6003818154811061265257fe5b906000526020600020016000915090505481565b600281565b6000602052816000526040600020818154811061268457fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000604043816126db57fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b60608061271661189d565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff8152506002600083815260200190815260200160002060008201518160000155602082015181600101556040820151816002015590505060038190806001815401808255809150509060018203906000526020600020016000909192909190915055506000806000838152602001908152602001600020816127bf9190612f80565b50600060016000838152602001908152602001600020816127e09190612f80565b5060008090505b83518110156129025760008083815260200190815260200160002080548091906001016128149190612f80565b50604051806060016040528082815260200184838151811061283257fe5b6020026020010151815260200185838151811061284b57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16815250600080848152602001908152602001600020828154811061288957fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505080806001019150506127e7565b5060008090505b8351811015612a26576001600083815260200190815260200160002080548091906001016129379190612f80565b50604051806060016040528082815260200184838151811061295557fe5b6020026020010151815260200185838151811061296e57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168152506001600084815260200190815260200160002082815481106129ad57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612909565b50505050565b600080828401905083811015612a4157600080fd5b8091505092915050565b612a5361300a565b600060208301905060405180604001604052808451815260200182815250915050919050565b6060612a8482612d80565b612a8d57600080fd5b6000612a9883612dce565b9050606081604051908082528060200260200182016040528015612ad657816020015b612ac3613024565b815260200190600190039081612abb5790505b5090506000612ae88560200151612e3f565b8560200151019050600080600090505b84811015612b4957612b0983612ec8565b9150604051806040016040528083815260200184815250848281518110612b2c57fe5b602002602001018190525081830192508080600101915050612af8565b5082945050505050919050565b6000808260000151118015612b7057506021826000015111155b612b7957600080fd5b6000612b888360200151612e3f565b90506000818460000151039050600080838660200151019050805191506020831015612bbb57826020036101000a820491505b81945050505050919050565b60006015826000015114612bda57600080fd5b612be382612b56565b9050919050565b606081830184511015612bfc57600080fd5b6060821560008114612c1957604051915060208201604052612c6a565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015612c575780518352602083019250602081019050612c3a565b50868552601f19601f8301166040525050505b50809150509392505050565b6000806000806041855114612c915760009350505050612d7a565b602085015192506040850151915060ff6041860151169050601b8160ff161015612cbc57601b810190505b601b8160ff1614158015612cd45750601c8160ff1614155b15612ce55760009350505050612d7a565b600060018783868660405160008152602001604052604051612d0a9493929190613a71565b6020604051602081039080840390855afa158015612d2c573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612d7257600080fd5b809450505050505b92915050565b60008082600001511415612d975760009050612dc9565b60008083602001519050805160001a915060c060ff168260ff161015612dc257600092505050612dc9565b6001925050505b919050565b60008082600001511415612de55760009050612e3a565b60008090506000612df98460200151612e3f565b84602001510190506000846000015185602001510190505b80821015612e3357612e2282612ec8565b820191508280600101935050612e11565b8293505050505b919050565b600080825160001a9050608060ff16811015612e5f576000915050612ec3565b60b860ff16811080612e84575060c060ff168110158015612e83575060f860ff1681105b5b15612e93576001915050612ec3565b60c060ff16811015612eb35760018060b80360ff16820301915050612ec3565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff16811015612ee95760019150612f76565b60b860ff16811015612f06576001608060ff168203019150612f75565b60c060ff16811015612f365760b78103600185019450806020036101000a85510460018201810193505050612f74565b60f860ff16811015612f5357600160c060ff168203019150612f73565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b815481835581811115612fad57600302816003028360005260206000209182019101612fac919061303e565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b61309191905b8082111561308d5760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600301613044565b5090565b90565b6000813590506130a381613e13565b92915050565b6000813590506130b881613e2a565b92915050565b6000815190506130cd81613e2a565b92915050565b60008083601f8401126130e557600080fd5b8235905067ffffffffffffffff8111156130fe57600080fd5b60208301915083600182028301111561311657600080fd5b9250929050565b600082601f83011261312e57600080fd5b813561314161313c82613c62565b613c35565b9150808252602083016020830185838301111561315d57600080fd5b613168838284613dbd565b50505092915050565b60008135905061318081613e41565b92915050565b60006020828403121561319857600080fd5b60006131a684828501613094565b91505092915050565b6000602082840312156131c157600080fd5b60006131cf848285016130a9565b91505092915050565b6000602082840312156131ea57600080fd5b60006131f8848285016130be565b91505092915050565b6000806040838503121561321457600080fd5b6000613222858286016130a9565b9250506020613233858286016130a9565b9150509250929050565b60008060006060848603121561325257600080fd5b6000613260868287016130a9565b9350506020613271868287016130a9565b925050604084013567ffffffffffffffff81111561328e57600080fd5b61329a8682870161311d565b9150509250925092565b6000602082840312156132b657600080fd5b60006132c484828501613171565b91505092915050565b600080604083850312156132e057600080fd5b60006132ee85828601613171565b92505060206132ff85828601613094565b9150509250929050565b60008060006060848603121561331e57600080fd5b600061332c86828701613171565b935050602061333d868287016130a9565b925050604084013567ffffffffffffffff81111561335a57600080fd5b6133668682870161311d565b9150509250925092565b6000806040838503121561338357600080fd5b600061339185828601613171565b92505060206133a285828601613171565b9150509250929050565b600080600080600080600060a0888a0312156133c757600080fd5b60006133d58a828b01613171565b97505060206133e68a828b01613171565b96505060406133f78a828b01613171565b955050606088013567ffffffffffffffff81111561341457600080fd5b6134208a828b016130d3565b9450945050608088013567ffffffffffffffff81111561343f57600080fd5b61344b8a828b016130d3565b925092505092959891949750929550565b6000613468838361348c565b60208301905092915050565b600061348083836138fd565b60208301905092915050565b61349581613d32565b82525050565b6134a481613d32565b82525050565b60006134b582613cae565b6134bf8185613ce9565b93506134ca83613c8e565b8060005b838110156134fb5781516134e2888261345c565b97506134ed83613ccf565b9250506001810190506134ce565b5085935050505092915050565b600061351382613cb9565b61351d8185613cfa565b935061352883613c9e565b8060005b838110156135595781516135408882613474565b975061354b83613cdc565b92505060018101905061352c565b5085935050505092915050565b61356f81613d44565b82525050565b61358661358182613d50565b613dff565b82525050565b61359581613d7c565b82525050565b6135ac6135a782613d7c565b613e09565b82525050565b60006135bd82613cc4565b6135c78185613d0b565b93506135d7818560208601613dcc565b80840191505092915050565b60006135f0600483613d27565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000613630602d83613d16565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000613696600483613d27565b91507f31323732000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b60006136d6600f83613d16565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000613716601383613d16565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000613756600d83613d27565b91507f6865696d64616c6c2d31323732000000000000000000000000000000000000006000830152600d82019050919050565b6000613796604583613d16565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000613822602a83613d16565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000613888601283613d16565b91507f4e6f742053797374656d204164646573732100000000000000000000000000006000830152602082019050919050565b6060820160008201516138d160008501826138fd565b5060208201516138e460208501826138fd565b5060408201516138f7604085018261348c565b50505050565b61390681613da6565b82525050565b61391581613da6565b82525050565b61392481613db0565b82525050565b60006139368285613575565b600182019150613946828461359b565b6020820191508190509392505050565b60006139628286613575565b600182019150613972828561359b565b602082019150613982828461359b565b602082019150819050949350505050565b600061399f82846135b2565b915081905092915050565b60006139b5826135e3565b9150819050919050565b60006139ca82613689565b9150819050919050565b60006139df82613749565b9150819050919050565b60006020820190506139fe600083018461349b565b92915050565b60006040820190508181036000830152613a1e81856134aa565b90508181036020830152613a328184613508565b90509392505050565b6000602082019050613a506000830184613566565b92915050565b6000602082019050613a6b600083018461358c565b92915050565b6000608082019050613a86600083018761358c565b613a93602083018661391b565b613aa0604083018561358c565b613aad606083018461358c565b95945050505050565b60006020820190508181036000830152613acf81613623565b9050919050565b60006020820190508181036000830152613aef816136c9565b9050919050565b60006020820190508181036000830152613b0f81613709565b9050919050565b60006020820190508181036000830152613b2f81613789565b9050919050565b60006020820190508181036000830152613b4f81613815565b9050919050565b60006020820190508181036000830152613b6f8161387b565b9050919050565b6000606082019050613b8b60008301846138bb565b92915050565b6000602082019050613ba6600083018461390c565b92915050565b6000606082019050613bc1600083018661390c565b613bce602083018561390c565b613bdb604083018461349b565b949350505050565b6000606082019050613bf8600083018661390c565b613c05602083018561390c565b613c12604083018461390c565b949350505050565b6000602082019050613c2f600083018461391b565b92915050565b6000604051905081810181811067ffffffffffffffff82111715613c5857600080fd5b8060405250919050565b600067ffffffffffffffff821115613c7957600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b6000613d3d82613d86565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b83811015613dea578082015181840152602081019050613dcf565b83811115613df9576000848401525b50505050565b6000819050919050565b6000819050919050565b613e1c81613d32565b8114613e2757600080fd5b50565b613e3381613d7c565b8114613e3e57600080fd5b50565b613e4a81613da6565b8114613e5557600080fd5b5056fea365627a7a723158201ab873d059437add6ac607f5340e9049b54373ac0b1ee64f5a41ad55b0c3d91c6c6578706572696d656e74616cf564736f6c63430005110040" + }, + "0000000000000000000000000000000000001001": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a72315820af228b81e19dac46d14c24d264bde25d8a461d559c4e3cc82a5f1660755df35e64736f6c63430005110032" + }, + "0000000000000000000000000000000000001010": { + "balance": "0x204fc9ebd499c125cce00000", + "code": "0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a3565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116a9565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611736565b005b348015610b2e57600080fd5b50610b37611753565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa828488611779565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3690919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611f046023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5690919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611ee16023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b75565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600281526020017f04f800000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c7338484611779565b90505b92915050565b6040518060800160405280605b8152602001611f79605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6d565b611d43565b9050949350505050565b6104f881565b60015481565b604051806080016040528060528152602001611f27605291396040516020018082805190602001908083835b602083106116f857805182526020820191506020810190506020830392506116d5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173e6114dd565b61174757600080fd5b61175081611b75565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117f957600080fd5b505afa15801561180d573d6000803e3d6000fd5b505050506040513d602081101561182357600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b557600080fd5b505afa1580156118c9573d6000803e3d6000fd5b505050506040513d60208110156118df57600080fd5b810190808051906020019092919050505090506118fd868686611d8d565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0557600080fd5b505afa158015611a19573d6000803e3d6000fd5b505050506040513d6020811015611a2f57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abd57600080fd5b505afa158015611ad1573d6000803e3d6000fd5b505050506040513d6020811015611ae757600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4557600080fd5b600082840390508091505092915050565b600080828401905083811015611b6b57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611baf57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611f79605b91396040516020018082805190602001908083835b60208310611cbf5780518252602082019150602081019050602083039250611c9c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611e2f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f63616e27742073656e6420746f204d524332300000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611e75573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a72315820e13d27a65c119cc67c45ced4a1722dcd6bac3e344d1dbddcaf4e1127d91a5e7c64736f6c63430005110032" + }, + "387d24252f81Ef0d2F33c344986644a5acC794A2": { + "balance": "0x3635c9adc5dea00000" + }, + "A73335dA992875cF74359D966bBa2f4471CE1Cb7": { + "balance": "0x3635c9adc5dea00000" + }, + "54FA823e70Dcd10a735F4202602A895D5978c27C": { + "balance": "0x3635c9adc5dea00000" + }, + "f630f2C51e17bECf5190Bc95B5211CdDB6848559": { + "balance": "0x3635c9adc5dea00000" + }, + "0b02C2957AfA5Bc02CE7ADC2d973D4d0A5d67Aa8": { + "balance": "0x3635c9adc5dea00000" + }, + "1BE1047566F230C21Edae22446713e7087a9e81C": { + "balance": "0x3635c9adc5dea00000" + }, + "316679E22D8acf5955e2562a4ABf54feC109D1ed": { + "balance": "0x3635c9adc5dea00000" + }, + "51ecFbE68aa337c720E6f17041CA6044d0958493": { + "balance": "0x3635c9adc5dea00000" + }, + "40E910D1bcBD0DACEF856594E02b176Be3EE736b": { + "balance": "0x3635c9adc5dea00000" + }, + "3594Cbcdd629A59ce16B581F7Bf6eA1E49F8F634": { + "balance": "0x3635c9adc5dea00000" + }, + "5F2CbdEE214AFeF14608A724559C870Df5636463": { + "balance": "0x3635c9adc5dea00000" + }, + "39539B6E7dEfa23482bEB77f3559a9413d861676": { + "balance": "0x3635c9adc5dea00000" + }, + "433929e706F85F7a5b7e95c21043b221B18351b9": { + "balance": "0x3635c9adc5dea00000" + }, + "d0aeeB8CB9a457F6b6d2279eb48057291E65b442": { + "balance": "0x3635c9adc5dea00000" + }, + "909721f84066AB0C8FBf6E1309818A461D1C2881": { + "balance": "0x3635c9adc5dea00000" + }, + "f96A0EC13f0E3FEa25270925b0Ffb0896857F366": { + "balance": "0x3635c9adc5dea00000" + }, + "Cd297859cAC13Fb4CCa55Fd2C591EBF035EBfbD9": { + "balance": "0x3635c9adc5dea00000" + }, + "f6A1A2D64B3835AC821aCC07275cd5F4FfF00a1F": { + "balance": "0x3635c9adc5dea00000" + }, + "c6F92b3C655DE61c9B0178600617e6F5E5a0fa7E": { + "balance": "0x3635c9adc5dea00000" + }, + "63ccD7e06399e4360993Fe5aD27dFd3DeE54b1cD": { + "balance": "0x3635c9adc5dea00000" + }, + "09fa9bc378B41029C2858f9Cc2Ef8a1707DC38c9": { + "balance": "0x3635c9adc5dea00000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" +} diff --git a/tests/bor/testdata/genesis_2val.json b/tests/bor/testdata/genesis_2val.json new file mode 100644 index 0000000000..5ce5fbcd4e --- /dev/null +++ b/tests/bor/testdata/genesis_2val.json @@ -0,0 +1,68 @@ +{ + "config": { + "chainId": 15001, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 1, + "bor": { + "jaipurBlock": 2, + "delhiBlock" :3, + "period": { + "0": 1 + }, + "producerDelay": { + "0": 4 + }, + "sprint": { + "0": 8 + }, + "backupMultiplier": { + "0": 1 + }, + "validatorContract": "0x0000000000000000000000000000000000001000", + "stateReceiverContract": "0x0000000000000000000000000000000000001001", + "burntContract": { + "0": "0x000000000000000000000000000000000000dead" + } + } + }, + "nonce": "0x0", + "timestamp": "0x5ce28211", + "extraData": "", + "gasLimit": "0x989680", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000001000": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a91908101906129ba565b610706565b60405161021e939291906132f9565b60405180910390f35b610241600480360361023c91908101906129ba565b61075d565b60405161024f92919061311a565b60405180910390f35b610272600480360361026d91908101906129e3565b610939565b60405161027f9190613151565b60405180910390f35b6102a2600480360361029d9190810190612ac2565b610a91565b005b6102be60048036036102b991908101906129e3565b61112a565b6040516102cb9190613151565b60405180910390f35b6102dc611281565b6040516102e991906132a7565b60405180910390f35b61030c60048036036103079190810190612917565b611286565b604051610319919061316c565b60405180910390f35b61033c600480360361033791908101906129ba565b611307565b60405161034991906132a7565b60405180910390f35b61035a611437565b60405161036791906130ff565b60405180910390f35b61038a60048036036103859190810190612953565b61144f565b6040516103979190613151565b60405180910390f35b6103a861151a565b6040516103b5919061316c565b60405180910390f35b6103d860048036036103d39190810190612a1f565b611531565b6040516103e591906132a7565b60405180910390f35b610408600480360361040391908101906129e3565b611619565b604051610415919061328c565b60405180910390f35b610426611781565b60405161043391906132a7565b60405180910390f35b6104566004803603610451919081019061289c565b611791565b6040516104639190613151565b60405180910390f35b610486600480360361048191908101906128c5565b6117ab565b604051610493919061316c565b60405180910390f35b6104a4611829565b6040516104b3939291906132f9565b60405180910390f35b6104c461189d565b6040516104d292919061311a565b60405180910390f35b6104e3611a04565b6040516104f091906132a7565b60405180910390f35b610513600480360361050e9190810190612a86565b611a09565b604051610522939291906132c2565b60405180910390f35b6105456004803603610540919081019061289c565b611a6d565b6040516105529190613151565b60405180910390f35b610563611a87565b604051610570919061316c565b60405180910390f35b610593600480360361058e91908101906129ba565b611a9e565b6040516105a091906132a7565b60405180910390f35b6105b1611bcf565b6040516105be919061316c565b60405180910390f35b6105cf611be6565b6040516105de939291906132f9565b60405180910390f35b61060160048036036105fc91908101906129ba565b611c47565b60405161060e91906132a7565b60405180910390f35b61061f611d47565b60405161062d92919061311a565b60405180910390f35b610650600480360361064b91908101906129ba565b611d5b565b60405161065d91906132a7565b60405180910390f35b61066e611d7c565b60405161067b9190613330565b60405180910390f35b61069e60048036036106999190810190612a86565b611d81565b6040516106ad939291906132c2565b60405180910390f35b6106be611de5565b6040516106cb91906132a7565b60405180910390f35b6106ee60048036036106e991908101906129ba565b611df7565b6040516106fd939291906132f9565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107795761077061189d565b91509150610934565b600061078484611c47565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a9061326c565b60405180910390fd5b6000610b1d611781565b90506000811415610b3157610b30611e21565b5b610b4560018261214290919063ffffffff16565b8814610b86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7d906131ec565b60405180910390fd5b868611610bc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbf9061324c565b60405180910390fd5b6000604060018989030181610bd957fe5b0614610c1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c119061322c565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a906131cc565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610ccc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc39061320c565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d669190612696565b506000600160008a815260200190815260200160002081610d879190612696565b506060610ddf610dda87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612161565b61218f565b905060008090505b8151811015610f51576060610e0e838381518110610e0157fe5b602002602001015161218f565b90506000808c81526020019081526020016000208054809190600101610e349190612696565b506040518060600160405280610e5d83600081518110610e5057fe5b602002602001015161226c565b8152602001610e7f83600181518110610e7257fe5b602002602001015161226c565b8152602001610ea183600281518110610e9457fe5b60200260200101516122dd565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ed757fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610de7565b506060610fa9610fa486868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612161565b61218f565b905060008090505b815181101561111d576060610fd8838381518110610fcb57fe5b602002602001015161218f565b9050600160008d81526020019081526020016000208054809190600101610fff9190612696565b5060405180606001604052806110288360008151811061101b57fe5b602002602001015161226c565b815260200161104a8360018151811061103d57fe5b602002602001015161226c565b815260200161106c8360028151811061105f57fe5b60200260200101516122dd565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e815260200190815260200160002083815481106110a357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fb1565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111fc578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611160565b50505050905060008090505b8151811015611274578373ffffffffffffffffffffffffffffffffffffffff1682828151811061123457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112675760019250505061127b565b8080600101915050611208565b5060009150505b92915050565b604081565b60006002600160f81b84846040516020016112a39392919061306c565b6040516020818303038152906040526040516112bf91906130a9565b602060405180830381855afa1580156112dc573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112ff91908101906128ee565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113d9578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061133d565b505050509050600080905060008090505b825181101561142c5761141d83828151811061140257fe5b6020026020010151602001518361214290919063ffffffff16565b915080806001019150506113ea565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161146657fe5b04029050600081111561147f5761147c876117ab565b91505b6000602190505b818111611509576000600182038801519050818801519550806000602081106114ab57fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114f0576114e98685611286565b93506114fd565b6114fa8487611286565b93505b50602181019050611486565b508782149450505050509392505050565b604051611526906130d5565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff16101561160c57606061156e868367ffffffffffffffff166041612300565b90506000611585828961238c90919063ffffffff16565b905061158f6126c8565b6115998a83611619565b90506115a58a8361112a565b80156115dc57508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115fe578194506115fb81602001518761214290919063ffffffff16565b95505b505050604181019050611543565b5081925050509392505050565b6116216126c8565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116f1578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611655565b50505050905060008090505b8151811015611779578373ffffffffffffffffffffffffffffffffffffffff1682828151811061172957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561176c5781818151811061175d57fe5b60200260200101519250611779565b80806001019150506116fd565b505092915050565b600061178c43611c47565b905090565b60006117a461179e611781565b8361112a565b9050919050565b60006002600060f81b836040516020016117c6929190613040565b6040516020818303038152906040526040516117e291906130a9565b602060405180830381855afa1580156117ff573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525061182291908101906128ee565b9050919050565b60008060008061184a600161183c611781565b61214290919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b606080606060026040519080825280602002602001820160405280156118d25781602001602082028038833980820191505090505b5090507371562b71999873db5b286df957af199ec94617f7816000815181106118f757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050739fb29aac15b9a4b7f17c3385939b007540f4d7918160018151811061195357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050606060026040519080825280602002602001820160405280156119bf5781602001602082028038833980820191505090505b5090506028816000815181106119d157fe5b602002602001018181525050601e816001815181106119ec57fe5b60200260200101818152505081819350935050509091565b60ff81565b60016020528160005260406000208181548110611a2257fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000611a80611a7a611781565b83610939565b9050919050565b604051611a93906130c0565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611b71578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611ad5565b505050509050600080905060008090505b8251811015611bc457611bb5838281518110611b9a57fe5b6020026020010151602001518361214290919063ffffffff16565b91508080600101915050611b82565b508092505050919050565b604051611bdb906130ea565b604051809103902081565b600080600080611bf4611781565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b6000811115611d0757611c646126ff565b6002600060036001850381548110611c7857fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611cd557506000816040015114155b8015611ce5575080604001518411155b15611cf857806000015192505050611d42565b50808060019003915050611c53565b5060006003805490501115611d3d57600360016003805490500381548110611d2b57fe5b90600052602060002001549050611d42565b600090505b919050565b606080611d534361075d565b915091509091565b60038181548110611d6857fe5b906000526020600020016000915090505481565b600281565b60006020528160005260406000208181548110611d9a57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b600060404381611df157fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b606080611e2c61189d565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff815250600260008381526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506003819080600181540180825580915050906001820390600052602060002001600090919290919091505550600080600083815260200190815260200160002081611ed59190612696565b5060006001600083815260200190815260200160002081611ef69190612696565b5060008090505b8351811015612018576000808381526020019081526020016000208054809190600101611f2a9190612696565b506040518060600160405280828152602001848381518110611f4857fe5b60200260200101518152602001858381518110611f6157fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168152506000808481526020019081526020016000208281548110611f9f57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050611efd565b5060008090505b835181101561213c5760016000838152602001908152602001600020805480919060010161204d9190612696565b50604051806060016040528082815260200184838151811061206b57fe5b6020026020010151815260200185838151811061208457fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168152506001600084815260200190815260200160002082815481106120c357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050808060010191505061201f565b50505050565b60008082840190508381101561215757600080fd5b8091505092915050565b612169612720565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061219a82612496565b6121a357600080fd5b60006121ae836124e4565b90506060816040519080825280602002602001820160405280156121ec57816020015b6121d961273a565b8152602001906001900390816121d15790505b50905060006121fe8560200151612555565b8560200151019050600080600090505b8481101561225f5761221f836125de565b915060405180604001604052808381526020018481525084828151811061224257fe5b60200260200101819052508183019250808060010191505061220e565b5082945050505050919050565b600080826000015111801561228657506021826000015111155b61228f57600080fd5b600061229e8360200151612555565b905060008184600001510390506000808386602001510190508051915060208310156122d157826020036101000a820491505b81945050505050919050565b600060158260000151146122f057600080fd5b6122f98261226c565b9050919050565b60608183018451101561231257600080fd5b606082156000811461232f57604051915060208201604052612380565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561236d5780518352602083019250602081019050612350565b50868552601f19601f8301166040525050505b50809150509392505050565b60008060008060418551146123a75760009350505050612490565b602085015192506040850151915060ff6041860151169050601b8160ff1610156123d257601b810190505b601b8160ff16141580156123ea5750601c8160ff1614155b156123fb5760009350505050612490565b6000600187838686604051600081526020016040526040516124209493929190613187565b6020604051602081039080840390855afa158015612442573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561248857600080fd5b809450505050505b92915050565b600080826000015114156124ad57600090506124df565b60008083602001519050805160001a915060c060ff168260ff1610156124d8576000925050506124df565b6001925050505b919050565b600080826000015114156124fb5760009050612550565b6000809050600061250f8460200151612555565b84602001510190506000846000015185602001510190505b8082101561254957612538826125de565b820191508280600101935050612527565b8293505050505b919050565b600080825160001a9050608060ff168110156125755760009150506125d9565b60b860ff1681108061259a575060c060ff168110158015612599575060f860ff1681105b5b156125a95760019150506125d9565b60c060ff168110156125c95760018060b80360ff168203019150506125d9565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff168110156125ff576001915061268c565b60b860ff1681101561261c576001608060ff16820301915061268b565b60c060ff1681101561264c5760b78103600185019450806020036101000a8551046001820181019350505061268a565b60f860ff1681101561266957600160c060ff168203019150612689565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b8154818355818111156126c3576003028160030283600052602060002091820191016126c29190612754565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b6127a791905b808211156127a35760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555060030161275a565b5090565b90565b6000813590506127b981613529565b92915050565b6000813590506127ce81613540565b92915050565b6000815190506127e381613540565b92915050565b60008083601f8401126127fb57600080fd5b8235905067ffffffffffffffff81111561281457600080fd5b60208301915083600182028301111561282c57600080fd5b9250929050565b600082601f83011261284457600080fd5b813561285761285282613378565b61334b565b9150808252602083016020830185838301111561287357600080fd5b61287e8382846134d3565b50505092915050565b60008135905061289681613557565b92915050565b6000602082840312156128ae57600080fd5b60006128bc848285016127aa565b91505092915050565b6000602082840312156128d757600080fd5b60006128e5848285016127bf565b91505092915050565b60006020828403121561290057600080fd5b600061290e848285016127d4565b91505092915050565b6000806040838503121561292a57600080fd5b6000612938858286016127bf565b9250506020612949858286016127bf565b9150509250929050565b60008060006060848603121561296857600080fd5b6000612976868287016127bf565b9350506020612987868287016127bf565b925050604084013567ffffffffffffffff8111156129a457600080fd5b6129b086828701612833565b9150509250925092565b6000602082840312156129cc57600080fd5b60006129da84828501612887565b91505092915050565b600080604083850312156129f657600080fd5b6000612a0485828601612887565b9250506020612a15858286016127aa565b9150509250929050565b600080600060608486031215612a3457600080fd5b6000612a4286828701612887565b9350506020612a53868287016127bf565b925050604084013567ffffffffffffffff811115612a7057600080fd5b612a7c86828701612833565b9150509250925092565b60008060408385031215612a9957600080fd5b6000612aa785828601612887565b9250506020612ab885828601612887565b9150509250929050565b600080600080600080600060a0888a031215612add57600080fd5b6000612aeb8a828b01612887565b9750506020612afc8a828b01612887565b9650506040612b0d8a828b01612887565b955050606088013567ffffffffffffffff811115612b2a57600080fd5b612b368a828b016127e9565b9450945050608088013567ffffffffffffffff811115612b5557600080fd5b612b618a828b016127e9565b925092505092959891949750929550565b6000612b7e8383612ba2565b60208301905092915050565b6000612b968383613013565b60208301905092915050565b612bab81613448565b82525050565b612bba81613448565b82525050565b6000612bcb826133c4565b612bd581856133ff565b9350612be0836133a4565b8060005b83811015612c11578151612bf88882612b72565b9750612c03836133e5565b925050600181019050612be4565b5085935050505092915050565b6000612c29826133cf565b612c338185613410565b9350612c3e836133b4565b8060005b83811015612c6f578151612c568882612b8a565b9750612c61836133f2565b925050600181019050612c42565b5085935050505092915050565b612c858161345a565b82525050565b612c9c612c9782613466565b613515565b82525050565b612cab81613492565b82525050565b612cc2612cbd82613492565b61351f565b82525050565b6000612cd3826133da565b612cdd8185613421565b9350612ced8185602086016134e2565b80840191505092915050565b6000612d0660048361343d565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000612d46602d8361342c565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000612dac600f8361343d565b91507f6865696d64616c6c2d50357258776700000000000000000000000000000000006000830152600f82019050919050565b6000612dec600f8361342c565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000612e2c60138361342c565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000612e6c60458361342c565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000612ef8602a8361342c565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000612f5e60058361343d565b91507f31353030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b6000612f9e60128361342c565b91507f4e6f742053797374656d204164646573732100000000000000000000000000006000830152602082019050919050565b606082016000820151612fe76000850182613013565b506020820151612ffa6020850182613013565b50604082015161300d6040850182612ba2565b50505050565b61301c816134bc565b82525050565b61302b816134bc565b82525050565b61303a816134c6565b82525050565b600061304c8285612c8b565b60018201915061305c8284612cb1565b6020820191508190509392505050565b60006130788286612c8b565b6001820191506130888285612cb1565b6020820191506130988284612cb1565b602082019150819050949350505050565b60006130b58284612cc8565b915081905092915050565b60006130cb82612cf9565b9150819050919050565b60006130e082612d9f565b9150819050919050565b60006130f582612f51565b9150819050919050565b60006020820190506131146000830184612bb1565b92915050565b600060408201905081810360008301526131348185612bc0565b905081810360208301526131488184612c1e565b90509392505050565b60006020820190506131666000830184612c7c565b92915050565b60006020820190506131816000830184612ca2565b92915050565b600060808201905061319c6000830187612ca2565b6131a96020830186613031565b6131b66040830185612ca2565b6131c36060830184612ca2565b95945050505050565b600060208201905081810360008301526131e581612d39565b9050919050565b6000602082019050818103600083015261320581612ddf565b9050919050565b6000602082019050818103600083015261322581612e1f565b9050919050565b6000602082019050818103600083015261324581612e5f565b9050919050565b6000602082019050818103600083015261326581612eeb565b9050919050565b6000602082019050818103600083015261328581612f91565b9050919050565b60006060820190506132a16000830184612fd1565b92915050565b60006020820190506132bc6000830184613022565b92915050565b60006060820190506132d76000830186613022565b6132e46020830185613022565b6132f16040830184612bb1565b949350505050565b600060608201905061330e6000830186613022565b61331b6020830185613022565b6133286040830184613022565b949350505050565b60006020820190506133456000830184613031565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561336e57600080fd5b8060405250919050565b600067ffffffffffffffff82111561338f57600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006134538261349c565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b838110156135005780820151818401526020810190506134e5565b8381111561350f576000848401525b50505050565b6000819050919050565b6000819050919050565b61353281613448565b811461353d57600080fd5b50565b61354981613492565b811461355457600080fd5b50565b613560816134bc565b811461356b57600080fd5b5056fea365627a7a7231582051bf0a46b5958c4ecdf9f1f9a9d8b62deacac5d79cdf5595e9853f3c0132fe236c6578706572696d656e74616cf564736f6c63430005110040" + }, + "0000000000000000000000000000000000001001": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a72315820af228b81e19dac46d14c24d264bde25d8a461d559c4e3cc82a5f1660755df35e64736f6c63430005110032" + }, + "0000000000000000000000000000000000001010": { + "balance": "0x204fcdf1d291a6d552c00000", + "code": "0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a3565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116a9565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611736565b005b348015610b2e57600080fd5b50610b37611753565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa828488611779565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3690919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611f046023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5690919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611ee16023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b75565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600281526020017f3a9900000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c7338484611779565b90505b92915050565b6040518060800160405280605b8152602001611f79605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6d565b611d43565b9050949350505050565b613a9981565b60015481565b604051806080016040528060528152602001611f27605291396040516020018082805190602001908083835b602083106116f857805182526020820191506020810190506020830392506116d5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173e6114dd565b61174757600080fd5b61175081611b75565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117f957600080fd5b505afa15801561180d573d6000803e3d6000fd5b505050506040513d602081101561182357600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b557600080fd5b505afa1580156118c9573d6000803e3d6000fd5b505050506040513d60208110156118df57600080fd5b810190808051906020019092919050505090506118fd868686611d8d565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0557600080fd5b505afa158015611a19573d6000803e3d6000fd5b505050506040513d6020811015611a2f57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abd57600080fd5b505afa158015611ad1573d6000803e3d6000fd5b505050506040513d6020811015611ae757600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4557600080fd5b600082840390508091505092915050565b600080828401905083811015611b6b57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611baf57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611f79605b91396040516020018082805190602001908083835b60208310611cbf5780518252602082019150602081019050602083039250611c9c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611e2f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f63616e27742073656e6420746f204d524332300000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611e75573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a723158205723157ad1c8ebb37fecace5dc0ce2dfa893ec59d46a1305ad694cd0170076ab64736f6c63430005110032" + }, + "71562b71999873DB5b286dF957af199Ec94617F7": { + "balance": "0x3635c9adc5dea00000" + }, + "9fB29AAc15b9A4B7F17c3385939b007540f4d791": { + "balance": "0x3635c9adc5dea00000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } diff --git a/tests/bor/testdata/genesis_7val.json b/tests/bor/testdata/genesis_7val.json new file mode 100644 index 0000000000..97982a3deb --- /dev/null +++ b/tests/bor/testdata/genesis_7val.json @@ -0,0 +1,83 @@ +{ + "config": { + "chainId": 4884, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "bor": { + "jaipurBlock": 0, + "delhiBlock" :0, + "period": { + "0": 1 + }, + "producerDelay": { + "0": 6 + }, + "sprint": { + "0": 32 + }, + "backupMultiplier": { + "0": 1 + }, + "validatorContract": "0x0000000000000000000000000000000000001000", + "stateReceiverContract": "0x0000000000000000000000000000000000001001", + "burntContract": { + "0": "0x000000000000000000000000000000000000dead" + } + } + }, + "nonce": "0x0", + "timestamp": "0x5ce28211", + "extraData": "", + "gasLimit": "0x989680", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000001000": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a9190810190612c14565b610706565b60405161021e93929190613553565b60405180910390f35b610241600480360361023c9190810190612c14565b61075d565b60405161024f929190613374565b60405180910390f35b610272600480360361026d9190810190612c3d565b610939565b60405161027f91906133ab565b60405180910390f35b6102a2600480360361029d9190810190612d1c565b610a91565b005b6102be60048036036102b99190810190612c3d565b61112a565b6040516102cb91906133ab565b60405180910390f35b6102dc611281565b6040516102e99190613501565b60405180910390f35b61030c60048036036103079190810190612b71565b611286565b60405161031991906133c6565b60405180910390f35b61033c60048036036103379190810190612c14565b611307565b6040516103499190613501565b60405180910390f35b61035a611437565b6040516103679190613359565b60405180910390f35b61038a60048036036103859190810190612bad565b61144f565b60405161039791906133ab565b60405180910390f35b6103a861151a565b6040516103b591906133c6565b60405180910390f35b6103d860048036036103d39190810190612c79565b611531565b6040516103e59190613501565b60405180910390f35b61040860048036036104039190810190612c3d565b611619565b60405161041591906134e6565b60405180910390f35b610426611781565b6040516104339190613501565b60405180910390f35b61045660048036036104519190810190612af6565b611791565b60405161046391906133ab565b60405180910390f35b61048660048036036104819190810190612b1f565b6117ab565b60405161049391906133c6565b60405180910390f35b6104a4611829565b6040516104b393929190613553565b60405180910390f35b6104c461189d565b6040516104d2929190613374565b60405180910390f35b6104e3611c5e565b6040516104f09190613501565b60405180910390f35b610513600480360361050e9190810190612ce0565b611c63565b6040516105229392919061351c565b60405180910390f35b61054560048036036105409190810190612af6565b611cc7565b60405161055291906133ab565b60405180910390f35b610563611ce1565b60405161057091906133c6565b60405180910390f35b610593600480360361058e9190810190612c14565b611cf8565b6040516105a09190613501565b60405180910390f35b6105b1611e29565b6040516105be91906133c6565b60405180910390f35b6105cf611e40565b6040516105de93929190613553565b60405180910390f35b61060160048036036105fc9190810190612c14565b611ea1565b60405161060e9190613501565b60405180910390f35b61061f611fa1565b60405161062d929190613374565b60405180910390f35b610650600480360361064b9190810190612c14565b611fb5565b60405161065d9190613501565b60405180910390f35b61066e611fd6565b60405161067b919061358a565b60405180910390f35b61069e60048036036106999190810190612ce0565b611fdb565b6040516106ad9392919061351c565b60405180910390f35b6106be61203f565b6040516106cb9190613501565b60405180910390f35b6106ee60048036036106e99190810190612c14565b612051565b6040516106fd93929190613553565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107795761077061189d565b91509150610934565b600061078484611ea1565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a906134c6565b60405180910390fd5b6000610b1d611781565b90506000811415610b3157610b3061207b565b5b610b4560018261239c90919063ffffffff16565b8814610b86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7d90613446565b60405180910390fd5b868611610bc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbf906134a6565b60405180910390fd5b6000604060018989030181610bd957fe5b0614610c1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1190613486565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a90613426565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610ccc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc390613466565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d6691906128f0565b506000600160008a815260200190815260200160002081610d8791906128f0565b506060610ddf610dda87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506123bb565b6123e9565b905060008090505b8151811015610f51576060610e0e838381518110610e0157fe5b60200260200101516123e9565b90506000808c81526020019081526020016000208054809190600101610e3491906128f0565b506040518060600160405280610e5d83600081518110610e5057fe5b60200260200101516124c6565b8152602001610e7f83600181518110610e7257fe5b60200260200101516124c6565b8152602001610ea183600281518110610e9457fe5b6020026020010151612537565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ed757fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610de7565b506060610fa9610fa486868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506123bb565b6123e9565b905060008090505b815181101561111d576060610fd8838381518110610fcb57fe5b60200260200101516123e9565b9050600160008d81526020019081526020016000208054809190600101610fff91906128f0565b5060405180606001604052806110288360008151811061101b57fe5b60200260200101516124c6565b815260200161104a8360018151811061103d57fe5b60200260200101516124c6565b815260200161106c8360028151811061105f57fe5b6020026020010151612537565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e815260200190815260200160002083815481106110a357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fb1565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111fc578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611160565b50505050905060008090505b8151811015611274578373ffffffffffffffffffffffffffffffffffffffff1682828151811061123457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112675760019250505061127b565b8080600101915050611208565b5060009150505b92915050565b604081565b60006002600160f81b84846040516020016112a3939291906132c6565b6040516020818303038152906040526040516112bf9190613303565b602060405180830381855afa1580156112dc573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112ff9190810190612b48565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113d9578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061133d565b505050509050600080905060008090505b825181101561142c5761141d83828151811061140257fe5b6020026020010151602001518361239c90919063ffffffff16565b915080806001019150506113ea565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161146657fe5b04029050600081111561147f5761147c876117ab565b91505b6000602190505b818111611509576000600182038801519050818801519550806000602081106114ab57fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114f0576114e98685611286565b93506114fd565b6114fa8487611286565b93505b50602181019050611486565b508782149450505050509392505050565b60405161152690613344565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff16101561160c57606061156e868367ffffffffffffffff16604161255a565b9050600061158582896125e690919063ffffffff16565b905061158f612922565b6115998a83611619565b90506115a58a8361112a565b80156115dc57508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115fe578194506115fb81602001518761239c90919063ffffffff16565b95505b505050604181019050611543565b5081925050509392505050565b611621612922565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116f1578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611655565b50505050905060008090505b8151811015611779578373ffffffffffffffffffffffffffffffffffffffff1682828151811061172957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561176c5781818151811061175d57fe5b60200260200101519250611779565b80806001019150506116fd565b505092915050565b600061178c43611ea1565b905090565b60006117a461179e611781565b8361112a565b9050919050565b60006002600060f81b836040516020016117c692919061329a565b6040516020818303038152906040526040516117e29190613303565b602060405180830381855afa1580156117ff573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506118229190810190612b48565b9050919050565b60008060008061184a600161183c611781565b61239c90919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b606080606060076040519080825280602002602001820160405280156118d25781602001602082028038833980820191505090505b5090507373e033779c9030d4528d86fbcef5b02e97488921816000815181106118f757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050735c3e1b893b9315a968fcc6bce9eb9f7d8e22edb38160018151811061195357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073b005bc07015170266bd430f3ec1322938603be20816002815181106119af57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073a464dc4810bc79b956810759e314d85bce35cd1c81600381518110611a0b57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073e8d02da3dfeeb3e755472d95d666bd6821d9212981600481518110611a6757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073f93b54cf36e917f625b48e1e3c9f93bc2344fb0681600581518110611ac357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505073751ec4877450b8a4d652d0d70197337fc38a42e681600681518110611b1f57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060606007604051908082528060200260200182016040528015611b8b5781602001602082028038833980820191505090505b50905061271081600081518110611b9e57fe5b60200260200101818152505061271081600181518110611bba57fe5b60200260200101818152505061271081600281518110611bd657fe5b60200260200101818152505061271081600381518110611bf257fe5b60200260200101818152505061271081600481518110611c0e57fe5b60200260200101818152505061271081600581518110611c2a57fe5b60200260200101818152505061271081600681518110611c4657fe5b60200260200101818152505081819350935050509091565b60ff81565b60016020528160005260406000208181548110611c7c57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000611cda611cd4611781565b83610939565b9050919050565b604051611ced9061331a565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611dcb578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611d2f565b505050509050600080905060008090505b8251811015611e1e57611e0f838281518110611df457fe5b6020026020010151602001518361239c90919063ffffffff16565b91508080600101915050611ddc565b508092505050919050565b604051611e359061332f565b604051809103902081565b600080600080611e4e611781565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b6000811115611f6157611ebe612959565b6002600060036001850381548110611ed257fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611f2f57506000816040015114155b8015611f3f575080604001518411155b15611f5257806000015192505050611f9c565b50808060019003915050611ead565b5060006003805490501115611f9757600360016003805490500381548110611f8557fe5b90600052602060002001549050611f9c565b600090505b919050565b606080611fad4361075d565b915091509091565b60038181548110611fc257fe5b906000526020600020016000915090505481565b600281565b60006020528160005260406000208181548110611ff457fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b60006040438161204b57fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b60608061208661189d565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff81525060026000838152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600381908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008381526020019081526020016000208161212f91906128f0565b506000600160008381526020019081526020016000208161215091906128f0565b5060008090505b835181101561227257600080838152602001908152602001600020805480919060010161218491906128f0565b5060405180606001604052808281526020018483815181106121a257fe5b602002602001015181526020018583815181106121bb57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060008084815260200190815260200160002082815481106121f957fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612157565b5060008090505b8351811015612396576001600083815260200190815260200160002080548091906001016122a791906128f0565b5060405180606001604052808281526020018483815181106122c557fe5b602002602001015181526020018583815181106122de57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060016000848152602001908152602001600020828154811061231d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050612279565b50505050565b6000808284019050838110156123b157600080fd5b8091505092915050565b6123c361297a565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606123f4826126f0565b6123fd57600080fd5b60006124088361273e565b905060608160405190808252806020026020018201604052801561244657816020015b612433612994565b81526020019060019003908161242b5790505b509050600061245885602001516127af565b8560200151019050600080600090505b848110156124b95761247983612838565b915060405180604001604052808381526020018481525084828151811061249c57fe5b602002602001018190525081830192508080600101915050612468565b5082945050505050919050565b60008082600001511180156124e057506021826000015111155b6124e957600080fd5b60006124f883602001516127af565b9050600081846000015103905060008083866020015101905080519150602083101561252b57826020036101000a820491505b81945050505050919050565b6000601582600001511461254a57600080fd5b612553826124c6565b9050919050565b60608183018451101561256c57600080fd5b6060821560008114612589576040519150602082016040526125da565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156125c757805183526020830192506020810190506125aa565b50868552601f19601f8301166040525050505b50809150509392505050565b600080600080604185511461260157600093505050506126ea565b602085015192506040850151915060ff6041860151169050601b8160ff16101561262c57601b810190505b601b8160ff16141580156126445750601c8160ff1614155b1561265557600093505050506126ea565b60006001878386866040516000815260200160405260405161267a94939291906133e1565b6020604051602081039080840390855afa15801561269c573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156126e257600080fd5b809450505050505b92915050565b600080826000015114156127075760009050612739565b60008083602001519050805160001a915060c060ff168260ff16101561273257600092505050612739565b6001925050505b919050565b6000808260000151141561275557600090506127aa565b6000809050600061276984602001516127af565b84602001510190506000846000015185602001510190505b808210156127a35761279282612838565b820191508280600101935050612781565b8293505050505b919050565b600080825160001a9050608060ff168110156127cf576000915050612833565b60b860ff168110806127f4575060c060ff1681101580156127f3575060f860ff1681105b5b15612803576001915050612833565b60c060ff168110156128235760018060b80360ff16820301915050612833565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561285957600191506128e6565b60b860ff16811015612876576001608060ff1682030191506128e5565b60c060ff168110156128a65760b78103600185019450806020036101000a855104600182018101935050506128e4565b60f860ff168110156128c357600160c060ff1682030191506128e3565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b81548183558181111561291d5760030281600302836000526020600020918201910161291c91906129ae565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b612a0191905b808211156129fd5760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506003016129b4565b5090565b90565b600081359050612a1381613783565b92915050565b600081359050612a288161379a565b92915050565b600081519050612a3d8161379a565b92915050565b60008083601f840112612a5557600080fd5b8235905067ffffffffffffffff811115612a6e57600080fd5b602083019150836001820283011115612a8657600080fd5b9250929050565b600082601f830112612a9e57600080fd5b8135612ab1612aac826135d2565b6135a5565b91508082526020830160208301858383011115612acd57600080fd5b612ad883828461372d565b50505092915050565b600081359050612af0816137b1565b92915050565b600060208284031215612b0857600080fd5b6000612b1684828501612a04565b91505092915050565b600060208284031215612b3157600080fd5b6000612b3f84828501612a19565b91505092915050565b600060208284031215612b5a57600080fd5b6000612b6884828501612a2e565b91505092915050565b60008060408385031215612b8457600080fd5b6000612b9285828601612a19565b9250506020612ba385828601612a19565b9150509250929050565b600080600060608486031215612bc257600080fd5b6000612bd086828701612a19565b9350506020612be186828701612a19565b925050604084013567ffffffffffffffff811115612bfe57600080fd5b612c0a86828701612a8d565b9150509250925092565b600060208284031215612c2657600080fd5b6000612c3484828501612ae1565b91505092915050565b60008060408385031215612c5057600080fd5b6000612c5e85828601612ae1565b9250506020612c6f85828601612a04565b9150509250929050565b600080600060608486031215612c8e57600080fd5b6000612c9c86828701612ae1565b9350506020612cad86828701612a19565b925050604084013567ffffffffffffffff811115612cca57600080fd5b612cd686828701612a8d565b9150509250925092565b60008060408385031215612cf357600080fd5b6000612d0185828601612ae1565b9250506020612d1285828601612ae1565b9150509250929050565b600080600080600080600060a0888a031215612d3757600080fd5b6000612d458a828b01612ae1565b9750506020612d568a828b01612ae1565b9650506040612d678a828b01612ae1565b955050606088013567ffffffffffffffff811115612d8457600080fd5b612d908a828b01612a43565b9450945050608088013567ffffffffffffffff811115612daf57600080fd5b612dbb8a828b01612a43565b925092505092959891949750929550565b6000612dd88383612dfc565b60208301905092915050565b6000612df0838361326d565b60208301905092915050565b612e05816136a2565b82525050565b612e14816136a2565b82525050565b6000612e258261361e565b612e2f8185613659565b9350612e3a836135fe565b8060005b83811015612e6b578151612e528882612dcc565b9750612e5d8361363f565b925050600181019050612e3e565b5085935050505092915050565b6000612e8382613629565b612e8d818561366a565b9350612e988361360e565b8060005b83811015612ec9578151612eb08882612de4565b9750612ebb8361364c565b925050600181019050612e9c565b5085935050505092915050565b612edf816136b4565b82525050565b612ef6612ef1826136c0565b61376f565b82525050565b612f05816136ec565b82525050565b612f1c612f17826136ec565b613779565b82525050565b6000612f2d82613634565b612f37818561367b565b9350612f4781856020860161373c565b80840191505092915050565b6000612f60600483613697565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000612fa0602d83613686565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000613006600f83613686565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000613046601383613686565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000613086604583613686565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000613112600483613697565b91507f34383834000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000613152600d83613697565b91507f6865696d64616c6c2d34383834000000000000000000000000000000000000006000830152600d82019050919050565b6000613192602a83613686565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b60006131f8601283613686565b91507f4e6f742053797374656d204164646573732100000000000000000000000000006000830152602082019050919050565b606082016000820151613241600085018261326d565b506020820151613254602085018261326d565b5060408201516132676040850182612dfc565b50505050565b61327681613716565b82525050565b61328581613716565b82525050565b61329481613720565b82525050565b60006132a68285612ee5565b6001820191506132b68284612f0b565b6020820191508190509392505050565b60006132d28286612ee5565b6001820191506132e28285612f0b565b6020820191506132f28284612f0b565b602082019150819050949350505050565b600061330f8284612f22565b915081905092915050565b600061332582612f53565b9150819050919050565b600061333a82613105565b9150819050919050565b600061334f82613145565b9150819050919050565b600060208201905061336e6000830184612e0b565b92915050565b6000604082019050818103600083015261338e8185612e1a565b905081810360208301526133a28184612e78565b90509392505050565b60006020820190506133c06000830184612ed6565b92915050565b60006020820190506133db6000830184612efc565b92915050565b60006080820190506133f66000830187612efc565b613403602083018661328b565b6134106040830185612efc565b61341d6060830184612efc565b95945050505050565b6000602082019050818103600083015261343f81612f93565b9050919050565b6000602082019050818103600083015261345f81612ff9565b9050919050565b6000602082019050818103600083015261347f81613039565b9050919050565b6000602082019050818103600083015261349f81613079565b9050919050565b600060208201905081810360008301526134bf81613185565b9050919050565b600060208201905081810360008301526134df816131eb565b9050919050565b60006060820190506134fb600083018461322b565b92915050565b6000602082019050613516600083018461327c565b92915050565b6000606082019050613531600083018661327c565b61353e602083018561327c565b61354b6040830184612e0b565b949350505050565b6000606082019050613568600083018661327c565b613575602083018561327c565b613582604083018461327c565b949350505050565b600060208201905061359f600083018461328b565b92915050565b6000604051905081810181811067ffffffffffffffff821117156135c857600080fd5b8060405250919050565b600067ffffffffffffffff8211156135e957600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006136ad826136f6565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b8381101561375a57808201518184015260208101905061373f565b83811115613769576000848401525b50505050565b6000819050919050565b6000819050919050565b61378c816136a2565b811461379757600080fd5b50565b6137a3816136ec565b81146137ae57600080fd5b50565b6137ba81613716565b81146137c557600080fd5b5056fea365627a7a72315820dcb8e2b316913b44a1ab06ab628616579f55396891b1e0b2ffe7c0630e4cd8a36c6578706572696d656e74616cf564736f6c63430005110040" + }, + "0000000000000000000000000000000000001001": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a72315820af228b81e19dac46d14c24d264bde25d8a461d559c4e3cc82a5f1660755df35e64736f6c63430005110032" + }, + "0000000000000000000000000000000000001010": { + "balance": "0x204fcce2c5a141f7f9a00000", + "code": "0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a3565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116a9565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611736565b005b348015610b2e57600080fd5b50610b37611753565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa828488611779565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3690919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611f046023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5690919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611ee16023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b75565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600281526020017f131400000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c7338484611779565b90505b92915050565b6040518060800160405280605b8152602001611f79605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6d565b611d43565b9050949350505050565b61131481565b60015481565b604051806080016040528060528152602001611f27605291396040516020018082805190602001908083835b602083106116f857805182526020820191506020810190506020830392506116d5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173e6114dd565b61174757600080fd5b61175081611b75565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117f957600080fd5b505afa15801561180d573d6000803e3d6000fd5b505050506040513d602081101561182357600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b557600080fd5b505afa1580156118c9573d6000803e3d6000fd5b505050506040513d60208110156118df57600080fd5b810190808051906020019092919050505090506118fd868686611d8d565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0557600080fd5b505afa158015611a19573d6000803e3d6000fd5b505050506040513d6020811015611a2f57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abd57600080fd5b505afa158015611ad1573d6000803e3d6000fd5b505050506040513d6020811015611ae757600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4557600080fd5b600082840390508091505092915050565b600080828401905083811015611b6b57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611baf57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611f79605b91396040516020018082805190602001908083835b60208310611cbf5780518252602082019150602081019050602083039250611c9c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611e2f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f63616e27742073656e6420746f204d524332300000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611e75573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a7231582064ab32303f390d5ef29825736ed3a65b8b2cdc4ca827355b9f3fed047dcd3dc564736f6c63430005110032" + }, + "73E033779C9030D4528d86FbceF5B02e97488921": { + "balance": "0x3635c9adc5dea00000" + }, + "5C3E1B893B9315a968fcC6bce9EB9F7d8E22edB3": { + "balance": "0x3635c9adc5dea00000" + }, + "b005bc07015170266Bd430f3EC1322938603be20": { + "balance": "0x3635c9adc5dea00000" + }, + "A464DC4810Bc79B956810759e314d85BcE35cD1c": { + "balance": "0x3635c9adc5dea00000" + }, + "E8d02Da3dFeeB3e755472D95D666BD6821D92129": { + "balance": "0x3635c9adc5dea00000" + }, + "F93B54Cf36E917f625B48e1e3C9F93BC2344Fb06": { + "balance": "0x3635c9adc5dea00000" + }, + "751eC4877450B8a4D652d0D70197337FC38a42e6": { + "balance": "0x3635c9adc5dea00000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } diff --git a/tests/bor/testdata/genesis_sprint_length_change.json b/tests/bor/testdata/genesis_sprint_length_change.json new file mode 100644 index 0000000000..cb6eb2a729 --- /dev/null +++ b/tests/bor/testdata/genesis_sprint_length_change.json @@ -0,0 +1,69 @@ +{ + "config": { + "chainId": 15001, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 1, + "bor": { + "jaipurBlock": 2, + "delhiBlock" :3, + "period": { + "0": 1 + }, + "producerDelay": { + "0": 6 + }, + "sprint": { + "0": 8, + "16": 4 + }, + "backupMultiplier": { + "0": 1 + }, + "validatorContract": "0x0000000000000000000000000000000000001000", + "stateReceiverContract": "0x0000000000000000000000000000000000001001", + "burntContract": { + "0": "0x000000000000000000000000000000000000dead" + } + } + }, + "nonce": "0x0", + "timestamp": "0x5ce28211", + "extraData": "", + "gasLimit": "0x989680", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000001000": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a91908101906129ba565b610706565b60405161021e939291906132f9565b60405180910390f35b610241600480360361023c91908101906129ba565b61075d565b60405161024f92919061311a565b60405180910390f35b610272600480360361026d91908101906129e3565b610939565b60405161027f9190613151565b60405180910390f35b6102a2600480360361029d9190810190612ac2565b610a91565b005b6102be60048036036102b991908101906129e3565b61112a565b6040516102cb9190613151565b60405180910390f35b6102dc611281565b6040516102e991906132a7565b60405180910390f35b61030c60048036036103079190810190612917565b611286565b604051610319919061316c565b60405180910390f35b61033c600480360361033791908101906129ba565b611307565b60405161034991906132a7565b60405180910390f35b61035a611437565b60405161036791906130ff565b60405180910390f35b61038a60048036036103859190810190612953565b61144f565b6040516103979190613151565b60405180910390f35b6103a861151a565b6040516103b5919061316c565b60405180910390f35b6103d860048036036103d39190810190612a1f565b611531565b6040516103e591906132a7565b60405180910390f35b610408600480360361040391908101906129e3565b611619565b604051610415919061328c565b60405180910390f35b610426611781565b60405161043391906132a7565b60405180910390f35b6104566004803603610451919081019061289c565b611791565b6040516104639190613151565b60405180910390f35b610486600480360361048191908101906128c5565b6117ab565b604051610493919061316c565b60405180910390f35b6104a4611829565b6040516104b3939291906132f9565b60405180910390f35b6104c461189d565b6040516104d292919061311a565b60405180910390f35b6104e3611a04565b6040516104f091906132a7565b60405180910390f35b610513600480360361050e9190810190612a86565b611a09565b604051610522939291906132c2565b60405180910390f35b6105456004803603610540919081019061289c565b611a6d565b6040516105529190613151565b60405180910390f35b610563611a87565b604051610570919061316c565b60405180910390f35b610593600480360361058e91908101906129ba565b611a9e565b6040516105a091906132a7565b60405180910390f35b6105b1611bcf565b6040516105be919061316c565b60405180910390f35b6105cf611be6565b6040516105de939291906132f9565b60405180910390f35b61060160048036036105fc91908101906129ba565b611c47565b60405161060e91906132a7565b60405180910390f35b61061f611d47565b60405161062d92919061311a565b60405180910390f35b610650600480360361064b91908101906129ba565b611d5b565b60405161065d91906132a7565b60405180910390f35b61066e611d7c565b60405161067b9190613330565b60405180910390f35b61069e60048036036106999190810190612a86565b611d81565b6040516106ad939291906132c2565b60405180910390f35b6106be611de5565b6040516106cb91906132a7565b60405180910390f35b6106ee60048036036106e991908101906129ba565b611df7565b6040516106fd939291906132f9565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107795761077061189d565b91509150610934565b600061078484611c47565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b13576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a9061326c565b60405180910390fd5b6000610b1d611781565b90506000811415610b3157610b30611e21565b5b610b4560018261214290919063ffffffff16565b8814610b86576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b7d906131ec565b60405180910390fd5b868611610bc8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bbf9061324c565b60405180910390fd5b6000604060018989030181610bd957fe5b0614610c1a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c119061322c565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c6a906131cc565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610ccc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cc39061320c565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d669190612696565b506000600160008a815260200190815260200160002081610d879190612696565b506060610ddf610dda87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612161565b61218f565b905060008090505b8151811015610f51576060610e0e838381518110610e0157fe5b602002602001015161218f565b90506000808c81526020019081526020016000208054809190600101610e349190612696565b506040518060600160405280610e5d83600081518110610e5057fe5b602002602001015161226c565b8152602001610e7f83600181518110610e7257fe5b602002602001015161226c565b8152602001610ea183600281518110610e9457fe5b60200260200101516122dd565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ed757fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610de7565b506060610fa9610fa486868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612161565b61218f565b905060008090505b815181101561111d576060610fd8838381518110610fcb57fe5b602002602001015161218f565b9050600160008d81526020019081526020016000208054809190600101610fff9190612696565b5060405180606001604052806110288360008151811061101b57fe5b602002602001015161226c565b815260200161104a8360018151811061103d57fe5b602002602001015161226c565b815260200161106c8360028151811061105f57fe5b60200260200101516122dd565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e815260200190815260200160002083815481106110a357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fb1565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111fc578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611160565b50505050905060008090505b8151811015611274578373ffffffffffffffffffffffffffffffffffffffff1682828151811061123457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112675760019250505061127b565b8080600101915050611208565b5060009150505b92915050565b604081565b60006002600160f81b84846040516020016112a39392919061306c565b6040516020818303038152906040526040516112bf91906130a9565b602060405180830381855afa1580156112dc573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112ff91908101906128ee565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113d9578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061133d565b505050509050600080905060008090505b825181101561142c5761141d83828151811061140257fe5b6020026020010151602001518361214290919063ffffffff16565b915080806001019150506113ea565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161146657fe5b04029050600081111561147f5761147c876117ab565b91505b6000602190505b818111611509576000600182038801519050818801519550806000602081106114ab57fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114f0576114e98685611286565b93506114fd565b6114fa8487611286565b93505b50602181019050611486565b508782149450505050509392505050565b604051611526906130d5565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff16101561160c57606061156e868367ffffffffffffffff166041612300565b90506000611585828961238c90919063ffffffff16565b905061158f6126c8565b6115998a83611619565b90506115a58a8361112a565b80156115dc57508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115fe578194506115fb81602001518761214290919063ffffffff16565b95505b505050604181019050611543565b5081925050509392505050565b6116216126c8565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116f1578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611655565b50505050905060008090505b8151811015611779578373ffffffffffffffffffffffffffffffffffffffff1682828151811061172957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561176c5781818151811061175d57fe5b60200260200101519250611779565b80806001019150506116fd565b505092915050565b600061178c43611c47565b905090565b60006117a461179e611781565b8361112a565b9050919050565b60006002600060f81b836040516020016117c6929190613040565b6040516020818303038152906040526040516117e291906130a9565b602060405180830381855afa1580156117ff573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525061182291908101906128ee565b9050919050565b60008060008061184a600161183c611781565b61214290919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b606080606060026040519080825280602002602001820160405280156118d25781602001602082028038833980820191505090505b5090507371562b71999873db5b286df957af199ec94617f7816000815181106118f757fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050739fb29aac15b9a4b7f17c3385939b007540f4d7918160018151811061195357fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050606060026040519080825280602002602001820160405280156119bf5781602001602082028038833980820191505090505b5090506028816000815181106119d157fe5b602002602001018181525050601e816001815181106119ec57fe5b60200260200101818152505081819350935050509091565b60ff81565b60016020528160005260406000208181548110611a2257fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000611a80611a7a611781565b83610939565b9050919050565b604051611a93906130c0565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611b71578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611ad5565b505050509050600080905060008090505b8251811015611bc457611bb5838281518110611b9a57fe5b6020026020010151602001518361214290919063ffffffff16565b91508080600101915050611b82565b508092505050919050565b604051611bdb906130ea565b604051809103902081565b600080600080611bf4611781565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b6000811115611d0757611c646126ff565b6002600060036001850381548110611c7857fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611cd557506000816040015114155b8015611ce5575080604001518411155b15611cf857806000015192505050611d42565b50808060019003915050611c53565b5060006003805490501115611d3d57600360016003805490500381548110611d2b57fe5b90600052602060002001549050611d42565b600090505b919050565b606080611d534361075d565b915091509091565b60038181548110611d6857fe5b906000526020600020016000915090505481565b600281565b60006020528160005260406000208181548110611d9a57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b600060404381611df157fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b606080611e2c61189d565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff815250600260008381526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506003819080600181540180825580915050906001820390600052602060002001600090919290919091505550600080600083815260200190815260200160002081611ed59190612696565b5060006001600083815260200190815260200160002081611ef69190612696565b5060008090505b8351811015612018576000808381526020019081526020016000208054809190600101611f2a9190612696565b506040518060600160405280828152602001848381518110611f4857fe5b60200260200101518152602001858381518110611f6157fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168152506000808481526020019081526020016000208281548110611f9f57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050611efd565b5060008090505b835181101561213c5760016000838152602001908152602001600020805480919060010161204d9190612696565b50604051806060016040528082815260200184838151811061206b57fe5b6020026020010151815260200185838151811061208457fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168152506001600084815260200190815260200160002082815481106120c357fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050808060010191505061201f565b50505050565b60008082840190508381101561215757600080fd5b8091505092915050565b612169612720565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061219a82612496565b6121a357600080fd5b60006121ae836124e4565b90506060816040519080825280602002602001820160405280156121ec57816020015b6121d961273a565b8152602001906001900390816121d15790505b50905060006121fe8560200151612555565b8560200151019050600080600090505b8481101561225f5761221f836125de565b915060405180604001604052808381526020018481525084828151811061224257fe5b60200260200101819052508183019250808060010191505061220e565b5082945050505050919050565b600080826000015111801561228657506021826000015111155b61228f57600080fd5b600061229e8360200151612555565b905060008184600001510390506000808386602001510190508051915060208310156122d157826020036101000a820491505b81945050505050919050565b600060158260000151146122f057600080fd5b6122f98261226c565b9050919050565b60608183018451101561231257600080fd5b606082156000811461232f57604051915060208201604052612380565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561236d5780518352602083019250602081019050612350565b50868552601f19601f8301166040525050505b50809150509392505050565b60008060008060418551146123a75760009350505050612490565b602085015192506040850151915060ff6041860151169050601b8160ff1610156123d257601b810190505b601b8160ff16141580156123ea5750601c8160ff1614155b156123fb5760009350505050612490565b6000600187838686604051600081526020016040526040516124209493929190613187565b6020604051602081039080840390855afa158015612442573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561248857600080fd5b809450505050505b92915050565b600080826000015114156124ad57600090506124df565b60008083602001519050805160001a915060c060ff168260ff1610156124d8576000925050506124df565b6001925050505b919050565b600080826000015114156124fb5760009050612550565b6000809050600061250f8460200151612555565b84602001510190506000846000015185602001510190505b8082101561254957612538826125de565b820191508280600101935050612527565b8293505050505b919050565b600080825160001a9050608060ff168110156125755760009150506125d9565b60b860ff1681108061259a575060c060ff168110158015612599575060f860ff1681105b5b156125a95760019150506125d9565b60c060ff168110156125c95760018060b80360ff168203019150506125d9565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff168110156125ff576001915061268c565b60b860ff1681101561261c576001608060ff16820301915061268b565b60c060ff1681101561264c5760b78103600185019450806020036101000a8551046001820181019350505061268a565b60f860ff1681101561266957600160c060ff168203019150612689565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b8154818355818111156126c3576003028160030283600052602060002091820191016126c29190612754565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b6127a791905b808211156127a35760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555060030161275a565b5090565b90565b6000813590506127b981613529565b92915050565b6000813590506127ce81613540565b92915050565b6000815190506127e381613540565b92915050565b60008083601f8401126127fb57600080fd5b8235905067ffffffffffffffff81111561281457600080fd5b60208301915083600182028301111561282c57600080fd5b9250929050565b600082601f83011261284457600080fd5b813561285761285282613378565b61334b565b9150808252602083016020830185838301111561287357600080fd5b61287e8382846134d3565b50505092915050565b60008135905061289681613557565b92915050565b6000602082840312156128ae57600080fd5b60006128bc848285016127aa565b91505092915050565b6000602082840312156128d757600080fd5b60006128e5848285016127bf565b91505092915050565b60006020828403121561290057600080fd5b600061290e848285016127d4565b91505092915050565b6000806040838503121561292a57600080fd5b6000612938858286016127bf565b9250506020612949858286016127bf565b9150509250929050565b60008060006060848603121561296857600080fd5b6000612976868287016127bf565b9350506020612987868287016127bf565b925050604084013567ffffffffffffffff8111156129a457600080fd5b6129b086828701612833565b9150509250925092565b6000602082840312156129cc57600080fd5b60006129da84828501612887565b91505092915050565b600080604083850312156129f657600080fd5b6000612a0485828601612887565b9250506020612a15858286016127aa565b9150509250929050565b600080600060608486031215612a3457600080fd5b6000612a4286828701612887565b9350506020612a53868287016127bf565b925050604084013567ffffffffffffffff811115612a7057600080fd5b612a7c86828701612833565b9150509250925092565b60008060408385031215612a9957600080fd5b6000612aa785828601612887565b9250506020612ab885828601612887565b9150509250929050565b600080600080600080600060a0888a031215612add57600080fd5b6000612aeb8a828b01612887565b9750506020612afc8a828b01612887565b9650506040612b0d8a828b01612887565b955050606088013567ffffffffffffffff811115612b2a57600080fd5b612b368a828b016127e9565b9450945050608088013567ffffffffffffffff811115612b5557600080fd5b612b618a828b016127e9565b925092505092959891949750929550565b6000612b7e8383612ba2565b60208301905092915050565b6000612b968383613013565b60208301905092915050565b612bab81613448565b82525050565b612bba81613448565b82525050565b6000612bcb826133c4565b612bd581856133ff565b9350612be0836133a4565b8060005b83811015612c11578151612bf88882612b72565b9750612c03836133e5565b925050600181019050612be4565b5085935050505092915050565b6000612c29826133cf565b612c338185613410565b9350612c3e836133b4565b8060005b83811015612c6f578151612c568882612b8a565b9750612c61836133f2565b925050600181019050612c42565b5085935050505092915050565b612c858161345a565b82525050565b612c9c612c9782613466565b613515565b82525050565b612cab81613492565b82525050565b612cc2612cbd82613492565b61351f565b82525050565b6000612cd3826133da565b612cdd8185613421565b9350612ced8185602086016134e2565b80840191505092915050565b6000612d0660048361343d565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000612d46602d8361342c565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000612dac600f8361343d565b91507f6865696d64616c6c2d50357258776700000000000000000000000000000000006000830152600f82019050919050565b6000612dec600f8361342c565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000612e2c60138361342c565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000612e6c60458361342c565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000612ef8602a8361342c565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000612f5e60058361343d565b91507f31353030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b6000612f9e60128361342c565b91507f4e6f742053797374656d204164646573732100000000000000000000000000006000830152602082019050919050565b606082016000820151612fe76000850182613013565b506020820151612ffa6020850182613013565b50604082015161300d6040850182612ba2565b50505050565b61301c816134bc565b82525050565b61302b816134bc565b82525050565b61303a816134c6565b82525050565b600061304c8285612c8b565b60018201915061305c8284612cb1565b6020820191508190509392505050565b60006130788286612c8b565b6001820191506130888285612cb1565b6020820191506130988284612cb1565b602082019150819050949350505050565b60006130b58284612cc8565b915081905092915050565b60006130cb82612cf9565b9150819050919050565b60006130e082612d9f565b9150819050919050565b60006130f582612f51565b9150819050919050565b60006020820190506131146000830184612bb1565b92915050565b600060408201905081810360008301526131348185612bc0565b905081810360208301526131488184612c1e565b90509392505050565b60006020820190506131666000830184612c7c565b92915050565b60006020820190506131816000830184612ca2565b92915050565b600060808201905061319c6000830187612ca2565b6131a96020830186613031565b6131b66040830185612ca2565b6131c36060830184612ca2565b95945050505050565b600060208201905081810360008301526131e581612d39565b9050919050565b6000602082019050818103600083015261320581612ddf565b9050919050565b6000602082019050818103600083015261322581612e1f565b9050919050565b6000602082019050818103600083015261324581612e5f565b9050919050565b6000602082019050818103600083015261326581612eeb565b9050919050565b6000602082019050818103600083015261328581612f91565b9050919050565b60006060820190506132a16000830184612fd1565b92915050565b60006020820190506132bc6000830184613022565b92915050565b60006060820190506132d76000830186613022565b6132e46020830185613022565b6132f16040830184612bb1565b949350505050565b600060608201905061330e6000830186613022565b61331b6020830185613022565b6133286040830184613022565b949350505050565b60006020820190506133456000830184613031565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561336e57600080fd5b8060405250919050565b600067ffffffffffffffff82111561338f57600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006134538261349c565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b838110156135005780820151818401526020810190506134e5565b8381111561350f576000848401525b50505050565b6000819050919050565b6000819050919050565b61353281613448565b811461353d57600080fd5b50565b61354981613492565b811461355457600080fd5b50565b613560816134bc565b811461356b57600080fd5b5056fea365627a7a7231582051bf0a46b5958c4ecdf9f1f9a9d8b62deacac5d79cdf5595e9853f3c0132fe236c6578706572696d656e74616cf564736f6c63430005110040" + }, + "0000000000000000000000000000000000001001": { + "balance": "0x0", + "code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a72315820af228b81e19dac46d14c24d264bde25d8a461d559c4e3cc82a5f1660755df35e64736f6c63430005110032" + }, + "0000000000000000000000000000000000001010": { + "balance": "0x204fcdf1d291a6d552c00000", + "code": "0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a3565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116a9565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611736565b005b348015610b2e57600080fd5b50610b37611753565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa828488611779565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3690919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611f046023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5690919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611ee16023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b75565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600281526020017f3a9900000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c7338484611779565b90505b92915050565b6040518060800160405280605b8152602001611f79605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6d565b611d43565b9050949350505050565b613a9981565b60015481565b604051806080016040528060528152602001611f27605291396040516020018082805190602001908083835b602083106116f857805182526020820191506020810190506020830392506116d5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173e6114dd565b61174757600080fd5b61175081611b75565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117f957600080fd5b505afa15801561180d573d6000803e3d6000fd5b505050506040513d602081101561182357600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b557600080fd5b505afa1580156118c9573d6000803e3d6000fd5b505050506040513d60208110156118df57600080fd5b810190808051906020019092919050505090506118fd868686611d8d565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0557600080fd5b505afa158015611a19573d6000803e3d6000fd5b505050506040513d6020811015611a2f57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abd57600080fd5b505afa158015611ad1573d6000803e3d6000fd5b505050506040513d6020811015611ae757600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4557600080fd5b600082840390508091505092915050565b600080828401905083811015611b6b57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611baf57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611f79605b91396040516020018082805190602001908083835b60208310611cbf5780518252602082019150602081019050602083039250611c9c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611e2f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f63616e27742073656e6420746f204d524332300000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611e75573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a723158205723157ad1c8ebb37fecace5dc0ce2dfa893ec59d46a1305ad694cd0170076ab64736f6c63430005110032" + }, + "71562b71999873DB5b286dF957af199Ec94617F7": { + "balance": "0x3635c9adc5dea00000" + }, + "9fB29AAc15b9A4B7F17c3385939b007540f4d791": { + "balance": "0x3635c9adc5dea00000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } diff --git a/tests/difficulty_test.go b/tests/difficulty_test.go index 0b030c1485..d8b172d6fe 100644 --- a/tests/difficulty_test.go +++ b/tests/difficulty_test.go @@ -91,7 +91,7 @@ func TestDifficulty(t *testing.T) { return } if err := dt.checkFailure(t, test.Run(cfg)); err != nil { - t.Error(err) + t.Errorf("in 'difficulty_test.go', test '%s' failed with error: '%v'", name, err) } }) } diff --git a/tests/fuzzers/les/les-fuzzer.go b/tests/fuzzers/les/les-fuzzer.go index 3e10171873..c379d1f08d 100644 --- a/tests/fuzzers/les/les-fuzzer.go +++ b/tests/fuzzers/les/les-fuzzer.go @@ -80,7 +80,7 @@ func makechain() (bc *core.BlockChain, addrHashes, txHashes []common.Hash) { addrHashes = append(addrHashes, crypto.Keccak256Hash(addr[:])) txHashes = append(txHashes, tx.Hash()) }) - bc, _ = core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if _, err := bc.InsertChain(blocks); err != nil { panic(err) } diff --git a/tests/fuzzers/snap/fuzz_handler.go b/tests/fuzzers/snap/fuzz_handler.go index 1ae61df29d..d58221b500 100644 --- a/tests/fuzzers/snap/fuzz_handler.go +++ b/tests/fuzzers/snap/fuzz_handler.go @@ -79,7 +79,7 @@ func getChain() *core.BlockChain { SnapshotWait: true, } trieRoot = blocks[len(blocks)-1].Root() - bc, _ := core.NewBlockChain(db, cacheConf, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := core.NewBlockChain(db, cacheConf, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if _, err := bc.InsertChain(blocks); err != nil { panic(err) } diff --git a/tests/init.go b/tests/init.go index d6b5b3043d..47bfac1859 100644 --- a/tests/init.go +++ b/tests/init.go @@ -28,15 +28,18 @@ import ( var Forks = map[string]*params.ChainConfig{ "Frontier": { ChainID: big.NewInt(1), + Bor: params.BorUnittestChainConfig.Bor, }, "Homestead": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), + Bor: params.BorUnittestChainConfig.Bor, }, "EIP150": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), + Bor: params.BorUnittestChainConfig.Bor, }, "EIP158": { ChainID: big.NewInt(1), @@ -44,6 +47,7 @@ var Forks = map[string]*params.ChainConfig{ EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), + Bor: params.BorUnittestChainConfig.Bor, }, "Byzantium": { ChainID: big.NewInt(1), @@ -53,6 +57,7 @@ var Forks = map[string]*params.ChainConfig{ EIP158Block: big.NewInt(0), DAOForkBlock: big.NewInt(0), ByzantiumBlock: big.NewInt(0), + Bor: params.BorUnittestChainConfig.Bor, }, "Constantinople": { ChainID: big.NewInt(1), @@ -64,6 +69,7 @@ var Forks = map[string]*params.ChainConfig{ ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(10000000), + Bor: params.BorUnittestChainConfig.Bor, }, "ConstantinopleFix": { ChainID: big.NewInt(1), @@ -75,6 +81,7 @@ var Forks = map[string]*params.ChainConfig{ ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), + Bor: params.BorUnittestChainConfig.Bor, }, "Istanbul": { ChainID: big.NewInt(1), @@ -87,21 +94,25 @@ var Forks = map[string]*params.ChainConfig{ ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), + Bor: params.BorUnittestChainConfig.Bor, }, "FrontierToHomesteadAt5": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(5), + Bor: params.BorUnittestChainConfig.Bor, }, "HomesteadToEIP150At5": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(5), + Bor: params.BorUnittestChainConfig.Bor, }, "HomesteadToDaoAt5": { ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: big.NewInt(5), DAOForkSupport: true, + Bor: params.BorUnittestChainConfig.Bor, }, "EIP158ToByzantiumAt5": { ChainID: big.NewInt(1), @@ -110,6 +121,7 @@ var Forks = map[string]*params.ChainConfig{ EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(5), + Bor: params.BorUnittestChainConfig.Bor, }, "ByzantiumToConstantinopleAt5": { ChainID: big.NewInt(1), @@ -119,6 +131,7 @@ var Forks = map[string]*params.ChainConfig{ EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(5), + Bor: params.BorUnittestChainConfig.Bor, }, "ByzantiumToConstantinopleFixAt5": { ChainID: big.NewInt(1), @@ -129,6 +142,7 @@ var Forks = map[string]*params.ChainConfig{ ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(5), PetersburgBlock: big.NewInt(5), + Bor: params.BorUnittestChainConfig.Bor, }, "ConstantinopleFixToIstanbulAt5": { ChainID: big.NewInt(1), @@ -140,6 +154,7 @@ var Forks = map[string]*params.ChainConfig{ ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(5), + Bor: params.BorUnittestChainConfig.Bor, }, "Berlin": { ChainID: big.NewInt(1), @@ -153,6 +168,7 @@ var Forks = map[string]*params.ChainConfig{ IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), + Bor: params.BorUnittestChainConfig.Bor, }, "BerlinToLondonAt5": { ChainID: big.NewInt(1), @@ -167,6 +183,7 @@ var Forks = map[string]*params.ChainConfig{ MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(5), + Bor: params.BorUnittestChainConfig.Bor, }, "London": { ChainID: big.NewInt(1), @@ -181,6 +198,7 @@ var Forks = map[string]*params.ChainConfig{ MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), + Bor: params.BorUnittestChainConfig.Bor, }, "ArrowGlacier": { ChainID: big.NewInt(1), @@ -196,6 +214,7 @@ var Forks = map[string]*params.ChainConfig{ BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0), + Bor: params.BorUnittestChainConfig.Bor, }, } diff --git a/tests/init_test.go b/tests/init_test.go index 4ade0bfb90..1c6841e030 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -285,7 +285,7 @@ func TestMatcherRunonlylist(t *testing.T) { tm.runonly("invalid*") tm.walk(t, rlpTestDir, func(t *testing.T, name string, test *RLPTest) { if name[:len("invalidRLPTest.json")] != "invalidRLPTest.json" { - t.Fatalf("invalid test found: %s != invalidRLPTest.json", name) + t.Fatalf("in 'init_test.go' invalid test found: %s != invalidRLPTest.json", name) } }) } diff --git a/tests/rlp_test.go b/tests/rlp_test.go index dbca73efc6..a41464c30c 100644 --- a/tests/rlp_test.go +++ b/tests/rlp_test.go @@ -28,7 +28,7 @@ func TestRLP(t *testing.T) { tm := new(testMatcher) tm.walk(t, rlpTestDir, func(t *testing.T, name string, test *RLPTest) { if err := tm.checkFailure(t, test.Run()); err != nil { - t.Error(err) + t.Errorf("in 'rlp_test.go', test '%s' failed with error: '%v'", name, err) } }) } diff --git a/tests/state_test.go b/tests/state_test.go index 8fcf35b864..f18b84d16e 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -58,6 +58,63 @@ func TestState(t *testing.T) { // Uses 1GB RAM per tested fork st.skipLoad(`^stStaticCall/static_Call1MB`) + // See POS-618 + st.skipLoad(`.*micro/*`) + st.skipLoad(`.*main/*`) + st.skipLoad(`.*stSStoreTest*`) + st.skipLoad(`.*stReturnDataTest*`) + st.skipLoad(`.*stShift*`) + st.skipLoad(`.*stWalletTest*`) + st.skipLoad(`.*stStaticCall*`) + st.skipLoad(`.*stZeroKnowledge*`) + st.skipLoad(`.*stSystemOperationsTest*`) + st.skipLoad(`.*stZeroCallsTest*`) + st.skipLoad(`.*stZeroCallsRevert*`) + st.skipLoad(`.*stTransactionTest*`) + st.skipLoad(`.*stRandom2*`) + st.skipLoad(`.*stSolidityTest*`) + st.skipLoad(`.*stSpecialTest*`) + st.skipLoad(`.*stSelfBalance*`) + st.skipLoad(`.*stRefundTest*`) + st.skipLoad(`.*stRecursiveCreate*`) + st.skipLoad(`.*stQuadraticComplexityTest*`) + st.skipLoad(`.*stNonZeroCallsTest*`) + st.skipLoad(`.*stPreCompiledContracts2*`) + st.skipLoad(`.*stRevertTest*`) + st.skipLoad(`.*stMemoryTest*`) + st.skipLoad(`.*stMemoryStressTest*`) + st.skipLoad(`.*stTransitionTest*`) + st.skipLoad(`.*stInitCodeTest*`) + st.skipLoad(`.*stMemExpandingEIP150Calls*`) + st.skipLoad(`.*stEIP150Specific*`) + st.skipLoad(`.*stEIP150singleCodeGasPrices*`) + st.skipLoad(`.*stExtCodeHash*`) + st.skipLoad(`.*stEIP158Specific*`) + st.skipLoad(`.*stHomesteadSpecific*`) + st.skipLoad(`.*stEIP2930*`) + st.skipLoad(`.*stEIP1559*`) + st.skipLoad(`.*stEIP3607*`) + st.skipLoad(`.*stChangedEIP150*`) + st.skipLoad(`.*stLogTests*`) + st.skipLoad(`.*stSLoadTest*`) + st.skipLoad(`.*stDelegatecallTestHomestead*`) + st.skipLoad(`.*stCallDelegateCodesHomestead*`) + st.skipLoad(`.*VMTests*`) + st.skipLoad(`.*stArgsZeroOneBalance*`) + st.skipLoad(`.*stCallCodes*`) + st.skipLoad(`.*stExample*`) + st.skipLoad(`.*stCreate2*`) + st.skipLoad(`.*stChainId*`) + st.skipLoad(`.*stStaticFlagEnabled*`) + st.skipLoad(`.*stCallDelegateCodesCallCodeHomestead*`) + st.skipLoad(`.*stCallCreateCallCodeTest*`) + st.skipLoad(`.*stBugs*`) + st.skipLoad(`.*stCodeSizeLimit*`) + st.skipLoad(`.*stCodeCopyTest*`) + st.skipLoad(`.*stBadOpcode*`) + st.skipLoad(`.*stStackTests*`) + st.skipLoad(`.*stAttackTest*`) + // Broken tests: // Expected failures: //st.fails(`^stRevertTest/RevertPrecompiledTouch(_storage)?\.json/Byzantium/0`, "bug in test") @@ -93,6 +150,7 @@ func TestState(t *testing.T) { snaps, statedb, err := test.Run(subtest, vmconfig, true) if snaps != nil && statedb != nil { if _, err := snaps.Journal(statedb.IntermediateRoot(false)); err != nil { + t.Errorf("in 'rlp_test.go', test '%s' failed with error: '%v'", name, err) return err } } @@ -121,6 +179,7 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { // Test failed, re-run with tracing enabled. t.Error(err) + if gasLimit > traceErrorLimit { t.Log("gas limit too high for EVM trace") return diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 4fd3cf76b2..65f93bfbe3 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -24,6 +24,8 @@ import ( "strconv" "strings" + "golang.org/x/crypto/sha3" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" @@ -37,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/crypto/sha3" ) // StateTest checks transaction processing without block context. @@ -217,15 +218,16 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // Prepare the EVM. txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) - context.GetHash = vmTestBlockHash - context.BaseFee = baseFee + evmContext := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) + evmContext.GetHash = vmTestBlockHash + evmContext.BaseFee = baseFee if t.json.Env.Random != nil { rnd := common.BigToHash(t.json.Env.Random) - context.Random = &rnd - context.Difficulty = big.NewInt(0) + evmContext.Random = &rnd + evmContext.Difficulty = big.NewInt(0) } - evm := vm.NewEVM(context, txContext, statedb, config, vmconfig) + + evm := vm.NewEVM(evmContext, txContext, statedb, config, vmconfig) // Execute the message. snapshot := statedb.Snapshot() gaspool := new(core.GasPool) diff --git a/tests/testdata b/tests/testdata new file mode 160000 index 0000000000..a380655e5f --- /dev/null +++ b/tests/testdata @@ -0,0 +1 @@ +Subproject commit a380655e5ffab1a5ea0f4d860224bdb19013f06a diff --git a/tests/transaction_test.go b/tests/transaction_test.go index 1197eebe19..5663805605 100644 --- a/tests/transaction_test.go +++ b/tests/transaction_test.go @@ -51,7 +51,7 @@ func TestTransaction(t *testing.T) { txt.walk(t, transactionTestDir, func(t *testing.T, name string, test *TransactionTest) { cfg := params.MainnetChainConfig if err := txt.checkFailure(t, test.Run(cfg)); err != nil { - t.Error(err) + t.Errorf("in 'transaction_test.go', test '%s' failed with error: '%v'", name, err) } }) }