From 816e30108aabb01612fea1fa82632ec1f6b599cd Mon Sep 17 00:00:00 2001 From: dylanhuang Date: Mon, 26 Sep 2022 17:31:16 +0800 Subject: [PATCH 01/61] tracers ci: drop duktape engine (#24934) and add linux-arm binaries to releases page (#1100) --- .github/generate_change_log.sh | 10 +- .github/workflows/pre-release.yml | 108 +- .github/workflows/release.yml | 110 +- Dockerfile | 6 +- Makefile | 17 +- accounts/abi/bind/bind_test.go | 2 +- console/console_test.go | 2 +- core/state_transition.go | 28 +- core/vm/logger.go | 10 +- core/vm/runtime/runtime_test.go | 21 +- eth/tracers/api.go | 85 +- eth/tracers/api_test.go | 33 +- .../internal/tracetest/calltrace_test.go | 17 +- .../testdata/call_tracer/simple_onlytop.json | 72 ++ eth/tracers/js/goja.go | 966 ++++++++++++++++++ eth/tracers/js/internal/tracers/tracers.go | 41 + eth/tracers/js/tracer.go | 880 ---------------- eth/tracers/js/tracer_test.go | 89 +- eth/tracers/logger/access_list_tracer.go | 4 + eth/tracers/logger/logger.go | 131 ++- eth/tracers/logger/logger_json.go | 4 + eth/tracers/native/4byte.go | 8 +- eth/tracers/native/call.go | 25 +- eth/tracers/native/noop.go | 8 +- eth/tracers/native/prestate.go | 30 +- eth/tracers/native/tracer.go | 16 +- eth/tracers/tracers.go | 6 +- go.mod | 76 +- go.sum | 26 +- 29 files changed, 1745 insertions(+), 1086 deletions(-) create mode 100644 eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json create mode 100644 eth/tracers/js/goja.go delete mode 100644 eth/tracers/js/tracer.go diff --git a/.github/generate_change_log.sh b/.github/generate_change_log.sh index ab8ffff68..9caf6f202 100755 --- a/.github/generate_change_log.sh +++ b/.github/generate_change_log.sh @@ -24,6 +24,10 @@ TESTNET_ZIP_SUM="$(checksum ./testnet.zip)" LINUX_BIN_SUM="$(checksum ./linux/geth)" MAC_BIN_SUM="$(checksum ./macos/geth)" WINDOWS_BIN_SUM="$(checksum ./windows/geth.exe)" +ARM5_BIN_SUM="$(checksum ./arm5/geth-linux-arm-5)" +ARM6_BIN_SUM="$(checksum ./arm6/geth-linux-arm-6)" +ARM7_BIN_SUM="$(checksum ./arm7/geth-linux-arm-7)" +ARM64_BIN_SUM="$(checksum ./arm64/geth-linux-arm64)" OUTPUT=$(cat <<-END ## Changelog\n ${CHANGE_LOG}\n @@ -35,7 +39,11 @@ ${CHANGE_LOG}\n | geth_linux | ${LINUX_BIN_SUM} |\n | geth_mac | ${MAC_BIN_SUM} |\n | geth_windows | ${WINDOWS_BIN_SUM} |\n +| geth_linux_arm-5 | ${ARM5_BIN_SUM} |\n +| geth_linux_arm-6 | ${ARM6_BIN_SUM} |\n +| geth_linux_arm-7 | ${ARM7_BIN_SUM} |\n +| geth_linux_arm64 | ${ARM64_BIN_SUM} |\n END ) -echo -e ${OUTPUT} +echo -e ${OUTPUT} \ No newline at end of file diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index cd9f5d193..0e7b5ea53 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -37,7 +37,6 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - # ============================== # Linux/Macos/Windows Build # ============================== @@ -46,6 +45,18 @@ jobs: run: make geth # ============================== + # Cross Compile for ARM + # ============================== + + - name: Build Binary for ARM + if: matrix.os == 'ubuntu-18.04' + env: + GOPATH: /home/runner/work/woodpecker/go + run: | + mkdir -p $GOPATH/src/github.com/bnb-chain/bsc/ + cp -r ./* $GOPATH/src/github.com/bnb-chain/bsc/ + cd $GOPATH/src/github.com/bnb-chain/bsc/ && make geth-linux-arm + # ============================== # Upload artifacts # ============================== @@ -70,6 +81,34 @@ jobs: name: windows path: ./build/bin/geth.exe + - name: Upload ARM-5 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm5 + path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-5 + + - name: Upload ARM-6 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm6 + path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-6 + + - name: Upload ARM-7 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm7 + path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-7 + + - name: Upload ARM-64 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm64 + path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm64 + release: name: Release needs: build @@ -102,6 +141,30 @@ jobs: with: name: windows path: ./windows + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm5 + path: ./arm5 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm6 + path: ./arm6 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm7 + path: ./arm7 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm64 + path: ./arm64 - name: Download Config File run: | @@ -110,7 +173,6 @@ jobs: echo "testnet.zip url: $TESTNET_FILE_URL" curl -L $MAINNET_FILE_URL -o ./mainnet.zip curl -L $TESTNET_FILE_URL -o ./testnet.zip - # ============================== # Create release # ============================== @@ -161,6 +223,46 @@ jobs: asset_path: ./windows/geth.exe asset_name: geth_windows.exe asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 5 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm5/geth-linux-arm-5 + asset_name: geth-linux-arm-5 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 6 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm6/geth-linux-arm-6 + asset_name: geth-linux-arm-6 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 7 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm7/geth-linux-arm-7 + asset_name: geth-linux-arm-7 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm64/geth-linux-arm64 + asset_name: geth-linux-arm64 + asset_content_type: application/octet-stream - name: Upload Release Asset - MAINNET.ZIP uses: actions/upload-release-asset@v1 @@ -180,4 +282,4 @@ jobs: upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps asset_path: ./testnet.zip asset_name: testnet.zip - asset_content_type: application/zip + asset_content_type: application/zip \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 66b8ca416..11c5f7893 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,7 +38,6 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - # ============================== # Linux/Macos/Windows Build # ============================== @@ -47,6 +46,18 @@ jobs: run: make geth # ============================== + # Cross Compile for ARM + # ============================== + + - name: Build Binary for ARM + if: matrix.os == 'ubuntu-18.04' + env: + GOPATH: /home/runner/work/woodpecker/go + run: | + mkdir -p $GOPATH/src/github.com/bnb-chain/bsc/ + cp -r ./* $GOPATH/src/github.com/bnb-chain/bsc/ + cd $GOPATH/src/github.com/bnb-chain/bsc/ && make geth-linux-arm + # ============================== # Upload artifacts # ============================== @@ -71,6 +82,34 @@ jobs: name: windows path: ./build/bin/geth.exe + - name: Upload ARM-5 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm5 + path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-5 + + - name: Upload ARM-6 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm6 + path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-6 + + - name: Upload ARM-7 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm7 + path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-7 + + - name: Upload ARM-64 Build + uses: actions/upload-artifact@v2 + if: matrix.os == 'ubuntu-18.04' + with: + name: arm64 + path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm64 + release: name: Release needs: build @@ -104,6 +143,30 @@ jobs: name: windows path: ./windows + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm5 + path: ./arm5 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm6 + path: ./arm6 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm7 + path: ./arm7 + + - name: Download Artifacts + uses: actions/download-artifact@v2 + with: + name: arm64 + path: ./arm64 + - name: Download Config File run: | . ./.github/release.env @@ -111,7 +174,6 @@ jobs: echo "testnet.zip url: $TESTNET_FILE_URL" curl -L $MAINNET_FILE_URL -o ./mainnet.zip curl -L $TESTNET_FILE_URL -o ./testnet.zip - # ============================== # Create release # ============================== @@ -120,11 +182,9 @@ jobs: run: | chmod 755 ./.github/generate_change_log.sh CHANGELOG=$(./.github/generate_change_log.sh ${{ env.RELEASE_VERSION}}) - echo "CHANGELOG<> $GITHUB_ENV echo "$CHANGELOG" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV - - name: Create Release id: create_release uses: actions/create-release@latest @@ -171,6 +231,46 @@ jobs: asset_name: geth_windows.exe asset_content_type: application/octet-stream + - name: Upload Release Asset - Linux ARM 5 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm5/geth-linux-arm-5 + asset_name: geth-linux-arm-5 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 6 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm6/geth-linux-arm-6 + asset_name: geth-linux-arm-6 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 7 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm7/geth-linux-arm-7 + asset_name: geth-linux-arm-7 + asset_content_type: application/octet-stream + + - name: Upload Release Asset - Linux ARM 64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./arm64/geth-linux-arm64 + asset_name: geth-linux-arm64 + asset_content_type: application/octet-stream + - name: Upload Release Asset - MAINNET.ZIP uses: actions/upload-release-asset@v1 env: @@ -189,4 +289,4 @@ jobs: upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps asset_path: ./testnet.zip asset_name: testnet.zip - asset_content_type: application/zip + asset_content_type: application/zip \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 2d46357ca..d18f73dfb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,9 +26,9 @@ ENV BSC_HOME=/bsc ENV HOME=${BSC_HOME} ENV DATA_DIR=/data -ENV PACKAGES ca-certificates~=20220614 jq~=1.6 \ - bash~=5.1.16-r2 bind-tools~=9.16.29-r0 tini~=0.19.0 \ - grep~=3.7 curl~=7.83.1-r2 sed~=4.8-r0 curl~=7.83 +ENV PACKAGES ca-certificates~=20220614-r0 jq~=1.6 \ + bash~=5.1.16-r2 bind-tools~=9.16.33-r0 tini~=0.19.0 \ + grep~=3.7 curl=~7.83.1-r3 sed~=4.8-r0 RUN apk add --no-cache $PACKAGES \ && rm -rf /var/cache/apk/* \ diff --git a/Makefile b/Makefile index 2cfb5def8..d2e5d66fd 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,9 @@ # with Go source code. If you know what GOPATH is then you probably # don't need to bother with make. -.PHONY: geth android ios geth-cross evm all test truffle-test clean +.PHONY: geth android ios evm all test truffle-test clean .PHONY: docker +.PHONY: geth-linux-arm geth-linux-arm64 geth-linux-arm5 geth-linux-arm6 geth-linux-arm7 GOBIN = ./build/bin GO ?= latest @@ -14,6 +15,20 @@ geth: @echo "Done building." @echo "Run \"$(GOBIN)/geth\" to launch geth." +geth-linux-arm: geth-linux-arm5 geth-linux-arm6 geth-linux-arm7 geth-linux-arm64 + +geth-linux-arm5: + env GO111MODULE=on GOARCH=arm GOARM=5 GOOS=linux go build -o build/bin/geth-linux-arm-5 ./cmd/geth + +geth-linux-arm6: + env GO111MODULE=on GOARCH=arm GOARM=6 GOOS=linux go build -o build/bin/geth-linux-arm-6 ./cmd/geth + +geth-linux-arm7: + env GO111MODULE=on GOARCH=arm GOARM=7 GOOS=linux go build -o build/bin/geth-linux-arm-7 ./cmd/geth + +geth-linux-arm64: + env GO111MODULE=on GOARCH=arm64 GOOS=linux go build -o build/bin/geth-linux-arm64 ./cmd/geth + all: $(GORUN) build/ci.go install diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 992497993..6b72cc456 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -2023,7 +2023,7 @@ func TestGolangBindings(t *testing.T) { if out, err := replacer.CombinedOutput(); err != nil { t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out) } - tidier := exec.Command(gocmd, "mod", "tidy") + tidier := exec.Command(gocmd, "mod", "tidy", "-compat=1.17") tidier.Dir = pkg if out, err := tidier.CombinedOutput(); err != nil { t.Fatalf("failed to tidy Go module file: %v\n%s", err, out) diff --git a/console/console_test.go b/console/console_test.go index 71c80c20f..50bb82c53 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -289,7 +289,7 @@ func TestPrettyError(t *testing.T) { defer tester.Close(t) tester.console.Evaluate("throw 'hello'") - want := jsre.ErrorColor("hello") + "\n\tat :1:7(1)\n\n" + want := jsre.ErrorColor("hello") + "\n\tat :1:1(1)\n\n" if output := tester.output.String(); output != want { t.Fatalf("pretty error mismatch: have %s, want %s", output, want) } diff --git a/core/state_transition.go b/core/state_transition.go index 728455cbd..f0f8cde0b 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -288,15 +288,23 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { if err := st.preCheck(); err != nil { return nil, err } - msg := st.msg - sender := vm.AccountRef(msg.From()) - homestead := st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber) - istanbul := st.evm.ChainConfig().IsIstanbul(st.evm.Context.BlockNumber) - london := st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) - contractCreation := msg.To() == nil + + if st.evm.Config.Debug { + st.evm.Config.Tracer.CaptureTxStart(st.initialGas) + defer func() { + st.evm.Config.Tracer.CaptureTxEnd(st.gas) + }() + } + + var ( + msg = st.msg + sender = vm.AccountRef(msg.From()) + rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil) + contractCreation = msg.To() == nil + ) // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul) + gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul) if err != nil { return nil, err } @@ -311,7 +319,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } // Set up the initial access list. - if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil); rules.IsBerlin { + if rules.IsBerlin { st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList()) } var ( @@ -326,7 +334,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value) } - if !london { + if !rules.IsLondon { // Before EIP-3529: refunds were capped to gasUsed / 2 st.refundGas(params.RefundQuotient) } else { @@ -339,7 +347,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { st.state.AddBalance(consensus.SystemAddress, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) } else { effectiveTip := st.gasPrice - if london { + if rules.IsLondon { effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)) } st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)) diff --git a/core/vm/logger.go b/core/vm/logger.go index 3af5aec19..1067947d4 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -29,10 +29,16 @@ import ( // Note that reference types are actual VM data structures; make copies // if you need to retain them beyond the current call. type EVMLogger interface { + // Transaction level + CaptureTxStart(gasLimit uint64) + CaptureTxEnd(restGas uint64) + // Top call frame CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) - CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) + CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) + // Rest of call frames CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) CaptureExit(output []byte, gasUsed uint64, err error) + // Opcode level + CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) - CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) } diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 97673b490..e03495dd8 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -353,7 +353,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) cfg.GasLimit = gas if len(tracerCode) > 0 { - tracer, err := tracers.New(tracerCode, new(tracers.Context)) + tracer, err := tracers.New(tracerCode, new(tracers.Context), nil) if err != nil { b.Fatal(err) } @@ -752,7 +752,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.CREATE), byte(vm.POP), }, - results: []string{`"1,1,4294935775,6,12"`, `"1,1,4294935775,6,0"`}, + results: []string{`"1,1,952855,6,12"`, `"1,1,952855,6,0"`}, }, { // CREATE2 @@ -768,7 +768,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.CREATE2), byte(vm.POP), }, - results: []string{`"1,1,4294935766,6,13"`, `"1,1,4294935766,6,0"`}, + results: []string{`"1,1,952846,6,13"`, `"1,1,952846,6,0"`}, }, { // CALL @@ -781,7 +781,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.CALL), byte(vm.POP), }, - results: []string{`"1,1,4294964716,6,13"`, `"1,1,4294964716,6,0"`}, + results: []string{`"1,1,981796,6,13"`, `"1,1,981796,6,0"`}, }, { // CALLCODE @@ -794,7 +794,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.CALLCODE), byte(vm.POP), }, - results: []string{`"1,1,4294964716,6,13"`, `"1,1,4294964716,6,0"`}, + results: []string{`"1,1,981796,6,13"`, `"1,1,981796,6,0"`}, }, { // STATICCALL @@ -806,7 +806,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.STATICCALL), byte(vm.POP), }, - results: []string{`"1,1,4294964719,6,12"`, `"1,1,4294964719,6,0"`}, + results: []string{`"1,1,981799,6,12"`, `"1,1,981799,6,0"`}, }, { // DELEGATECALL @@ -818,7 +818,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.DELEGATECALL), byte(vm.POP), }, - results: []string{`"1,1,4294964719,6,12"`, `"1,1,4294964719,6,0"`}, + results: []string{`"1,1,981799,6,12"`, `"1,1,981799,6,0"`}, }, { // CALL self-destructing contract @@ -854,12 +854,13 @@ func TestRuntimeJSTracer(t *testing.T) { statedb.SetCode(common.HexToAddress("0xee"), calleeCode) statedb.SetCode(common.HexToAddress("0xff"), depressedCode) - tracer, err := tracers.New(jsTracer, new(tracers.Context)) + tracer, err := tracers.New(jsTracer, new(tracers.Context), nil) if err != nil { t.Fatal(err) } _, _, err = Call(main, nil, &Config{ - State: statedb, + GasLimit: 1000000, + State: statedb, EVMConfig: vm.Config{ Debug: true, Tracer: tracer, @@ -889,7 +890,7 @@ func TestJSTracerCreateTx(t *testing.T) { code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)} statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - tracer, err := tracers.New(jsTracer, new(tracers.Context)) + tracer, err := tracers.New(jsTracer, new(tracers.Context), nil) if err != nil { t.Fatal(err) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 9c1fdfbd5..aa186c7f7 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -20,6 +20,7 @@ import ( "bufio" "bytes" "context" + "encoding/json" "errors" "fmt" "io/ioutil" @@ -172,15 +173,15 @@ type TraceConfig struct { Tracer *string Timeout *string Reexec *uint64 + // Config specific to given tracer. Note struct logger + // config are historically embedded in main object. + TracerConfig json.RawMessage } // TraceCallConfig is the config for traceCall API. It holds one more // field to override the state for tracing. type TraceCallConfig struct { - *logger.Config - Tracer *string - Timeout *string - Reexec *uint64 + TraceConfig StateOverrides *ethapi.StateOverride } @@ -895,39 +896,38 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc // executes the given message in the provided environment. The return value will // be tracer dependent. func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { - // Assemble the structured logger or the JavaScript tracer var ( - tracer vm.EVMLogger + tracer Tracer err error + timeout = defaultTraceTimeout txContext = core.NewEVMTxContext(message) ) - switch { - case config == nil: - tracer = logger.NewStructLogger(nil) - case config.Tracer != nil: - // Define a meaningful timeout of a single transaction trace - timeout := defaultTraceTimeout - if config.Timeout != nil { - if timeout, err = time.ParseDuration(*config.Timeout); err != nil { - return nil, err - } + if config == nil { + config = &TraceConfig{} + } + // Default tracer is the struct logger + tracer = logger.NewStructLogger(config.Config) + if config.Tracer != nil { + tracer, err = New(*config.Tracer, txctx, config.TracerConfig) + if err != nil { + return nil, err } - if t, err := New(*config.Tracer, txctx); err != nil { + } + // Define a meaningful timeout of a single transaction trace + if config.Timeout != nil { + if timeout, err = time.ParseDuration(*config.Timeout); err != nil { return nil, err - } else { - deadlineCtx, cancel := context.WithTimeout(ctx, timeout) - gopool.Submit(func() { - <-deadlineCtx.Done() - if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) { - t.Stop(errors.New("execution timeout")) - } - }) - defer cancel() - tracer = t } - default: - tracer = logger.NewStructLogger(config.Config) } + deadlineCtx, cancel := context.WithTimeout(ctx, timeout) + go func() { + <-deadlineCtx.Done() + if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) { + tracer.Stop(errors.New("execution timeout")) + } + }() + defer cancel() + // Run the transaction with tracing enabled. vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) @@ -942,33 +942,10 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex // Call Prepare to clear out the statedb access list statedb.Prepare(txctx.TxHash, txctx.TxIndex) - - result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) - if err != nil { + if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())); err != nil { return nil, fmt.Errorf("tracing failed: %w", err) } - - // Depending on the tracer type, format and return the output. - switch tracer := tracer.(type) { - case *logger.StructLogger: - // If the result contains a revert reason, return it. - returnVal := fmt.Sprintf("%x", result.Return()) - if len(result.Revert()) > 0 { - returnVal = fmt.Sprintf("%x", result.Revert()) - } - return ðapi.ExecutionResult{ - Gas: result.UsedGas, - Failed: result.Failed(), - ReturnValue: returnVal, - StructLogs: ethapi.FormatLogs(tracer.StructLogs()), - }, nil - - case Tracer: - return tracer.GetResult() - - default: - panic(fmt.Sprintf("bad tracer type %T", tracer)) - } + return tracer.GetResult() } // APIs return the collection of RPC services the tracer package offers. diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 5c2975557..c71ebfa6b 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -39,6 +39,7 @@ import ( "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/tracers/logger" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/params" @@ -214,11 +215,11 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: ðapi.ExecutionResult{ + expect: &logger.ExecutionResult{ Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + StructLogs: []logger.StructLogRes{}, }, }, // Standard JSON trace upon the head, plain transfer. @@ -231,11 +232,11 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: ðapi.ExecutionResult{ + expect: &logger.ExecutionResult{ Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + StructLogs: []logger.StructLogRes{}, }, }, // Standard JSON trace upon the non-existent block, error expects @@ -260,11 +261,11 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: ðapi.ExecutionResult{ + expect: &logger.ExecutionResult{ Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + StructLogs: []logger.StructLogRes{}, }, }, // Standard JSON trace upon the pending block @@ -277,11 +278,11 @@ func TestTraceCall(t *testing.T) { }, config: nil, expectErr: nil, - expect: ðapi.ExecutionResult{ + expect: &logger.ExecutionResult{ Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + StructLogs: []logger.StructLogRes{}, }, }, } @@ -300,8 +301,12 @@ func TestTraceCall(t *testing.T) { t.Errorf("Expect no error, get %v", err) continue } - if !reflect.DeepEqual(result, testspec.expect) { - t.Errorf("Result mismatch, want %v, get %v", testspec.expect, result) + var have *logger.ExecutionResult + if err := json.Unmarshal(result.(json.RawMessage), &have); err != nil { + t.Errorf("failed to unmarshal result %v", err) + } + if !reflect.DeepEqual(have, testspec.expect) { + t.Errorf("Result mismatch, want %v, get %v", testspec.expect, have) } } } @@ -330,11 +335,15 @@ func TestTraceTransaction(t *testing.T) { if err != nil { t.Errorf("Failed to trace transaction %v", err) } - if !reflect.DeepEqual(result, ðapi.ExecutionResult{ + var have *logger.ExecutionResult + if err := json.Unmarshal(result.(json.RawMessage), &have); err != nil { + t.Errorf("failed to unmarshal result %v", err) + } + if !reflect.DeepEqual(have, &logger.ExecutionResult{ Gas: params.TxGas, Failed: false, ReturnValue: "", - StructLogs: []ethapi.StructLogRes{}, + StructLogs: []logger.StructLogRes{}, }) { t.Error("Transaction tracing result is different") } diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index cf7c1e6c0..465fe57dc 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -118,10 +118,11 @@ type callTrace struct { // callTracerTest defines a single test to check the call tracer against. type callTracerTest struct { - Genesis *core.Genesis `json:"genesis"` - Context *callContext `json:"context"` - Input string `json:"input"` - Result *callTrace `json:"result"` + Genesis *core.Genesis `json:"genesis"` + Context *callContext `json:"context"` + Input string `json:"input"` + TracerConfig json.RawMessage `json:"tracerConfig"` + Result *callTrace `json:"result"` } // Iterates over all the input-output datasets in the tracer test harness and @@ -179,7 +180,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { } _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false) ) - tracer, err := tracers.New(tracerName, new(tracers.Context)) + tracer, err := tracers.New(tracerName, new(tracers.Context), test.TracerConfig) if err != nil { t.Fatalf("failed to create call tracer: %v", err) } @@ -258,7 +259,7 @@ func BenchmarkTracers(b *testing.B) { if err := json.Unmarshal(blob, test); err != nil { b.Fatalf("failed to parse testcase: %v", err) } - benchTracer("callTracerNative", test, b) + benchTracer("callTracer", test, b) }) } } @@ -293,7 +294,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - tracer, err := tracers.New(tracerName, new(tracers.Context)) + tracer, err := tracers.New(tracerName, new(tracers.Context), nil) if err != nil { b.Fatalf("failed to create call tracer: %v", err) } @@ -359,7 +360,7 @@ func TestZeroValueToNotExitCall(t *testing.T) { } _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false) // Create the tracer, the EVM environment and run it - tracer, err := tracers.New("callTracer", nil) + tracer, err := tracers.New("callTracer", nil, nil) if err != nil { t.Fatalf("failed to create call tracer: %v", err) } diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json new file mode 100644 index 000000000..ac1fef440 --- /dev/null +++ b/eth/tracers/internal/tracetest/testdata/call_tracer/simple_onlytop.json @@ -0,0 +1,72 @@ +{ + "context": { + "difficulty": "3502894804", + "gasLimit": "4722976", + "miner": "0x1585936b53834b021f68cc13eeefdec2efc8e724", + "number": "2289806", + "timestamp": "1513601314" + }, + "genesis": { + "alloc": { + "0x0024f658a46fbb89d8ac105e98d7ac7cbbaf27c5": { + "balance": "0x0", + "code": "0x", + "nonce": "22", + "storage": {} + }, + "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe": { + "balance": "0x4d87094125a369d9bd5", + "code": "0x606060405236156100935763ffffffff60e060020a60003504166311ee8382811461009c57806313af4035146100be5780631f5e8f4c146100ee57806324daddc5146101125780634921a91a1461013b57806363e4bff414610157578063764978f91461017f578063893d20e8146101a1578063ba40aaa1146101cd578063cebc9a82146101f4578063e177246e14610216575b61009a5b5b565b005b34156100a457fe5b6100ac61023d565b60408051918252519081900360200190f35b34156100c657fe5b6100da600160a060020a0360043516610244565b604080519115158252519081900360200190f35b34156100f657fe5b6100da610307565b604080519115158252519081900360200190f35b341561011a57fe5b6100da6004351515610318565b604080519115158252519081900360200190f35b6100da6103d6565b604080519115158252519081900360200190f35b6100da600160a060020a0360043516610420565b604080519115158252519081900360200190f35b341561018757fe5b6100ac61046c565b60408051918252519081900360200190f35b34156101a957fe5b6101b1610473565b60408051600160a060020a039092168252519081900360200190f35b34156101d557fe5b6100da600435610483565b604080519115158252519081900360200190f35b34156101fc57fe5b6100ac61050d565b60408051918252519081900360200190f35b341561021e57fe5b6100da600435610514565b604080519115158252519081900360200190f35b6003545b90565b60006000610250610473565b600160a060020a031633600160a060020a03161415156102705760006000fd5b600160a060020a03831615156102865760006000fd5b50600054600160a060020a0390811690831681146102fb57604051600160a060020a0380851691908316907ffcf23a92150d56e85e3a3d33b357493246e55783095eb6a733eb8439ffc752c890600090a360008054600160a060020a031916600160a060020a03851617905560019150610300565b600091505b5b50919050565b60005460a060020a900460ff165b90565b60006000610324610473565b600160a060020a031633600160a060020a03161415156103445760006000fd5b5060005460a060020a900460ff16801515831515146102fb576000546040805160a060020a90920460ff1615158252841515602083015280517fe6cd46a119083b86efc6884b970bfa30c1708f53ba57b86716f15b2f4551a9539281900390910190a16000805460a060020a60ff02191660a060020a8515150217905560019150610300565b600091505b5b50919050565b60006103e0610307565b801561040557506103ef610473565b600160a060020a031633600160a060020a031614155b156104105760006000fd5b610419336105a0565b90505b5b90565b600061042a610307565b801561044f5750610439610473565b600160a060020a031633600160a060020a031614155b1561045a5760006000fd5b610463826105a0565b90505b5b919050565b6001545b90565b600054600160a060020a03165b90565b6000600061048f610473565b600160a060020a031633600160a060020a03161415156104af5760006000fd5b506001548281146102fb57604080518281526020810185905281517f79a3746dde45672c9e8ab3644b8bb9c399a103da2dc94b56ba09777330a83509929181900390910190a160018381559150610300565b600091505b5b50919050565b6002545b90565b60006000610520610473565b600160a060020a031633600160a060020a03161415156105405760006000fd5b506002548281146102fb57604080518281526020810185905281517ff6991a728965fedd6e927fdf16bdad42d8995970b4b31b8a2bf88767516e2494929181900390910190a1600283905560019150610300565b600091505b5b50919050565b60006000426105ad61023d565b116102fb576105c46105bd61050d565b4201610652565b6105cc61046c565b604051909150600160a060020a038416908290600081818185876187965a03f1925050501561063d57604080518281529051600160a060020a038516917f9bca65ce52fdef8a470977b51f247a2295123a4807dfa9e502edf0d30722da3b919081900360200190a260019150610300565b6102fb42610652565b5b600091505b50919050565b60038190555b505600a165627a7a72305820f3c973c8b7ed1f62000b6701bd5b708469e19d0f1d73fde378a56c07fd0b19090029", + "nonce": "1", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000001b436ba50d378d4bbc8660d312a13df6af6e89dfb", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x00000000000000000000000000000000000000000000000006f05b59d3b20000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x000000000000000000000000000000000000000000000000000000000000003c", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x000000000000000000000000000000000000000000000000000000005a37b834" + } + }, + "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb": { + "balance": "0x1780d77678137ac1b775", + "code": "0x", + "nonce": "29072", + "storage": {} + } + }, + "config": { + "byzantiumBlock": 1700000, + "chainId": 3, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d", + "eip155Block": 10, + "eip158Block": 10, + "ethash": {}, + "homesteadBlock": 0 + }, + "difficulty": "3509749784", + "extraData": "0x4554482e45544846414e532e4f52472d4641313738394444", + "gasLimit": "4727564", + "hash": "0x609948ac3bd3c00b7736b933248891d6c901ee28f066241bddb28f4e00a9f440", + "miner": "0xbbf5029fd710d227630c8b7d338051b8e76d50b3", + "mixHash": "0xb131e4507c93c7377de00e7c271bf409ec7492767142ff0f45c882f8068c2ada", + "nonce": "0x4eb12e19c16d43da", + "number": "2289805", + "stateRoot": "0xc7f10f352bff82fac3c2999d3085093d12652e19c7fd32591de49dc5d91b4f1f", + "timestamp": "1513601261", + "totalDifficulty": "7143276353481064" + }, + "input": "0xf88b8271908506fc23ac0083015f90943b873a919aa0512d5a0f09e6dcceaa4a6727fafe80a463e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c52aa0bdce0b59e8761854e857fe64015f06dd08a4fbb7624f6094893a79a72e6ad6bea01d9dde033cff7bb235a3163f348a6d7ab8d6b52bc0963a95b91612e40ca766a4", + "tracerConfig": { + "onlyTopCall": true + }, + "result": { + "from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb", + "gas": "0x10738", + "gasUsed": "0x3ef9", + "input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5", + "output": "0x0000000000000000000000000000000000000000000000000000000000000001", + "to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe", + "type": "CALL", + "value": "0x0" + } +} diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go new file mode 100644 index 000000000..20bb4866f --- /dev/null +++ b/eth/tracers/js/goja.go @@ -0,0 +1,966 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . +package js + +import ( + "encoding/json" + "errors" + "fmt" + "math/big" + "time" + + "github.com/dop251/goja" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers" + jsassets "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers" +) + +var assetTracers = make(map[string]string) + +// init retrieves the JavaScript transaction tracers included in go-ethereum. +func init() { + var err error + assetTracers, err = jsassets.Load() + if err != nil { + panic(err) + } + tracers.RegisterLookup(true, newJsTracer) +} + +// bigIntProgram is compiled once and the exported function mostly invoked to convert +// hex strings into big ints. +var bigIntProgram = goja.MustCompile("bigInt", bigIntegerJS, false) + +type toBigFn = func(vm *goja.Runtime, val string) (goja.Value, error) +type toBufFn = func(vm *goja.Runtime, val []byte) (goja.Value, error) +type fromBufFn = func(vm *goja.Runtime, buf goja.Value, allowString bool) ([]byte, error) + +func toBuf(vm *goja.Runtime, bufType goja.Value, val []byte) (goja.Value, error) { + // bufType is usually Uint8Array. This is equivalent to `new Uint8Array(val)` in JS. + res, err := vm.New(bufType, vm.ToValue(val)) + if err != nil { + return nil, err + } + return vm.ToValue(res), nil +} + +func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString bool) ([]byte, error) { + obj := buf.ToObject(vm) + switch obj.ClassName() { + case "String": + if !allowString { + break + } + return common.FromHex(obj.String()), nil + case "Array": + var b []byte + if err := vm.ExportTo(buf, &b); err != nil { + return nil, err + } + return b, nil + + case "Object": + if !obj.Get("constructor").SameAs(bufType) { + break + } + var b []byte + if err := vm.ExportTo(buf, &b); err != nil { + return nil, err + } + return b, nil + } + return nil, fmt.Errorf("invalid buffer type") +} + +// jsTracer is an implementation of the Tracer interface which evaluates +// JS functions on the relevant EVM hooks. It uses Goja as its JS engine. +type jsTracer struct { + vm *goja.Runtime + env *vm.EVM + toBig toBigFn // Converts a hex string into a JS bigint + toBuf toBufFn // Converts a []byte into a JS buffer + fromBuf fromBufFn // Converts an array, hex string or Uint8Array to a []byte + ctx map[string]goja.Value // KV-bag passed to JS in `result` + activePrecompiles []common.Address // List of active precompiles at current block + traceStep bool // True if tracer object exposes a `step()` method + traceFrame bool // True if tracer object exposes the `enter()` and `exit()` methods + gasLimit uint64 // Amount of gas bought for the whole tx + err error // Any error that should stop tracing + obj *goja.Object // Trace object + + // Methods exposed by tracer + result goja.Callable + fault goja.Callable + step goja.Callable + enter goja.Callable + exit goja.Callable + + // Underlying structs being passed into JS + log *steplog + frame *callframe + frameResult *callframeResult + + // Goja-wrapping of types prepared for JS consumption + logValue goja.Value + dbValue goja.Value + frameValue goja.Value + frameResultValue goja.Value +} + +// newJsTracer instantiates a new JS tracer instance. code is either +// the name of a built-in JS tracer or a Javascript snippet which +// evaluates to an expression returning an object with certain methods. +// The methods `result` and `fault` are required to be present. +// The methods `step`, `enter`, and `exit` are optional, but note that +// `enter` and `exit` always go together. +func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { + if c, ok := assetTracers[code]; ok { + code = c + } + vm := goja.New() + // By default field names are exported to JS as is, i.e. capitalized. + vm.SetFieldNameMapper(goja.UncapFieldNameMapper()) + t := &jsTracer{ + vm: vm, + ctx: make(map[string]goja.Value), + } + if ctx == nil { + ctx = new(tracers.Context) + } + if ctx.BlockHash != (common.Hash{}) { + t.ctx["blockHash"] = vm.ToValue(ctx.BlockHash.Bytes()) + if ctx.TxHash != (common.Hash{}) { + t.ctx["txIndex"] = vm.ToValue(ctx.TxIndex) + t.ctx["txHash"] = vm.ToValue(ctx.TxHash.Bytes()) + } + } + + t.setTypeConverters() + t.setBuiltinFunctions() + ret, err := vm.RunString("(" + code + ")") + if err != nil { + return nil, err + } + // Check tracer's interface for required and optional methods. + obj := ret.ToObject(vm) + result, ok := goja.AssertFunction(obj.Get("result")) + if !ok { + return nil, errors.New("trace object must expose a function result()") + } + fault, ok := goja.AssertFunction(obj.Get("fault")) + if !ok { + return nil, errors.New("trace object must expose a function fault()") + } + step, ok := goja.AssertFunction(obj.Get("step")) + t.traceStep = ok + enter, hasEnter := goja.AssertFunction(obj.Get("enter")) + exit, hasExit := goja.AssertFunction(obj.Get("exit")) + if hasEnter != hasExit { + return nil, errors.New("trace object must expose either both or none of enter() and exit()") + } + t.traceFrame = hasEnter + t.obj = obj + t.step = step + t.enter = enter + t.exit = exit + t.result = result + t.fault = fault + + // Pass in config + if setup, ok := goja.AssertFunction(obj.Get("setup")); ok { + cfgStr := "{}" + if cfg != nil { + cfgStr = string(cfg) + } + if _, err := setup(obj, vm.ToValue(cfgStr)); err != nil { + return nil, err + } + } + // Setup objects carrying data to JS. These are created once and re-used. + t.log = &steplog{ + vm: vm, + op: &opObj{vm: vm}, + memory: &memoryObj{vm: vm, toBig: t.toBig, toBuf: t.toBuf}, + stack: &stackObj{vm: vm, toBig: t.toBig}, + contract: &contractObj{vm: vm, toBig: t.toBig, toBuf: t.toBuf}, + } + t.frame = &callframe{vm: vm, toBig: t.toBig, toBuf: t.toBuf} + t.frameResult = &callframeResult{vm: vm, toBuf: t.toBuf} + t.frameValue = t.frame.setupObject() + t.frameResultValue = t.frameResult.setupObject() + t.logValue = t.log.setupObject() + return t, nil +} + +// CaptureTxStart implements the Tracer interface and is invoked at the beginning of +// transaction processing. +func (t *jsTracer) CaptureTxStart(gasLimit uint64) { + t.gasLimit = gasLimit +} + +// CaptureTxStart implements the Tracer interface and is invoked at the end of +// transaction processing. +func (t *jsTracer) CaptureTxEnd(restGas uint64) {} + +// CaptureStart implements the Tracer interface to initialize the tracing operation. +func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { + t.env = env + db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf} + t.dbValue = db.setupObject() + if create { + t.ctx["type"] = t.vm.ToValue("CREATE") + } else { + t.ctx["type"] = t.vm.ToValue("CALL") + } + t.ctx["from"] = t.vm.ToValue(from.Bytes()) + t.ctx["to"] = t.vm.ToValue(to.Bytes()) + t.ctx["input"] = t.vm.ToValue(input) + t.ctx["gas"] = t.vm.ToValue(gas) + t.ctx["gasPrice"] = t.vm.ToValue(env.TxContext.GasPrice) + valueBig, err := t.toBig(t.vm, value.String()) + if err != nil { + t.err = err + return + } + t.ctx["value"] = valueBig + t.ctx["block"] = t.vm.ToValue(env.Context.BlockNumber.Uint64()) + // Update list of precompiles based on current block + rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) + t.activePrecompiles = vm.ActivePrecompiles(rules) + t.ctx["intrinsicGas"] = t.vm.ToValue(t.gasLimit - gas) +} + +// CaptureState implements the Tracer interface to trace a single step of VM execution. +func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { + if !t.traceStep { + return + } + if t.err != nil { + return + } + + log := t.log + log.op.op = op + log.memory.memory = scope.Memory + log.stack.stack = scope.Stack + log.contract.contract = scope.Contract + log.pc = uint(pc) + log.gas = uint(gas) + log.cost = uint(cost) + log.depth = uint(depth) + log.err = err + if _, err := t.step(t.obj, t.logValue, t.dbValue); err != nil { + t.onError("step", err) + } +} + +// CaptureFault implements the Tracer interface to trace an execution fault +func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { + if t.err != nil { + return + } + // Other log fields have been already set as part of the last CaptureState. + t.log.err = err + if _, err := t.fault(t.obj, t.logValue, t.dbValue); err != nil { + t.onError("fault", err) + } +} + +// CaptureEnd is called after the call finishes to finalize the tracing. +func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, duration time.Duration, err error) { + t.ctx["output"] = t.vm.ToValue(output) + t.ctx["time"] = t.vm.ToValue(duration.String()) + t.ctx["gasUsed"] = t.vm.ToValue(gasUsed) + if err != nil { + t.ctx["error"] = t.vm.ToValue(err.Error()) + } +} + +// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). +func (t *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if !t.traceFrame { + return + } + if t.err != nil { + return + } + + t.frame.typ = typ.String() + t.frame.from = from + t.frame.to = to + t.frame.input = common.CopyBytes(input) + t.frame.gas = uint(gas) + t.frame.value = nil + if value != nil { + t.frame.value = new(big.Int).SetBytes(value.Bytes()) + } + + if _, err := t.enter(t.obj, t.frameValue); err != nil { + t.onError("enter", err) + } +} + +// CaptureExit is called when EVM exits a scope, even if the scope didn't +// execute any code. +func (t *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error) { + if !t.traceFrame { + return + } + + t.frameResult.gasUsed = uint(gasUsed) + t.frameResult.output = common.CopyBytes(output) + t.frameResult.err = err + + if _, err := t.exit(t.obj, t.frameResultValue); err != nil { + t.onError("exit", err) + } +} + +// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error +func (t *jsTracer) GetResult() (json.RawMessage, error) { + ctx := t.vm.ToValue(t.ctx) + res, err := t.result(t.obj, ctx, t.dbValue) + if err != nil { + return nil, wrapError("result", err) + } + encoded, err := json.Marshal(res) + if err != nil { + return nil, err + } + return json.RawMessage(encoded), t.err +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (t *jsTracer) Stop(err error) { + t.vm.Interrupt(err) +} + +// onError is called anytime the running JS code is interrupted +// and returns an error. It in turn pings the EVM to cancel its +// execution. +func (t *jsTracer) onError(context string, err error) { + t.err = wrapError(context, err) + // `env` is set on CaptureStart which comes before any JS execution. + // So it should be non-nil. + t.env.Cancel() +} + +func wrapError(context string, err error) error { + return fmt.Errorf("%v in server-side tracer function '%v'", err, context) +} + +// setBuiltinFunctions injects Go functions which are available to tracers into the environment. +// It depends on type converters having been set up. +func (t *jsTracer) setBuiltinFunctions() { + vm := t.vm + // TODO: load console from goja-nodejs + vm.Set("toHex", func(v goja.Value) string { + b, err := t.fromBuf(vm, v, false) + if err != nil { + vm.Interrupt(err) + return "" + } + return hexutil.Encode(b) + }) + vm.Set("toWord", func(v goja.Value) goja.Value { + // TODO: add test with []byte len < 32 or > 32 + b, err := t.fromBuf(vm, v, true) + if err != nil { + vm.Interrupt(err) + return nil + } + b = common.BytesToHash(b).Bytes() + res, err := t.toBuf(vm, b) + if err != nil { + vm.Interrupt(err) + return nil + } + return res + }) + vm.Set("toAddress", func(v goja.Value) goja.Value { + a, err := t.fromBuf(vm, v, true) + if err != nil { + vm.Interrupt(err) + return nil + } + a = common.BytesToAddress(a).Bytes() + res, err := t.toBuf(vm, a) + if err != nil { + vm.Interrupt(err) + return nil + } + return res + }) + vm.Set("toContract", func(from goja.Value, nonce uint) goja.Value { + a, err := t.fromBuf(vm, from, true) + if err != nil { + vm.Interrupt(err) + return nil + } + addr := common.BytesToAddress(a) + b := crypto.CreateAddress(addr, uint64(nonce)).Bytes() + res, err := t.toBuf(vm, b) + if err != nil { + vm.Interrupt(err) + return nil + } + return res + }) + vm.Set("toContract2", func(from goja.Value, salt string, initcode goja.Value) goja.Value { + a, err := t.fromBuf(vm, from, true) + if err != nil { + vm.Interrupt(err) + return nil + } + addr := common.BytesToAddress(a) + code, err := t.fromBuf(vm, initcode, true) + if err != nil { + vm.Interrupt(err) + return nil + } + code = common.CopyBytes(code) + codeHash := crypto.Keccak256(code) + b := crypto.CreateAddress2(addr, common.HexToHash(salt), codeHash).Bytes() + res, err := t.toBuf(vm, b) + if err != nil { + vm.Interrupt(err) + return nil + } + return res + }) + vm.Set("isPrecompiled", func(v goja.Value) bool { + a, err := t.fromBuf(vm, v, true) + if err != nil { + vm.Interrupt(err) + return false + } + addr := common.BytesToAddress(a) + for _, p := range t.activePrecompiles { + if p == addr { + return true + } + } + return false + }) + vm.Set("slice", func(slice goja.Value, start, end int) goja.Value { + b, err := t.fromBuf(vm, slice, false) + if err != nil { + vm.Interrupt(err) + return nil + } + if start < 0 || start > end || end > len(b) { + vm.Interrupt(fmt.Sprintf("Tracer accessed out of bound memory: available %d, offset %d, size %d", len(b), start, end-start)) + return nil + } + res, err := t.toBuf(vm, b[start:end]) + if err != nil { + vm.Interrupt(err) + return nil + } + return res + }) +} + +// setTypeConverters sets up utilities for converting Go types into those +// suitable for JS consumption. +func (t *jsTracer) setTypeConverters() error { + // Inject bigint logic. + // TODO: To be replaced after goja adds support for native JS bigint. + toBigCode, err := t.vm.RunProgram(bigIntProgram) + if err != nil { + return err + } + // Used to create JS bigint objects from go. + toBigFn, ok := goja.AssertFunction(toBigCode) + if !ok { + return errors.New("failed to bind bigInt func") + } + toBigWrapper := func(vm *goja.Runtime, val string) (goja.Value, error) { + return toBigFn(goja.Undefined(), vm.ToValue(val)) + } + t.toBig = toBigWrapper + // NOTE: We need this workaround to create JS buffers because + // goja doesn't at the moment expose constructors for typed arrays. + // + // Cache uint8ArrayType once to be used every time for less overhead. + uint8ArrayType := t.vm.Get("Uint8Array") + toBufWrapper := func(vm *goja.Runtime, val []byte) (goja.Value, error) { + return toBuf(vm, uint8ArrayType, val) + } + t.toBuf = toBufWrapper + fromBufWrapper := func(vm *goja.Runtime, buf goja.Value, allowString bool) ([]byte, error) { + return fromBuf(vm, uint8ArrayType, buf, allowString) + } + t.fromBuf = fromBufWrapper + return nil +} + +type opObj struct { + vm *goja.Runtime + op vm.OpCode +} + +func (o *opObj) ToNumber() int { + return int(o.op) +} + +func (o *opObj) ToString() string { + return o.op.String() +} + +func (o *opObj) IsPush() bool { + return o.op.IsPush() +} + +func (o *opObj) setupObject() *goja.Object { + obj := o.vm.NewObject() + obj.Set("toNumber", o.vm.ToValue(o.ToNumber)) + obj.Set("toString", o.vm.ToValue(o.ToString)) + obj.Set("isPush", o.vm.ToValue(o.IsPush)) + return obj +} + +type memoryObj struct { + memory *vm.Memory + vm *goja.Runtime + toBig toBigFn + toBuf toBufFn +} + +func (mo *memoryObj) Slice(begin, end int64) goja.Value { + b, err := mo.slice(begin, end) + if err != nil { + mo.vm.Interrupt(err) + return nil + } + res, err := mo.toBuf(mo.vm, b) + if err != nil { + mo.vm.Interrupt(err) + return nil + } + return res +} + +// slice returns the requested range of memory as a byte slice. +func (mo *memoryObj) slice(begin, end int64) ([]byte, error) { + if end == begin { + return []byte{}, nil + } + if end < begin || begin < 0 { + return nil, fmt.Errorf("Tracer accessed out of bound memory: offset %d, end %d", begin, end) + } + if mo.memory.Len() < int(end) { + return nil, fmt.Errorf("Tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), begin, end-begin) + } + return mo.memory.GetCopy(begin, end-begin), nil +} + +func (mo *memoryObj) GetUint(addr int64) goja.Value { + value, err := mo.getUint(addr) + if err != nil { + mo.vm.Interrupt(err) + return nil + } + res, err := mo.toBig(mo.vm, value.String()) + if err != nil { + mo.vm.Interrupt(err) + return nil + } + return res +} + +// getUint returns the 32 bytes at the specified address interpreted as a uint. +func (mo *memoryObj) getUint(addr int64) (*big.Int, error) { + if mo.memory.Len() < int(addr)+32 || addr < 0 { + return nil, fmt.Errorf("Tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), addr, 32) + } + return new(big.Int).SetBytes(mo.memory.GetPtr(addr, 32)), nil +} + +func (mo *memoryObj) Length() int { + return mo.memory.Len() +} + +func (m *memoryObj) setupObject() *goja.Object { + o := m.vm.NewObject() + o.Set("slice", m.vm.ToValue(m.Slice)) + o.Set("getUint", m.vm.ToValue(m.GetUint)) + o.Set("length", m.vm.ToValue(m.Length)) + return o +} + +type stackObj struct { + stack *vm.Stack + vm *goja.Runtime + toBig toBigFn +} + +func (s *stackObj) Peek(idx int) goja.Value { + value, err := s.peek(idx) + if err != nil { + s.vm.Interrupt(err) + return nil + } + res, err := s.toBig(s.vm, value.String()) + if err != nil { + s.vm.Interrupt(err) + return nil + } + return res +} + +// peek returns the nth-from-the-top element of the stack. +func (s *stackObj) peek(idx int) (*big.Int, error) { + if len(s.stack.Data()) <= idx || idx < 0 { + return nil, fmt.Errorf("Tracer accessed out of bound stack: size %d, index %d", len(s.stack.Data()), idx) + } + return s.stack.Back(idx).ToBig(), nil +} + +func (s *stackObj) Length() int { + return len(s.stack.Data()) +} + +func (s *stackObj) setupObject() *goja.Object { + o := s.vm.NewObject() + o.Set("peek", s.vm.ToValue(s.Peek)) + o.Set("length", s.vm.ToValue(s.Length)) + return o +} + +type dbObj struct { + db vm.StateDB + vm *goja.Runtime + toBig toBigFn + toBuf toBufFn + fromBuf fromBufFn +} + +func (do *dbObj) GetBalance(addrSlice goja.Value) goja.Value { + a, err := do.fromBuf(do.vm, addrSlice, false) + if err != nil { + do.vm.Interrupt(err) + return nil + } + addr := common.BytesToAddress(a) + value := do.db.GetBalance(addr) + res, err := do.toBig(do.vm, value.String()) + if err != nil { + do.vm.Interrupt(err) + return nil + } + return res +} + +func (do *dbObj) GetNonce(addrSlice goja.Value) uint64 { + a, err := do.fromBuf(do.vm, addrSlice, false) + if err != nil { + do.vm.Interrupt(err) + return 0 + } + addr := common.BytesToAddress(a) + return do.db.GetNonce(addr) +} + +func (do *dbObj) GetCode(addrSlice goja.Value) goja.Value { + a, err := do.fromBuf(do.vm, addrSlice, false) + if err != nil { + do.vm.Interrupt(err) + return nil + } + addr := common.BytesToAddress(a) + code := do.db.GetCode(addr) + res, err := do.toBuf(do.vm, code) + if err != nil { + do.vm.Interrupt(err) + return nil + } + return res +} + +func (do *dbObj) GetState(addrSlice goja.Value, hashSlice goja.Value) goja.Value { + a, err := do.fromBuf(do.vm, addrSlice, false) + if err != nil { + do.vm.Interrupt(err) + return nil + } + addr := common.BytesToAddress(a) + h, err := do.fromBuf(do.vm, hashSlice, false) + if err != nil { + do.vm.Interrupt(err) + return nil + } + hash := common.BytesToHash(h) + state := do.db.GetState(addr, hash).Bytes() + res, err := do.toBuf(do.vm, state) + if err != nil { + do.vm.Interrupt(err) + return nil + } + return res +} + +func (do *dbObj) Exists(addrSlice goja.Value) bool { + a, err := do.fromBuf(do.vm, addrSlice, false) + if err != nil { + do.vm.Interrupt(err) + return false + } + addr := common.BytesToAddress(a) + return do.db.Exist(addr) +} + +func (do *dbObj) setupObject() *goja.Object { + o := do.vm.NewObject() + o.Set("getBalance", do.vm.ToValue(do.GetBalance)) + o.Set("getNonce", do.vm.ToValue(do.GetNonce)) + o.Set("getCode", do.vm.ToValue(do.GetCode)) + o.Set("getState", do.vm.ToValue(do.GetState)) + o.Set("exists", do.vm.ToValue(do.Exists)) + return o +} + +type contractObj struct { + contract *vm.Contract + vm *goja.Runtime + toBig toBigFn + toBuf toBufFn +} + +func (co *contractObj) GetCaller() goja.Value { + caller := co.contract.Caller().Bytes() + res, err := co.toBuf(co.vm, caller) + if err != nil { + co.vm.Interrupt(err) + return nil + } + return res +} + +func (co *contractObj) GetAddress() goja.Value { + addr := co.contract.Address().Bytes() + res, err := co.toBuf(co.vm, addr) + if err != nil { + co.vm.Interrupt(err) + return nil + } + return res +} + +func (co *contractObj) GetValue() goja.Value { + value := co.contract.Value() + res, err := co.toBig(co.vm, value.String()) + if err != nil { + co.vm.Interrupt(err) + return nil + } + return res +} + +func (co *contractObj) GetInput() goja.Value { + input := co.contract.Input + res, err := co.toBuf(co.vm, input) + if err != nil { + co.vm.Interrupt(err) + return nil + } + return res +} + +func (c *contractObj) setupObject() *goja.Object { + o := c.vm.NewObject() + o.Set("getCaller", c.vm.ToValue(c.GetCaller)) + o.Set("getAddress", c.vm.ToValue(c.GetAddress)) + o.Set("getValue", c.vm.ToValue(c.GetValue)) + o.Set("getInput", c.vm.ToValue(c.GetInput)) + return o +} + +type callframe struct { + vm *goja.Runtime + toBig toBigFn + toBuf toBufFn + + typ string + from common.Address + to common.Address + input []byte + gas uint + value *big.Int +} + +func (f *callframe) GetType() string { + return f.typ +} + +func (f *callframe) GetFrom() goja.Value { + from := f.from.Bytes() + res, err := f.toBuf(f.vm, from) + if err != nil { + f.vm.Interrupt(err) + return nil + } + return res +} + +func (f *callframe) GetTo() goja.Value { + to := f.to.Bytes() + res, err := f.toBuf(f.vm, to) + if err != nil { + f.vm.Interrupt(err) + return nil + } + return res +} + +func (f *callframe) GetInput() goja.Value { + input := f.input + res, err := f.toBuf(f.vm, input) + if err != nil { + f.vm.Interrupt(err) + return nil + } + return res +} + +func (f *callframe) GetGas() uint { + return f.gas +} + +func (f *callframe) GetValue() goja.Value { + if f.value == nil { + return goja.Undefined() + } + res, err := f.toBig(f.vm, f.value.String()) + if err != nil { + f.vm.Interrupt(err) + return nil + } + return res +} + +func (f *callframe) setupObject() *goja.Object { + o := f.vm.NewObject() + o.Set("getType", f.vm.ToValue(f.GetType)) + o.Set("getFrom", f.vm.ToValue(f.GetFrom)) + o.Set("getTo", f.vm.ToValue(f.GetTo)) + o.Set("getInput", f.vm.ToValue(f.GetInput)) + o.Set("getGas", f.vm.ToValue(f.GetGas)) + o.Set("getValue", f.vm.ToValue(f.GetValue)) + return o +} + +type callframeResult struct { + vm *goja.Runtime + toBuf toBufFn + + gasUsed uint + output []byte + err error +} + +func (r *callframeResult) GetGasUsed() uint { + return r.gasUsed +} + +func (r *callframeResult) GetOutput() goja.Value { + res, err := r.toBuf(r.vm, r.output) + if err != nil { + r.vm.Interrupt(err) + return nil + } + return res +} + +func (r *callframeResult) GetError() goja.Value { + if r.err != nil { + return r.vm.ToValue(r.err.Error()) + } + return goja.Undefined() + +} + +func (r *callframeResult) setupObject() *goja.Object { + o := r.vm.NewObject() + o.Set("getGasUsed", r.vm.ToValue(r.GetGasUsed)) + o.Set("getOutput", r.vm.ToValue(r.GetOutput)) + o.Set("getError", r.vm.ToValue(r.GetError)) + return o +} + +type steplog struct { + vm *goja.Runtime + + op *opObj + memory *memoryObj + stack *stackObj + contract *contractObj + + pc uint + gas uint + cost uint + depth uint + refund uint + err error +} + +func (l *steplog) GetPC() uint { + return l.pc +} + +func (l *steplog) GetGas() uint { + return l.gas +} + +func (l *steplog) GetCost() uint { + return l.cost +} + +func (l *steplog) GetDepth() uint { + return l.depth +} + +func (l *steplog) GetRefund() uint { + return l.refund +} + +func (l *steplog) GetError() goja.Value { + if l.err != nil { + return l.vm.ToValue(l.err.Error()) + } + return goja.Undefined() +} + +func (l *steplog) setupObject() *goja.Object { + o := l.vm.NewObject() + // Setup basic fields. + o.Set("getPC", l.vm.ToValue(l.GetPC)) + o.Set("getGas", l.vm.ToValue(l.GetGas)) + o.Set("getCost", l.vm.ToValue(l.GetCost)) + o.Set("getDepth", l.vm.ToValue(l.GetDepth)) + o.Set("getRefund", l.vm.ToValue(l.GetRefund)) + o.Set("getError", l.vm.ToValue(l.GetError)) + // Setup nested objects. + o.Set("op", l.op.setupObject()) + o.Set("stack", l.stack.setupObject()) + o.Set("memory", l.memory.setupObject()) + o.Set("contract", l.contract.setupObject()) + return o +} diff --git a/eth/tracers/js/internal/tracers/tracers.go b/eth/tracers/js/internal/tracers/tracers.go index 2e40975bb..bce8488cf 100644 --- a/eth/tracers/js/internal/tracers/tracers.go +++ b/eth/tracers/js/internal/tracers/tracers.go @@ -19,3 +19,44 @@ // Package tracers contains the actual JavaScript tracer assets. package tracers + +import ( + "embed" + "io/fs" + "strings" + "unicode" +) + +//go:embed *.js +var files embed.FS + +// Load reads the built-in JS tracer files embedded in the binary and +// returns a mapping of tracer name to source. +func Load() (map[string]string, error) { + var assetTracers = make(map[string]string) + err := fs.WalkDir(files, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + b, err := fs.ReadFile(files, path) + if err != nil { + return err + } + name := camel(strings.TrimSuffix(path, ".js")) + assetTracers[name] = string(b) + return nil + }) + return assetTracers, err +} + +// camel converts a snake cased input string into a camel cased output. +func camel(str string) string { + pieces := strings.Split(str, "_") + for i := 1; i < len(pieces); i++ { + pieces[i] = string(unicode.ToUpper(rune(pieces[i][0]))) + pieces[i][1:] + } + return strings.Join(pieces, "") +} diff --git a/eth/tracers/js/tracer.go b/eth/tracers/js/tracer.go deleted file mode 100644 index 30c5c2cf1..000000000 --- a/eth/tracers/js/tracer.go +++ /dev/null @@ -1,880 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// package js is a collection of tracers written in javascript. -package js - -import ( - "encoding/json" - "errors" - "fmt" - "math/big" - "strings" - "sync/atomic" - "time" - "unicode" - "unsafe" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/crypto" - tracers2 "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers" - "github.com/ethereum/go-ethereum/log" - "gopkg.in/olebedev/go-duktape.v3" -) - -// camel converts a snake cased input string into a camel cased output. -func camel(str string) string { - pieces := strings.Split(str, "_") - for i := 1; i < len(pieces); i++ { - pieces[i] = string(unicode.ToUpper(rune(pieces[i][0]))) + pieces[i][1:] - } - return strings.Join(pieces, "") -} - -var assetTracers = make(map[string]string) - -// init retrieves the JavaScript transaction tracers included in go-ethereum. -func init() { - for _, file := range tracers.AssetNames() { - name := camel(strings.TrimSuffix(file, ".js")) - assetTracers[name] = string(tracers.MustAsset(file)) - } - tracers2.RegisterLookup(true, newJsTracer) -} - -// makeSlice convert an unsafe memory pointer with the given type into a Go byte -// slice. -// -// Note, the returned slice uses the same memory area as the input arguments. -// If those are duktape stack items, popping them off **will** make the slice -// contents change. -func makeSlice(ptr unsafe.Pointer, size uint) []byte { - var sl = struct { - addr uintptr - len int - cap int - }{uintptr(ptr), int(size), int(size)} - - return *(*[]byte)(unsafe.Pointer(&sl)) -} - -// popSlice pops a buffer off the JavaScript stack and returns it as a slice. -func popSlice(ctx *duktape.Context) []byte { - blob := common.CopyBytes(makeSlice(ctx.GetBuffer(-1))) - ctx.Pop() - return blob -} - -// pushBigInt create a JavaScript BigInteger in the VM. -func pushBigInt(n *big.Int, ctx *duktape.Context) { - ctx.GetGlobalString("bigInt") - ctx.PushString(n.String()) - ctx.Call(1) -} - -// opWrapper provides a JavaScript wrapper around OpCode. -type opWrapper struct { - op vm.OpCode -} - -// pushObject assembles a JSVM object wrapping a swappable opcode and pushes it -// onto the VM stack. -func (ow *opWrapper) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(int(ow.op)); return 1 }) - vm.PutPropString(obj, "toNumber") - - vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushString(ow.op.String()); return 1 }) - vm.PutPropString(obj, "toString") - - vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushBoolean(ow.op.IsPush()); return 1 }) - vm.PutPropString(obj, "isPush") -} - -// memoryWrapper provides a JavaScript wrapper around vm.Memory. -type memoryWrapper struct { - memory *vm.Memory -} - -// slice returns the requested range of memory as a byte slice. -func (mw *memoryWrapper) slice(begin, end int64) []byte { - if end == begin { - return []byte{} - } - if end < begin || begin < 0 { - // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go - // runtime goes belly up https://github.com/golang/go/issues/15639. - log.Warn("Tracer accessed out of bound memory", "offset", begin, "end", end) - return nil - } - if mw.memory.Len() < int(end) { - // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go - // runtime goes belly up https://github.com/golang/go/issues/15639. - log.Warn("Tracer accessed out of bound memory", "available", mw.memory.Len(), "offset", begin, "size", end-begin) - return nil - } - return mw.memory.GetCopy(begin, end-begin) -} - -// getUint returns the 32 bytes at the specified address interpreted as a uint. -func (mw *memoryWrapper) getUint(addr int64) *big.Int { - if mw.memory.Len() < int(addr)+32 || addr < 0 { - // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go - // runtime goes belly up https://github.com/golang/go/issues/15639. - log.Warn("Tracer accessed out of bound memory", "available", mw.memory.Len(), "offset", addr, "size", 32) - return new(big.Int) - } - return new(big.Int).SetBytes(mw.memory.GetPtr(addr, 32)) -} - -// pushObject assembles a JSVM object wrapping a swappable memory and pushes it -// onto the VM stack. -func (mw *memoryWrapper) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - // Generate the `slice` method which takes two ints and returns a buffer - vm.PushGoFunction(func(ctx *duktape.Context) int { - blob := mw.slice(int64(ctx.GetInt(-2)), int64(ctx.GetInt(-1))) - ctx.Pop2() - - ptr := ctx.PushFixedBuffer(len(blob)) - copy(makeSlice(ptr, uint(len(blob))), blob) - return 1 - }) - vm.PutPropString(obj, "slice") - - // Generate the `getUint` method which takes an int and returns a bigint - vm.PushGoFunction(func(ctx *duktape.Context) int { - offset := int64(ctx.GetInt(-1)) - ctx.Pop() - - pushBigInt(mw.getUint(offset), ctx) - return 1 - }) - vm.PutPropString(obj, "getUint") -} - -// stackWrapper provides a JavaScript wrapper around vm.Stack. -type stackWrapper struct { - stack *vm.Stack -} - -// peek returns the nth-from-the-top element of the stack. -func (sw *stackWrapper) peek(idx int) *big.Int { - if len(sw.stack.Data()) <= idx || idx < 0 { - // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go - // runtime goes belly up https://github.com/golang/go/issues/15639. - log.Warn("Tracer accessed out of bound stack", "size", len(sw.stack.Data()), "index", idx) - return new(big.Int) - } - return sw.stack.Back(idx).ToBig() -} - -// pushObject assembles a JSVM object wrapping a swappable stack and pushes it -// onto the VM stack. -func (sw *stackWrapper) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushInt(len(sw.stack.Data())); return 1 }) - vm.PutPropString(obj, "length") - - // Generate the `peek` method which takes an int and returns a bigint - vm.PushGoFunction(func(ctx *duktape.Context) int { - offset := ctx.GetInt(-1) - ctx.Pop() - - pushBigInt(sw.peek(offset), ctx) - return 1 - }) - vm.PutPropString(obj, "peek") -} - -// dbWrapper provides a JavaScript wrapper around vm.Database. -type dbWrapper struct { - db vm.StateDB -} - -// pushObject assembles a JSVM object wrapping a swappable database and pushes it -// onto the VM stack. -func (dw *dbWrapper) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - // Push the wrapper for statedb.GetBalance - vm.PushGoFunction(func(ctx *duktape.Context) int { - pushBigInt(dw.db.GetBalance(common.BytesToAddress(popSlice(ctx))), ctx) - return 1 - }) - vm.PutPropString(obj, "getBalance") - - // Push the wrapper for statedb.GetNonce - vm.PushGoFunction(func(ctx *duktape.Context) int { - ctx.PushInt(int(dw.db.GetNonce(common.BytesToAddress(popSlice(ctx))))) - return 1 - }) - vm.PutPropString(obj, "getNonce") - - // Push the wrapper for statedb.GetCode - vm.PushGoFunction(func(ctx *duktape.Context) int { - code := dw.db.GetCode(common.BytesToAddress(popSlice(ctx))) - - ptr := ctx.PushFixedBuffer(len(code)) - copy(makeSlice(ptr, uint(len(code))), code) - return 1 - }) - vm.PutPropString(obj, "getCode") - - // Push the wrapper for statedb.GetState - vm.PushGoFunction(func(ctx *duktape.Context) int { - hash := popSlice(ctx) - addr := popSlice(ctx) - - state := dw.db.GetState(common.BytesToAddress(addr), common.BytesToHash(hash)) - - ptr := ctx.PushFixedBuffer(len(state)) - copy(makeSlice(ptr, uint(len(state))), state[:]) - return 1 - }) - vm.PutPropString(obj, "getState") - - // Push the wrapper for statedb.Exists - vm.PushGoFunction(func(ctx *duktape.Context) int { - ctx.PushBoolean(dw.db.Exist(common.BytesToAddress(popSlice(ctx)))) - return 1 - }) - vm.PutPropString(obj, "exists") -} - -// contractWrapper provides a JavaScript wrapper around vm.Contract -type contractWrapper struct { - contract *vm.Contract -} - -// pushObject assembles a JSVM object wrapping a swappable contract and pushes it -// onto the VM stack. -func (cw *contractWrapper) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - // Push the wrapper for contract.Caller - vm.PushGoFunction(func(ctx *duktape.Context) int { - ptr := ctx.PushFixedBuffer(20) - copy(makeSlice(ptr, 20), cw.contract.Caller().Bytes()) - return 1 - }) - vm.PutPropString(obj, "getCaller") - - // Push the wrapper for contract.Address - vm.PushGoFunction(func(ctx *duktape.Context) int { - ptr := ctx.PushFixedBuffer(20) - copy(makeSlice(ptr, 20), cw.contract.Address().Bytes()) - return 1 - }) - vm.PutPropString(obj, "getAddress") - - // Push the wrapper for contract.Value - vm.PushGoFunction(func(ctx *duktape.Context) int { - pushBigInt(cw.contract.Value(), ctx) - return 1 - }) - vm.PutPropString(obj, "getValue") - - // Push the wrapper for contract.Input - vm.PushGoFunction(func(ctx *duktape.Context) int { - blob := cw.contract.Input - - ptr := ctx.PushFixedBuffer(len(blob)) - copy(makeSlice(ptr, uint(len(blob))), blob) - return 1 - }) - vm.PutPropString(obj, "getInput") -} - -type frame struct { - typ *string - from *common.Address - to *common.Address - input []byte - gas *uint - value *big.Int -} - -func newFrame() *frame { - return &frame{ - typ: new(string), - from: new(common.Address), - to: new(common.Address), - gas: new(uint), - } -} - -func (f *frame) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.typ); return 1 }) - vm.PutPropString(obj, "getType") - - vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.from); return 1 }) - vm.PutPropString(obj, "getFrom") - - vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.to); return 1 }) - vm.PutPropString(obj, "getTo") - - vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, f.input); return 1 }) - vm.PutPropString(obj, "getInput") - - vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *f.gas); return 1 }) - vm.PutPropString(obj, "getGas") - - vm.PushGoFunction(func(ctx *duktape.Context) int { - if f.value != nil { - pushValue(ctx, f.value) - } else { - ctx.PushUndefined() - } - return 1 - }) - vm.PutPropString(obj, "getValue") -} - -type frameResult struct { - gasUsed *uint - output []byte - errorValue *string -} - -func newFrameResult() *frameResult { - return &frameResult{ - gasUsed: new(uint), - } -} - -func (r *frameResult) pushObject(vm *duktape.Context) { - obj := vm.PushObject() - - vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, *r.gasUsed); return 1 }) - vm.PutPropString(obj, "getGasUsed") - - vm.PushGoFunction(func(ctx *duktape.Context) int { pushValue(ctx, r.output); return 1 }) - vm.PutPropString(obj, "getOutput") - - vm.PushGoFunction(func(ctx *duktape.Context) int { - if r.errorValue != nil { - pushValue(ctx, *r.errorValue) - } else { - ctx.PushUndefined() - } - return 1 - }) - vm.PutPropString(obj, "getError") -} - -// jsTracer provides an implementation of Tracer that evaluates a Javascript -// function for each VM execution step. -type jsTracer struct { - vm *duktape.Context // Javascript VM instance - env *vm.EVM // EVM instance executing the code being traced - - tracerObject int // Stack index of the tracer JavaScript object - stateObject int // Stack index of the global state to pull arguments from - - opWrapper *opWrapper // Wrapper around the VM opcode - stackWrapper *stackWrapper // Wrapper around the VM stack - memoryWrapper *memoryWrapper // Wrapper around the VM memory - contractWrapper *contractWrapper // Wrapper around the contract object - dbWrapper *dbWrapper // Wrapper around the VM environment - - pcValue *uint // Swappable pc value wrapped by a log accessor - gasValue *uint // Swappable gas value wrapped by a log accessor - costValue *uint // Swappable cost value wrapped by a log accessor - depthValue *uint // Swappable depth value wrapped by a log accessor - errorValue *string // Swappable error value wrapped by a log accessor - refundValue *uint // Swappable refund value wrapped by a log accessor - - frame *frame // Represents entry into call frame. Fields are swappable - frameResult *frameResult // Represents exit from a call frame. Fields are swappable - - ctx map[string]interface{} // Transaction context gathered throughout execution - err error // Error, if one has occurred - - interrupt uint32 // Atomic flag to signal execution interruption - reason error // Textual reason for the interruption - - activePrecompiles []common.Address // Updated on CaptureStart based on given rules - traceSteps bool // When true, will invoke step() on each opcode - traceCallFrames bool // When true, will invoke enter() and exit() js funcs -} - -// New instantiates a new tracer instance. code specifies a Javascript snippet, -// which must evaluate to an expression returning an object with 'step', 'fault' -// and 'result' functions. -func newJsTracer(code string, ctx *tracers2.Context) (tracers2.Tracer, error) { - if c, ok := assetTracers[code]; ok { - code = c - } - if ctx == nil { - ctx = new(tracers2.Context) - } - tracer := &jsTracer{ - vm: duktape.New(), - ctx: make(map[string]interface{}), - opWrapper: new(opWrapper), - stackWrapper: new(stackWrapper), - memoryWrapper: new(memoryWrapper), - contractWrapper: new(contractWrapper), - dbWrapper: new(dbWrapper), - pcValue: new(uint), - gasValue: new(uint), - costValue: new(uint), - depthValue: new(uint), - refundValue: new(uint), - frame: newFrame(), - frameResult: newFrameResult(), - } - if ctx.BlockHash != (common.Hash{}) { - tracer.ctx["blockHash"] = ctx.BlockHash - - if ctx.TxHash != (common.Hash{}) { - tracer.ctx["txIndex"] = ctx.TxIndex - tracer.ctx["txHash"] = ctx.TxHash - } - } - // Set up builtins for this environment - tracer.vm.PushGlobalGoFunction("toHex", func(ctx *duktape.Context) int { - ctx.PushString(hexutil.Encode(popSlice(ctx))) - return 1 - }) - tracer.vm.PushGlobalGoFunction("toWord", func(ctx *duktape.Context) int { - var word common.Hash - if ptr, size := ctx.GetBuffer(-1); ptr != nil { - word = common.BytesToHash(makeSlice(ptr, size)) - } else { - word = common.HexToHash(ctx.GetString(-1)) - } - ctx.Pop() - copy(makeSlice(ctx.PushFixedBuffer(32), 32), word[:]) - return 1 - }) - tracer.vm.PushGlobalGoFunction("toAddress", func(ctx *duktape.Context) int { - var addr common.Address - if ptr, size := ctx.GetBuffer(-1); ptr != nil { - addr = common.BytesToAddress(makeSlice(ptr, size)) - } else { - addr = common.HexToAddress(ctx.GetString(-1)) - } - ctx.Pop() - copy(makeSlice(ctx.PushFixedBuffer(20), 20), addr[:]) - return 1 - }) - tracer.vm.PushGlobalGoFunction("toContract", func(ctx *duktape.Context) int { - var from common.Address - if ptr, size := ctx.GetBuffer(-2); ptr != nil { - from = common.BytesToAddress(makeSlice(ptr, size)) - } else { - from = common.HexToAddress(ctx.GetString(-2)) - } - nonce := uint64(ctx.GetInt(-1)) - ctx.Pop2() - - contract := crypto.CreateAddress(from, nonce) - copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:]) - return 1 - }) - tracer.vm.PushGlobalGoFunction("toContract2", func(ctx *duktape.Context) int { - var from common.Address - if ptr, size := ctx.GetBuffer(-3); ptr != nil { - from = common.BytesToAddress(makeSlice(ptr, size)) - } else { - from = common.HexToAddress(ctx.GetString(-3)) - } - // Retrieve salt hex string from js stack - salt := common.HexToHash(ctx.GetString(-2)) - // Retrieve code slice from js stack - var code []byte - if ptr, size := ctx.GetBuffer(-1); ptr != nil { - code = common.CopyBytes(makeSlice(ptr, size)) - } else { - code = common.FromHex(ctx.GetString(-1)) - } - codeHash := crypto.Keccak256(code) - ctx.Pop3() - contract := crypto.CreateAddress2(from, salt, codeHash) - copy(makeSlice(ctx.PushFixedBuffer(20), 20), contract[:]) - return 1 - }) - tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int { - addr := common.BytesToAddress(popSlice(ctx)) - for _, p := range tracer.activePrecompiles { - if p == addr { - ctx.PushBoolean(true) - return 1 - } - } - ctx.PushBoolean(false) - return 1 - }) - tracer.vm.PushGlobalGoFunction("slice", func(ctx *duktape.Context) int { - start, end := ctx.GetInt(-2), ctx.GetInt(-1) - ctx.Pop2() - - blob := popSlice(ctx) - size := end - start - - if start < 0 || start > end || end > len(blob) { - // TODO(karalabe): We can't js-throw from Go inside duktape inside Go. The Go - // runtime goes belly up https://github.com/golang/go/issues/15639. - log.Warn("Tracer accessed out of bound memory", "available", len(blob), "offset", start, "size", size) - ctx.PushFixedBuffer(0) - return 1 - } - copy(makeSlice(ctx.PushFixedBuffer(size), uint(size)), blob[start:end]) - return 1 - }) - // Push the JavaScript tracer as object #0 onto the JSVM stack and validate it - if err := tracer.vm.PevalString("(" + code + ")"); err != nil { - log.Warn("Failed to compile tracer", "err", err) - return nil, err - } - tracer.tracerObject = 0 // yeah, nice, eval can't return the index itself - - hasStep := tracer.vm.GetPropString(tracer.tracerObject, "step") - tracer.vm.Pop() - - if !tracer.vm.GetPropString(tracer.tracerObject, "fault") { - return nil, fmt.Errorf("trace object must expose a function fault()") - } - tracer.vm.Pop() - - if !tracer.vm.GetPropString(tracer.tracerObject, "result") { - return nil, fmt.Errorf("trace object must expose a function result()") - } - tracer.vm.Pop() - - hasEnter := tracer.vm.GetPropString(tracer.tracerObject, "enter") - tracer.vm.Pop() - hasExit := tracer.vm.GetPropString(tracer.tracerObject, "exit") - tracer.vm.Pop() - if hasEnter != hasExit { - return nil, fmt.Errorf("trace object must expose either both or none of enter() and exit()") - } - tracer.traceCallFrames = hasEnter && hasExit - tracer.traceSteps = hasStep - - // Tracer is valid, inject the big int library to access large numbers - tracer.vm.EvalString(bigIntegerJS) - tracer.vm.PutGlobalString("bigInt") - - // Push the global environment state as object #1 into the JSVM stack - tracer.stateObject = tracer.vm.PushObject() - - logObject := tracer.vm.PushObject() - - tracer.opWrapper.pushObject(tracer.vm) - tracer.vm.PutPropString(logObject, "op") - - tracer.stackWrapper.pushObject(tracer.vm) - tracer.vm.PutPropString(logObject, "stack") - - tracer.memoryWrapper.pushObject(tracer.vm) - tracer.vm.PutPropString(logObject, "memory") - - tracer.contractWrapper.pushObject(tracer.vm) - tracer.vm.PutPropString(logObject, "contract") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.pcValue); return 1 }) - tracer.vm.PutPropString(logObject, "getPC") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.gasValue); return 1 }) - tracer.vm.PutPropString(logObject, "getGas") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.costValue); return 1 }) - tracer.vm.PutPropString(logObject, "getCost") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.depthValue); return 1 }) - tracer.vm.PutPropString(logObject, "getDepth") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { ctx.PushUint(*tracer.refundValue); return 1 }) - tracer.vm.PutPropString(logObject, "getRefund") - - tracer.vm.PushGoFunction(func(ctx *duktape.Context) int { - if tracer.errorValue != nil { - ctx.PushString(*tracer.errorValue) - } else { - ctx.PushUndefined() - } - return 1 - }) - tracer.vm.PutPropString(logObject, "getError") - - tracer.vm.PutPropString(tracer.stateObject, "log") - - tracer.frame.pushObject(tracer.vm) - tracer.vm.PutPropString(tracer.stateObject, "frame") - - tracer.frameResult.pushObject(tracer.vm) - tracer.vm.PutPropString(tracer.stateObject, "frameResult") - - tracer.dbWrapper.pushObject(tracer.vm) - tracer.vm.PutPropString(tracer.stateObject, "db") - - return tracer, nil -} - -// Stop terminates execution of the tracer at the first opportune moment. -func (jst *jsTracer) Stop(err error) { - jst.reason = err - atomic.StoreUint32(&jst.interrupt, 1) -} - -// call executes a method on a JS object, catching any errors, formatting and -// returning them as error objects. -func (jst *jsTracer) call(noret bool, method string, args ...string) (json.RawMessage, error) { - // Execute the JavaScript call and return any error - jst.vm.PushString(method) - for _, arg := range args { - jst.vm.GetPropString(jst.stateObject, arg) - } - code := jst.vm.PcallProp(jst.tracerObject, len(args)) - defer jst.vm.Pop() - - if code != 0 { - err := jst.vm.SafeToString(-1) - return nil, errors.New(err) - } - // No error occurred, extract return value and return - if noret { - return nil, nil - } - // Push a JSON marshaller onto the stack. We can't marshal from the out- - // side because duktape can crash on large nestings and we can't catch - // C++ exceptions ourselves from Go. TODO(karalabe): Yuck, why wrap?! - jst.vm.PushString("(JSON.stringify)") - jst.vm.Eval() - - jst.vm.Swap(-1, -2) - if code = jst.vm.Pcall(1); code != 0 { - err := jst.vm.SafeToString(-1) - return nil, errors.New(err) - } - return json.RawMessage(jst.vm.SafeToString(-1)), nil -} - -func wrapError(context string, err error) error { - return fmt.Errorf("%v in server-side tracer function '%v'", err, context) -} - -// CaptureStart implements the Tracer interface to initialize the tracing operation. -func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - jst.env = env - jst.ctx["type"] = "CALL" - if create { - jst.ctx["type"] = "CREATE" - } - jst.ctx["from"] = from - jst.ctx["to"] = to - jst.ctx["input"] = input - jst.ctx["gas"] = gas - jst.ctx["gasPrice"] = env.TxContext.GasPrice - jst.ctx["value"] = value - - // Initialize the context - jst.ctx["block"] = env.Context.BlockNumber.Uint64() - jst.dbWrapper.db = env.StateDB - // Update list of precompiles based on current block - rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil) - jst.activePrecompiles = vm.ActivePrecompiles(rules) - - // Compute intrinsic gas - isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) - isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber) - intrinsicGas, err := core.IntrinsicGas(input, nil, jst.ctx["type"] == "CREATE", isHomestead, isIstanbul) - if err != nil { - return - } - jst.ctx["intrinsicGas"] = intrinsicGas -} - -// CaptureState implements the Tracer interface to trace a single step of VM execution. -func (jst *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - if !jst.traceSteps { - return - } - if jst.err != nil { - return - } - // If tracing was interrupted, set the error and stop - if atomic.LoadUint32(&jst.interrupt) > 0 { - jst.err = jst.reason - jst.env.Cancel() - return - } - jst.opWrapper.op = op - jst.stackWrapper.stack = scope.Stack - jst.memoryWrapper.memory = scope.Memory - jst.contractWrapper.contract = scope.Contract - - *jst.pcValue = uint(pc) - *jst.gasValue = uint(gas) - *jst.costValue = uint(cost) - *jst.depthValue = uint(depth) - *jst.refundValue = uint(jst.env.StateDB.GetRefund()) - - jst.errorValue = nil - if err != nil { - jst.errorValue = new(string) - *jst.errorValue = err.Error() - } - - if _, err := jst.call(true, "step", "log", "db"); err != nil { - jst.err = wrapError("step", err) - } -} - -// CaptureFault implements the Tracer interface to trace an execution fault -func (jst *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { - if jst.err != nil { - return - } - // Apart from the error, everything matches the previous invocation - jst.errorValue = new(string) - *jst.errorValue = err.Error() - - if _, err := jst.call(true, "fault", "log", "db"); err != nil { - jst.err = wrapError("fault", err) - } -} - -// CaptureEnd is called after the call finishes to finalize the tracing. -func (jst *jsTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) { - jst.ctx["output"] = output - jst.ctx["time"] = t.String() - jst.ctx["gasUsed"] = gasUsed - - if err != nil { - jst.ctx["error"] = err.Error() - } -} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (jst *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - if !jst.traceCallFrames { - return - } - if jst.err != nil { - return - } - // If tracing was interrupted, set the error and stop - if atomic.LoadUint32(&jst.interrupt) > 0 { - jst.err = jst.reason - return - } - - *jst.frame.typ = typ.String() - *jst.frame.from = from - *jst.frame.to = to - jst.frame.input = common.CopyBytes(input) - *jst.frame.gas = uint(gas) - jst.frame.value = nil - if value != nil { - jst.frame.value = new(big.Int).SetBytes(value.Bytes()) - } - - if _, err := jst.call(true, "enter", "frame"); err != nil { - jst.err = wrapError("enter", err) - } -} - -// CaptureExit is called when EVM exits a scope, even if the scope didn't -// execute any code. -func (jst *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error) { - if !jst.traceCallFrames { - return - } - // If tracing was interrupted, set the error and stop - if atomic.LoadUint32(&jst.interrupt) > 0 { - jst.err = jst.reason - return - } - - jst.frameResult.output = common.CopyBytes(output) - *jst.frameResult.gasUsed = uint(gasUsed) - jst.frameResult.errorValue = nil - if err != nil { - jst.frameResult.errorValue = new(string) - *jst.frameResult.errorValue = err.Error() - } - - if _, err := jst.call(true, "exit", "frameResult"); err != nil { - jst.err = wrapError("exit", err) - } -} - -// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error -func (jst *jsTracer) GetResult() (json.RawMessage, error) { - // Transform the context into a JavaScript object and inject into the state - obj := jst.vm.PushObject() - - for key, val := range jst.ctx { - jst.addToObj(obj, key, val) - } - jst.vm.PutPropString(jst.stateObject, "ctx") - - // Finalize the trace and return the results - result, err := jst.call(false, "result", "ctx", "db") - if err != nil { - jst.err = wrapError("result", err) - } - // Clean up the JavaScript environment - jst.vm.DestroyHeap() - jst.vm.Destroy() - - return result, jst.err -} - -// addToObj pushes a field to a JS object. -func (jst *jsTracer) addToObj(obj int, key string, val interface{}) { - pushValue(jst.vm, val) - jst.vm.PutPropString(obj, key) -} - -func pushValue(ctx *duktape.Context, val interface{}) { - switch val := val.(type) { - case uint64: - ctx.PushUint(uint(val)) - case string: - ctx.PushString(val) - case []byte: - ptr := ctx.PushFixedBuffer(len(val)) - copy(makeSlice(ptr, uint(len(val))), val) - case common.Address: - ptr := ctx.PushFixedBuffer(20) - copy(makeSlice(ptr, 20), val[:]) - case *big.Int: - pushBigInt(val, ctx) - case int: - ctx.PushInt(val) - case uint: - ctx.PushUint(val) - case common.Hash: - ptr := ctx.PushFixedBuffer(32) - copy(makeSlice(ptr, 32), val[:]) - default: - panic(fmt.Sprintf("unsupported type: %T", val)) - } -} diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index cf0a4aa82..4389004dc 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -1,4 +1,4 @@ -// Copyright 2017 The go-ethereum Authors +// Copyright 2022 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -20,6 +20,7 @@ import ( "encoding/json" "errors" "math/big" + "strings" "testing" "time" @@ -62,15 +63,19 @@ func testCtx() *vmContext { func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig) (json.RawMessage, error) { var ( env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Debug: true, Tracer: tracer}) + gasLimit uint64 = 31000 startGas uint64 = 10000 value = big.NewInt(0) contract = vm.NewContract(account{}, account{}, value, startGas) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} + tracer.CaptureTxStart(gasLimit) tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value) ret, err := env.Interpreter().Run(contract, []byte{}, false) tracer.CaptureEnd(ret, startGas-contract.Gas, 1, err) + // Rest gas assumes no refund + tracer.CaptureTxEnd(startGas - contract.Gas) if err != nil { return nil, err } @@ -80,7 +85,7 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon func TestTracer(t *testing.T) { execTracer := func(code string) ([]byte, string) { t.Helper() - tracer, err := newJsTracer(code, nil) + tracer, err := newJsTracer(code, nil, nil) if err != nil { t.Fatal(err) } @@ -97,28 +102,43 @@ func TestTracer(t *testing.T) { }{ { // tests that we don't panic on bad arguments to memory access code: "{depths: [], step: function(log) { this.depths.push(log.memory.slice(-1,-2)); }, fault: function() {}, result: function() { return this.depths; }}", - want: `[{},{},{}]`, + want: ``, + fail: "Tracer accessed out of bound memory: offset -1, end -2 at step (:1:53(15)) in server-side tracer function 'step'", }, { // tests that we don't panic on bad arguments to stack peeks code: "{depths: [], step: function(log) { this.depths.push(log.stack.peek(-1)); }, fault: function() {}, result: function() { return this.depths; }}", - want: `["0","0","0"]`, + want: ``, + fail: "Tracer accessed out of bound stack: size 0, index -1 at step (:1:53(13)) in server-side tracer function 'step'", }, { // tests that we don't panic on bad arguments to memory getUint code: "{ depths: [], step: function(log, db) { this.depths.push(log.memory.getUint(-64));}, fault: function() {}, result: function() { return this.depths; }}", - want: `["0","0","0"]`, + want: ``, + fail: "Tracer accessed out of bound memory: available 0, offset -64, size 32 at step (:1:58(13)) in server-side tracer function 'step'", }, { // tests some general counting code: "{count: 0, step: function() { this.count += 1; }, fault: function() {}, result: function() { return this.count; }}", want: `3`, }, { // tests that depth is reported correctly code: "{depths: [], step: function(log) { this.depths.push(log.stack.length()); }, fault: function() {}, result: function() { return this.depths; }}", want: `[0,1,2]`, + }, { // tests memory length + code: "{lengths: [], step: function(log) { this.lengths.push(log.memory.length()); }, fault: function() {}, result: function() { return this.lengths; }}", + want: `[0,0,0]`, }, { // tests to-string of opcodes code: "{opcodes: [], step: function(log) { this.opcodes.push(log.op.toString()); }, fault: function() {}, result: function() { return this.opcodes; }}", want: `["PUSH1","PUSH1","STOP"]`, }, { // tests intrinsic gas code: "{depths: [], step: function() {}, fault: function() {}, result: function(ctx) { return ctx.gasPrice+'.'+ctx.gasUsed+'.'+ctx.intrinsicGas; }}", want: `"100000.6.21000"`, - }, { // tests too deep object / serialization crash - code: "{step: function() {}, fault: function() {}, result: function() { var o={}; var x=o; for (var i=0; i<1000; i++){ o.foo={}; o=o.foo; } return x; }}", - fail: "RangeError: json encode recursion limit in server-side tracer function 'result'", + }, { + code: "{res: null, step: function(log) {}, fault: function() {}, result: function() { return toWord('0xffaa') }}", + want: `{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":255,"31":170}`, + }, { // test feeding a buffer back into go + code: "{res: null, step: function(log) { var address = log.contract.getAddress(); this.res = toAddress(address); }, fault: function() {}, result: function() { return this.res }}", + want: `{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0}`, + }, { + code: "{res: null, step: function(log) { var address = '0x0000000000000000000000000000000000000000'; this.res = toAddress(address); }, fault: function() {}, result: function() { return this.res }}", + want: `{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0}`, + }, { + code: "{res: null, step: function(log) { var address = Array.prototype.slice.call(log.contract.getAddress()); this.res = toAddress(address); }, fault: function() {}, result: function() { return this.res }}", + want: `{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0}`, }, } { if have, err := execTracer(tt.code); tt.want != string(have) || tt.fail != err { @@ -128,9 +148,8 @@ func TestTracer(t *testing.T) { } func TestHalt(t *testing.T) { - t.Skip("duktape doesn't support abortion") timeout := errors.New("stahp") - tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil) + tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil, nil) if err != nil { t.Fatal(err) } @@ -138,13 +157,13 @@ func TestHalt(t *testing.T) { time.Sleep(1 * time.Second) tracer.Stop(timeout) }() - if _, err = runTrace(tracer, testCtx(), params.TestChainConfig); err.Error() != "stahp in server-side tracer function 'step'" { + if _, err = runTrace(tracer, testCtx(), params.TestChainConfig); !strings.Contains(err.Error(), "stahp") { t.Errorf("Expected timeout error, got %v", err) } } func TestHaltBetweenSteps(t *testing.T) { - tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil) + tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil, nil) if err != nil { t.Fatal(err) } @@ -158,17 +177,17 @@ func TestHaltBetweenSteps(t *testing.T) { tracer.Stop(timeout) tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil) - if _, err := tracer.GetResult(); err.Error() != timeout.Error() { + if _, err := tracer.GetResult(); !strings.Contains(err.Error(), timeout.Error()) { t.Errorf("Expected timeout error, got %v", err) } } -// TestNoStepExec tests a regular value transfer (no exec), and accessing the statedb +// testNoStepExec tests a regular value transfer (no exec), and accessing the statedb // in 'result' func TestNoStepExec(t *testing.T) { execTracer := func(code string) []byte { t.Helper() - tracer, err := newJsTracer(code, nil) + tracer, err := newJsTracer(code, nil, nil) if err != nil { t.Fatal(err) } @@ -202,7 +221,7 @@ func TestIsPrecompile(t *testing.T) { chaincfg.IstanbulBlock = big.NewInt(200) chaincfg.BerlinBlock = big.NewInt(300) txCtx := vm.TxContext{GasPrice: big.NewInt(100000)} - tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil) + tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil) if err != nil { t.Fatal(err) } @@ -216,7 +235,7 @@ func TestIsPrecompile(t *testing.T) { t.Errorf("Tracer should not consider blake2f as precompile in byzantium") } - tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil) + tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil) blockCtx = vm.BlockContext{BlockNumber: big.NewInt(250)} res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg) if err != nil { @@ -229,14 +248,14 @@ func TestIsPrecompile(t *testing.T) { func TestEnterExit(t *testing.T) { // test that either both or none of enter() and exit() are defined - if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context)); err == nil { + if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil); err == nil { t.Fatal("tracer creation should've failed without exit() definition") } - if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context)); err != nil { + if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil); err != nil { t.Fatal(err) } // test that the enter and exit method are correctly invoked and the values passed - tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context)) + tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil) if err != nil { t.Fatal(err) } @@ -255,3 +274,33 @@ func TestEnterExit(t *testing.T) { t.Errorf("Number of invocations of enter() and exit() is wrong. Have %s, want %s\n", have, want) } } + +func TestSetup(t *testing.T) { + // Test empty config + _, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil) + if err != nil { + t.Error(err) + } + + cfg, err := json.Marshal(map[string]string{"foo": "bar"}) + if err != nil { + t.Fatal(err) + } + // Test no setup func + _, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg) + if err != nil { + t.Fatal(err) + } + // Test config value + tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg) + if err != nil { + t.Fatal(err) + } + have, err := tracer.GetResult() + if err != nil { + t.Fatal(err) + } + if string(have) != `"bar"` { + t.Errorf("tracer returned wrong result. have: %s, want: \"bar\"\n", string(have)) + } +} diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index bb1097d8e..a8908094e 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -169,6 +169,10 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {} +func (*AccessListTracer) CaptureTxStart(gasLimit uint64) {} + +func (*AccessListTracer) CaptureTxEnd(restGas uint64) {} + // AccessList returns the current accesslist maintained by the tracer. func (a *AccessListTracer) AccessList() types.AccessList { return a.list.accessList() diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index d0c7bff89..c4dec9f36 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -18,10 +18,12 @@ package logger import ( "encoding/hex" + "encoding/json" "fmt" "io" "math/big" "strings" + "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -108,10 +110,15 @@ type StructLogger struct { cfg Config env *vm.EVM - storage map[common.Address]Storage - logs []StructLog - output []byte - err error + storage map[common.Address]Storage + logs []StructLog + output []byte + err error + gasLimit uint64 + usedGas uint64 + + interrupt uint32 // Atomic flag to signal execution interruption + reason error // Textual reason for the interruption } // NewStructLogger returns a new logger @@ -142,13 +149,19 @@ func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common. // // CaptureState also tracks SLOAD/SSTORE ops to track storage change. func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - memory := scope.Memory - stack := scope.Stack - contract := scope.Contract + // If tracing was interrupted, set the error and stop + if atomic.LoadUint32(&l.interrupt) > 0 { + l.env.Cancel() + return + } // check if already accumulated the specified number of logs if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) { return } + + memory := scope.Memory + stack := scope.Stack + contract := scope.Contract // Copy a snapshot of the current memory state to a new buffer var mem []byte if l.cfg.EnableMemory { @@ -221,7 +234,42 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { } -func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} +func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) { +} + +func (l *StructLogger) GetResult() (json.RawMessage, error) { + // Tracing aborted + if l.reason != nil { + return nil, l.reason + } + failed := l.err != nil + returnData := common.CopyBytes(l.output) + // Return data when successful and revert reason when reverted, otherwise empty. + returnVal := fmt.Sprintf("%x", returnData) + if failed && l.err != vm.ErrExecutionReverted { + returnVal = "" + } + return json.Marshal(&ExecutionResult{ + Gas: l.usedGas, + Failed: failed, + ReturnValue: returnVal, + StructLogs: formatLogs(l.StructLogs()), + }) +} + +// Stop terminates execution of the tracer at the first opportune moment. +func (l *StructLogger) Stop(err error) { + l.reason = err + atomic.StoreUint32(&l.interrupt, 1) +} + +func (l *StructLogger) CaptureTxStart(gasLimit uint64) { + l.gasLimit = gasLimit +} + +func (l *StructLogger) CaptureTxEnd(restGas uint64) { + l.usedGas = l.gasLimit - restGas +} // StructLogs returns the captured log entries. func (l *StructLogger) StructLogs() []StructLog { return l.logs } @@ -347,3 +395,70 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad } func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} + +func (*mdLogger) CaptureTxStart(gasLimit uint64) {} + +func (*mdLogger) CaptureTxEnd(restGas uint64) {} + +// ExecutionResult groups all structured logs emitted by the EVM +// while replaying a transaction in debug mode as well as transaction +// execution status, the amount of gas used and the return value +type ExecutionResult struct { + Gas uint64 `json:"gas"` + Failed bool `json:"failed"` + ReturnValue string `json:"returnValue"` + StructLogs []StructLogRes `json:"structLogs"` +} + +// StructLogRes stores a structured log emitted by the EVM while replaying a +// transaction in debug mode +type StructLogRes struct { + Pc uint64 `json:"pc"` + Op string `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Depth int `json:"depth"` + Error string `json:"error,omitempty"` + Stack *[]string `json:"stack,omitempty"` + Memory *[]string `json:"memory,omitempty"` + Storage *map[string]string `json:"storage,omitempty"` + RefundCounter uint64 `json:"refund,omitempty"` +} + +// formatLogs formats EVM returned structured logs for json output +func formatLogs(logs []StructLog) []StructLogRes { + formatted := make([]StructLogRes, len(logs)) + for index, trace := range logs { + formatted[index] = StructLogRes{ + Pc: trace.Pc, + Op: trace.Op.String(), + Gas: trace.Gas, + GasCost: trace.GasCost, + Depth: trace.Depth, + Error: trace.ErrorString(), + RefundCounter: trace.RefundCounter, + } + if trace.Stack != nil { + stack := make([]string, len(trace.Stack)) + for i, stackValue := range trace.Stack { + stack[i] = stackValue.Hex() + } + formatted[index].Stack = &stack + } + if trace.Memory != nil { + memory := make([]string, 0, (len(trace.Memory)+31)/32) + for i := 0; i+32 <= len(trace.Memory); i += 32 { + memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) + } + formatted[index].Memory = &memory + } + if trace.Storage != nil { + storage := make(map[string]string) + for i, storageValue := range trace.Storage { + storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + } + formatted[index].Storage = &storage + } + } + return formatted +} diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 4a7abacba..72ad0199c 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -98,3 +98,7 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common. } func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {} + +func (l *JSONLogger) CaptureTxStart(gasLimit uint64) {} + +func (l *JSONLogger) CaptureTxEnd(restGas uint64) {} diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index ad1d89071..34e608bfd 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -55,11 +55,11 @@ type fourByteTracer struct { // newFourByteTracer returns a native go tracer which collects // 4 byte-identifiers of a tx, and implements vm.EVMLogger. -func newFourByteTracer() tracers.Tracer { +func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { t := &fourByteTracer{ ids: make(map[string]int), } - return t + return t, nil } // isPrecompiled returns whether the addr is a precompile. Logic borrowed from newJsTracer in eth/tracers/js/tracer.go @@ -131,6 +131,10 @@ func (t *fourByteTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, func (t *fourByteTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) { } +func (*fourByteTracer) CaptureTxStart(gasLimit uint64) {} + +func (*fourByteTracer) CaptureTxEnd(restGas uint64) {} + // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). func (t *fourByteTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 08dc76aa6..7af0e658a 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -50,16 +50,27 @@ type callFrame struct { type callTracer struct { env *vm.EVM callstack []callFrame + config callTracerConfig interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption } +type callTracerConfig struct { + OnlyTopCall bool `json:"onlyTopCall"` // If true, call tracer won't collect any subcalls +} + // newCallTracer returns a native go tracer which tracks // call frames of a tx, and implements vm.EVMLogger. -func newCallTracer() tracers.Tracer { +func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { + var config callTracerConfig + if cfg != nil { + if err := json.Unmarshal(cfg, &config); err != nil { + return nil, err + } + } // First callframe contains tx context info // and is populated on start and end. - return &callTracer{callstack: make([]callFrame, 1)} + return &callTracer{callstack: make([]callFrame, 1), config: config}, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. @@ -101,6 +112,9 @@ func (t *callTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ * // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if t.config.OnlyTopCall { + return + } // Skip if tracing was interrupted if atomic.LoadUint32(&t.interrupt) > 0 { t.env.Cancel() @@ -121,6 +135,9 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. // CaptureExit is called when EVM exits a scope, even if the scope didn't // execute any code. func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { + if t.config.OnlyTopCall { + return + } size := len(t.callstack) if size <= 1 { return @@ -142,6 +159,10 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) { t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call) } +func (*callTracer) CaptureTxStart(gasLimit uint64) {} + +func (*callTracer) CaptureTxEnd(restGas uint64) {} + // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). func (t *callTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index 15b7dbccb..c252b2408 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -35,8 +35,8 @@ func init() { type noopTracer struct{} // newNoopTracer returns a new noop tracer. -func newNoopTracer() tracers.Tracer { - return &noopTracer{} +func newNoopTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { + return &noopTracer{}, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. @@ -64,6 +64,10 @@ func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common. func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } +func (*noopTracer) CaptureTxStart(gasLimit uint64) {} + +func (*noopTracer) CaptureTxEnd(restGas uint64) {} + // GetResult returns an empty json object. func (t *noopTracer) GetResult() (json.RawMessage, error) { return json.RawMessage(`{}`), nil diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 598663ac8..b513f383b 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers" @@ -47,14 +46,15 @@ type prestateTracer struct { prestate prestate create bool to common.Address + gasLimit uint64 // Amount of gas bought for the whole tx interrupt uint32 // Atomic flag to signal execution interruption reason error // Textual reason for the interruption } -func newPrestateTracer() tracers.Tracer { +func newPrestateTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { // First callframe contains tx context info // and is populated on start and end. - return &prestateTracer{prestate: prestate{}} + return &prestateTracer{prestate: prestate{}}, nil } // CaptureStart implements the EVMLogger interface to initialize the tracing operation. @@ -63,14 +63,6 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo t.create = create t.to = to - // Compute intrinsic gas - isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber) - isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber) - intrinsicGas, err := core.IntrinsicGas(input, nil, create, isHomestead, isIstanbul) - if err != nil { - return - } - t.lookupAccount(from) t.lookupAccount(to) @@ -79,17 +71,11 @@ func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to commo toBal = new(big.Int).Sub(toBal, value) t.prestate[to].Balance = hexutil.EncodeBig(toBal) - // The sender balance is after reducing: value, gasLimit, intrinsicGas. + // The sender balance is after reducing: value and gasLimit. // We need to re-add them to get the pre-tx balance. fromBal := hexutil.MustDecodeBig(t.prestate[from].Balance) gasPrice := env.TxContext.GasPrice - consumedGas := new(big.Int).Mul( - gasPrice, - new(big.Int).Add( - new(big.Int).SetUint64(intrinsicGas), - new(big.Int).SetUint64(gas), - ), - ) + consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit)) fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas)) t.prestate[from].Balance = hexutil.EncodeBig(fromBal) t.prestate[from].Nonce-- @@ -145,6 +131,12 @@ func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) { } +func (t *prestateTracer) CaptureTxStart(gasLimit uint64) { + t.gasLimit = gasLimit +} + +func (t *prestateTracer) CaptureTxEnd(restGas uint64) {} + // GetResult returns the json-encoded nested list of call traces, and any // error arising from the encoding or forceful termination (via `Stop`). func (t *prestateTracer) GetResult() (json.RawMessage, error) { diff --git a/eth/tracers/native/tracer.go b/eth/tracers/native/tracer.go index 3158654f3..9587caf19 100644 --- a/eth/tracers/native/tracer.go +++ b/eth/tracers/native/tracer.go @@ -35,6 +35,7 @@ func init() { package native import ( + "encoding/json" "errors" "github.com/ethereum/go-ethereum/eth/tracers" @@ -45,6 +46,9 @@ func init() { tracers.RegisterLookup(false, lookup) } +// ctorFn is the constructor signature of a native tracer. +type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error) + /* ctors is a map of package-local tracer constructors. @@ -57,23 +61,23 @@ The go spec (https://golang.org/ref/spec#Package_initialization) says Hence, we cannot make the map in init, but must make it upon first use. */ -var ctors map[string]func() tracers.Tracer +var ctors map[string]ctorFn // register is used by native tracers to register their presence. -func register(name string, ctor func() tracers.Tracer) { +func register(name string, ctor ctorFn) { if ctors == nil { - ctors = make(map[string]func() tracers.Tracer) + ctors = make(map[string]ctorFn) } ctors[name] = ctor } // lookup returns a tracer, if one can be matched to the given name. -func lookup(name string, ctx *tracers.Context) (tracers.Tracer, error) { +func lookup(name string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) { if ctors == nil { - ctors = make(map[string]func() tracers.Tracer) + ctors = make(map[string]ctorFn) } if ctor, ok := ctors[name]; ok { - return ctor(), nil + return ctor(ctx, cfg) } return nil, errors.New("no tracer found") } diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index e7073e7d2..3d2d1256c 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -42,7 +42,7 @@ type Tracer interface { Stop(err error) } -type lookupFunc func(string, *Context) (Tracer, error) +type lookupFunc func(string, *Context, json.RawMessage) (Tracer, error) var ( lookups []lookupFunc @@ -62,9 +62,9 @@ func RegisterLookup(wildcard bool, lookup lookupFunc) { // New returns a new instance of a tracer, by iterating through the // registered lookups. -func New(code string, ctx *Context) (Tracer, error) { +func New(code string, ctx *Context, cfg json.RawMessage) (Tracer, error) { for _, lookup := range lookups { - if tracer, err := lookup(code, ctx); err == nil { + if tracer, err := lookup(code, ctx, cfg); err == nil { return tracer, nil } } diff --git a/go.mod b/go.mod index a9849b51f..3156b4b3b 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,10 @@ module github.com/ethereum/go-ethereum -go 1.15 +go 1.17 require ( - github.com/Azure/azure-pipeline-go v0.2.2 // indirect github.com/Azure/azure-storage-blob-go v0.7.0 - github.com/Azure/go-autorest/autorest/adal v0.8.0 // indirect - github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 - github.com/VividCortex/gohistogram v1.0.0 // indirect github.com/aws/aws-sdk-go-v2 v1.2.0 github.com/aws/aws-sdk-go-v2/config v1.1.1 github.com/aws/aws-sdk-go-v2/credentials v1.1.1 @@ -20,17 +16,12 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v1.8.0 github.com/deepmap/oapi-codegen v1.8.2 // indirect - github.com/dlclark/regexp2 v1.2.0 // indirect github.com/docker/docker v1.6.1 - github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 + github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf github.com/edsrzf/mmap-go v1.0.0 - github.com/etcd-io/bbolt v1.3.3 // indirect github.com/fatih/color v1.7.0 github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 - github.com/fortytw2/leaktest v1.3.0 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff - github.com/go-ole/go-ole v1.2.1 // indirect - github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-stack/stack v1.8.0 github.com/golang/protobuf v1.4.3 github.com/golang/snappy v0.0.4 @@ -46,23 +37,17 @@ require ( github.com/huin/goupnp v1.0.3 github.com/influxdata/influxdb v1.8.3 github.com/influxdata/influxdb-client-go/v2 v2.4.0 - github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e - github.com/jmhodges/levigo v1.0.0 // indirect github.com/julienschmidt/httprouter v1.2.0 github.com/karalabe/usb v0.0.2 - github.com/kylelemons/godebug v1.1.0 // indirect - github.com/magiconair/properties v1.8.6 // indirect github.com/mattn/go-colorable v0.1.8 github.com/mattn/go-isatty v0.0.12 - github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/panjf2000/ants/v2 v2.4.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 github.com/prometheus/tsdb v0.7.1 - github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 // indirect github.com/rjeczalik/notify v0.9.1 github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible @@ -72,21 +57,70 @@ require ( github.com/tendermint/go-amino v0.14.1 github.com/tendermint/iavl v0.12.0 github.com/tendermint/tendermint v0.31.11 - github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef - go.etcd.io/bbolt v1.3.5 // indirect golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 - golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 golang.org/x/text v0.3.6 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/tools v0.1.5 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 ) +require ( + github.com/Azure/azure-pipeline-go v0.2.2 // indirect + github.com/Azure/go-autorest/autorest/adal v0.8.0 // indirect + github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect + github.com/VividCortex/gohistogram v1.0.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect + github.com/aws/smithy-go v1.1.0 // indirect + github.com/beorn7/perks v1.0.0 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect + github.com/etcd-io/bbolt v1.3.3 // indirect + github.com/fortytw2/leaktest v1.3.0 // indirect + github.com/go-kit/kit v0.8.0 // indirect + github.com/go-logfmt/logfmt v0.4.0 // indirect + github.com/go-ole/go-ole v1.2.1 // indirect + github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect + github.com/gogo/protobuf v1.3.1 // indirect + github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect + github.com/jmhodges/levigo v1.0.0 // indirect + github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/mitchellh/pointerstructure v1.2.0 // indirect + github.com/naoina/go-stringutil v0.1.0 // indirect + github.com/opentracing/opentracing-go v1.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.0.0 // indirect + github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect + github.com/prometheus/common v0.6.0 // indirect + github.com/prometheus/procfs v0.0.2 // indirect + github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 // indirect + github.com/tklauser/go-sysconf v0.3.5 // indirect + github.com/tklauser/numcpus v0.2.2 // indirect + go.etcd.io/bbolt v1.3.5 // indirect + golang.org/x/mod v0.4.2 // indirect + golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f // indirect + google.golang.org/grpc v1.26.0 // indirect + google.golang.org/protobuf v1.23.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect +) + replace ( github.com/gogo/protobuf v1.1.1 => github.com/gogo/protobuf v1.3.2 github.com/gogo/protobuf v1.3.1 => github.com/gogo/protobuf v1.3.2 diff --git a/go.sum b/go.sum index 4f2b39c89..571112301 100644 --- a/go.sum +++ b/go.sum @@ -33,7 +33,6 @@ github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSW github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= @@ -111,6 +110,7 @@ github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/ github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f h1:C43yEtQ6NIf4ftFXD/V55gnGFgPbMQobd//YlnLjUJ8= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -126,12 +126,13 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= -github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/docker/docker v1.6.1 h1:4xYASHy5cScPkLD7PO0uTmnVc860m9NarPN1X8zeMe8= github.com/docker/docker v1.6.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 h1:Y9vTBSsV4hSwPSj4bacAU/eSnV3dAxVpepaghAdhGoQ= -github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= +github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= +github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -292,11 +293,13 @@ github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH6 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= @@ -534,7 +537,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20200317015054-43a5402ce75a/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= @@ -678,14 +680,13 @@ google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyz google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= @@ -696,8 +697,9 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 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 h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 2662e16451634593604a51a9d7e05e20d0b868ff Mon Sep 17 00:00:00 2001 From: Guillaume George Date: Fri, 7 Oct 2022 16:13:32 +0900 Subject: [PATCH 02/61] .github: fix job name --- .github/workflows/unit-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index fb0b01fbe..7a5535b8d 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -43,7 +43,7 @@ jobs: restore-keys: | ${{ runner.os }}-go- - - name: Uint Test + - name: Unit Test env: ANDROID_HOME: "" # Skip android test run: | From 237c31870edded5035bfd4d5377fbc089c77cf7f Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 17 Jun 2022 00:44:30 +0200 Subject: [PATCH 03/61] tests/fuzzers/rlp: avoid very large input (#25109) The oss-fuzz engine crashes due to stack overflow decoding a large nested structure into a interface{}. This PR limits the size of the input data, so should avoid such crashes. --- tests/fuzzers/rlp/rlp_fuzzer.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/fuzzers/rlp/rlp_fuzzer.go b/tests/fuzzers/rlp/rlp_fuzzer.go index 18b36287b..ac02e1651 100644 --- a/tests/fuzzers/rlp/rlp_fuzzer.go +++ b/tests/fuzzers/rlp/rlp_fuzzer.go @@ -40,6 +40,9 @@ func Fuzz(input []byte) int { if len(input) == 0 { return 0 } + if len(input) > 500*1024 { + return 0 + } var i int { From ce9dae2517a9b5948efeabb8748d0bf0d30d30ce Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Mon, 20 Jun 2022 10:38:46 +0200 Subject: [PATCH 04/61] internal/ethapi: remove SignAndSendTransaction (#25111) --- internal/ethapi/api.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index d7c01be1f..86d4cfbbe 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -563,12 +563,6 @@ func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Byt return crypto.PubkeyToAddress(*rpk), nil } -// SignAndSendTransaction was renamed to SendTransaction. This method is deprecated -// and will be removed in the future. It primary goal is to give clients time to update. -func (s *PrivateAccountAPI) SignAndSendTransaction(ctx context.Context, args TransactionArgs, passwd string) (common.Hash, error) { - return s.SendTransaction(ctx, args, passwd) -} - // InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key. func (s *PrivateAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) { wallet, err := s.am.Wallet(url) From fafc29f922013b65927a24950ff6211c8ea88cea Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Tue, 21 Jun 2022 05:00:37 -0400 Subject: [PATCH 05/61] trie: fix size accounting in cleaner (#25007) Decrease children size instead of dirties size when marking dirties as cleaned up in trie cleaner --- trie/database.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trie/database.go b/trie/database.go index 7504eb2c9..1de49d3b2 100644 --- a/trie/database.go +++ b/trie/database.go @@ -838,7 +838,7 @@ func (c *cleaner) Put(key []byte, rlp []byte) error { delete(c.db.dirties, hash) c.db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) if node.children != nil { - c.db.dirtiesSize -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) + c.db.childrenSize -= common.StorageSize(cachedNodeChildrenSize + len(node.children)*(common.HashLength+2)) } // Move the flushed node into the clean cache to prevent insta-reloads if c.db.cleans != nil { From 660f920cde535655bf7e6f322c5b1213015d85e9 Mon Sep 17 00:00:00 2001 From: Zachinquarantine Date: Tue, 21 Jun 2022 05:59:02 -0400 Subject: [PATCH 06/61] README,rpc: remove mention of "shh" RPC API (#25137) --- README.md | 2 +- rpc/subscription_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 32a0951e0..f108af280 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ HTTP based JSON-RPC API options: * `--ws.api` API's offered over the WS-RPC interface (default: `eth,net,web3`) * `--ws.origins` Origins from which to accept websockets requests * `--ipcdisable` Disable the IPC-RPC server - * `--ipcapi` API's offered over the IPC-RPC interface (default: `admin,debug,eth,miner,net,personal,shh,txpool,web3`) + * `--ipcapi` API's offered over the IPC-RPC interface (default: `admin,debug,eth,miner,net,personal,txpool,web3`) * `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it) You'll need to use your own programming environments' capabilities (libraries, tools, etc) to diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index 54a053dba..a920205c0 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -48,7 +48,7 @@ func TestNewID(t *testing.T) { func TestSubscriptions(t *testing.T) { var ( - namespaces = []string{"eth", "shh", "bzz"} + namespaces = []string{"eth", "bzz"} service = ¬ificationTestService{} subCount = len(namespaces) notificationCount = 3 From aedd5aaba1a533bbe62dfa23bb5a790b76cf3e1c Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 22 Jun 2022 19:59:55 +0800 Subject: [PATCH 07/61] eth, miner: retrieve mining state from live database (#25139) * miner: retrieve mining state from live database * eth/catalyst: ignore stale fcu events from cl --- miner/miner.go | 1 - miner/worker.go | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index dea30273b..4b20599d6 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -40,7 +40,6 @@ import ( type Backend interface { BlockChain() *core.BlockChain TxPool() *core.TxPool - StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) } // Config is the configuration parameters of mining. diff --git a/miner/worker.go b/miner/worker.go index 7a7eaf14c..3845100a9 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -786,16 +786,6 @@ func (w *worker) makeEnv(parent *types.Block, header *types.Header, coinbase com // Retrieve the parent state to execute on top and start a prefetcher for // the miner to speed block sealing up a bit state, err := w.chain.StateAtWithSharedPool(parent.Root()) - if err != nil { - // Note since the sealing block can be created upon the arbitrary parent - // block, but the state of parent block may already be pruned, so the necessary - // state recovery is needed here in the future. - // - // The maximum acceptable reorg depth can be limited by the finalised block - // somehow. TODO(rjl493456442) fix the hard-coded number here later. - state, err = w.eth.StateAtBlock(parent, 1024, nil, false, false) - log.Warn("Recovered mining state", "root", parent.Root(), "err", err) - } if err != nil { return nil, err } From 0ca5dd727a7eab7af06a9a8a3626dd4dc6f95892 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Thu, 23 Jun 2022 18:11:47 +0200 Subject: [PATCH 08/61] eth/tracers: optimize goja buffer conversion (#25156) This changes the []byte <-> Uint8Array conversion to use an ArrayBuffer, avoiding inefficient copying of the slice data in Goja. Co-authored-by: Felix Lange --- eth/tracers/js/goja.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 20bb4866f..e91e222a6 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -54,11 +54,7 @@ type fromBufFn = func(vm *goja.Runtime, buf goja.Value, allowString bool) ([]byt func toBuf(vm *goja.Runtime, bufType goja.Value, val []byte) (goja.Value, error) { // bufType is usually Uint8Array. This is equivalent to `new Uint8Array(val)` in JS. - res, err := vm.New(bufType, vm.ToValue(val)) - if err != nil { - return nil, err - } - return vm.ToValue(res), nil + return vm.New(bufType, vm.ToValue(vm.NewArrayBuffer(val))) } func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString bool) ([]byte, error) { @@ -69,6 +65,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b break } return common.FromHex(obj.String()), nil + case "Array": var b []byte if err := vm.ExportTo(buf, &b); err != nil { @@ -80,10 +77,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b if !obj.Get("constructor").SameAs(bufType) { break } - var b []byte - if err := vm.ExportTo(buf, &b); err != nil { - return nil, err - } + b := obj.Get("buffer").Export().(goja.ArrayBuffer).Bytes() return b, nil } return nil, fmt.Errorf("invalid buffer type") @@ -775,7 +769,7 @@ func (co *contractObj) GetValue() goja.Value { } func (co *contractObj) GetInput() goja.Value { - input := co.contract.Input + input := common.CopyBytes(co.contract.Input) res, err := co.toBuf(co.vm, input) if err != nil { co.vm.Interrupt(err) From 8c90dc946a0eb765863eaa63cc8ccd8b5e6e9be1 Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Wed, 29 Jun 2022 05:54:42 -0400 Subject: [PATCH 09/61] core/rawdb: simplify TestDiskSeek to use memorydb (#25182) --- core/state/snapshot/disklayer_test.go | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/core/state/snapshot/disklayer_test.go b/core/state/snapshot/disklayer_test.go index 689ed3877..f0c416be6 100644 --- a/core/state/snapshot/disklayer_test.go +++ b/core/state/snapshot/disklayer_test.go @@ -18,15 +18,11 @@ package snapshot import ( "bytes" - "io/ioutil" - "os" "testing" "github.com/VictoriaMetrics/fastcache" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/ethdb/leveldb" "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/rlp" ) @@ -518,18 +514,7 @@ func TestDiskMidAccountPartialMerge(t *testing.T) { // TestDiskSeek tests that seek-operations work on the disk layer func TestDiskSeek(t *testing.T) { // Create some accounts in the disk layer - var db ethdb.Database - - if dir, err := ioutil.TempDir("", "disklayer-test"); err != nil { - t.Fatal(err) - } else { - defer os.RemoveAll(dir) - diskdb, err := leveldb.New(dir, 256, 0, "", false) - if err != nil { - t.Fatal(err) - } - db = rawdb.NewDatabase(diskdb) - } + db := rawdb.NewMemoryDatabase() // Fill even keys [0,2,4...] for i := 0; i < 0xff; i += 2 { acc := common.Hash{byte(i)} From 4ce96802121b8cf7b66543f2116b320aa5489389 Mon Sep 17 00:00:00 2001 From: Andre Patta Date: Wed, 29 Jun 2022 06:57:12 -0300 Subject: [PATCH 10/61] cmd/utils: fix applying bootstrap nodes from config file (#25174) --- cmd/utils/flags.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 376817356..5a9dd0697 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -296,12 +296,12 @@ var ( defaultVerifyMode = ethconfig.Defaults.TriesVerifyMode TriesVerifyModeFlag = TextMarshalerFlag{ Name: "tries-verify-mode", - Usage: `tries verify mode: - "local(default): a normal full node with complete state world(both MPT and snapshot), merkle state root will - be verified against the block header.", - "full: a fast node with only snapshot state world. Merkle state root is verified by the trustworthy remote verify node - by comparing the diffhash(an identify of difflayer generated by the block) and state root.", - "insecure: same as full mode, except that it can tolerate without verifying the diffhash when verify node does not have it.", + Usage: `tries verify mode: + "local(default): a normal full node with complete state world(both MPT and snapshot), merkle state root will + be verified against the block header.", + "full: a fast node with only snapshot state world. Merkle state root is verified by the trustworthy remote verify node + by comparing the diffhash(an identify of difflayer generated by the block) and state root.", + "insecure: same as full mode, except that it can tolerate without verifying the diffhash when verify node does not have it.", "none: no merkle state root verification at all, there is no need to setup or connect remote verify node at all, it is more light comparing to full and insecure mode, but get a very small chance that the state is not consistent with other peers."`, @@ -975,10 +975,11 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { urls = params.RinkebyBootnodes case ctx.GlobalBool(GoerliFlag.Name): urls = params.GoerliBootnodes - case cfg.BootstrapNodes != nil: - return // already set, don't apply defaults. } - + // don't apply defaults if BootstrapNodes is already set + if cfg.BootstrapNodes != nil { + return + } cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls)) for _, url := range urls { if url != "" { From d9229e5c6bdaf7609ae5da4fa084208aa255d47a Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Wed, 29 Jun 2022 19:13:00 +0900 Subject: [PATCH 11/61] common: increase StorageSize test coverage (#25188) --- common/size_test.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/common/size_test.go b/common/size_test.go index 0938d483c..28f053d39 100644 --- a/common/size_test.go +++ b/common/size_test.go @@ -25,6 +25,8 @@ func TestStorageSizeString(t *testing.T) { size StorageSize str string }{ + {2839274474874, "2.58 TiB"}, + {2458492810, "2.29 GiB"}, {2381273, "2.27 MiB"}, {2192, "2.14 KiB"}, {12, "12.00 B"}, @@ -36,3 +38,22 @@ func TestStorageSizeString(t *testing.T) { } } } + +func TestStorageSizeTerminalString(t *testing.T) { + tests := []struct { + size StorageSize + str string + }{ + {2839274474874, "2.58TiB"}, + {2458492810, "2.29GiB"}, + {2381273, "2.27MiB"}, + {2192, "2.14KiB"}, + {12, "12.00B"}, + } + + for _, test := range tests { + if test.size.TerminalString() != test.str { + t.Errorf("%f: got %q, want %q", float64(test.size), test.size.TerminalString(), test.str) + } + } +} From f86368279508d8741da6ba08117fd1e48527f38c Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 30 May 2022 08:42:06 +0200 Subject: [PATCH 12/61] core: use less memory during reorgs (#24616) This PR significantly reduces the memory consumption of a long reorg --- core/blockchain.go | 38 +++++++++++++++++++++++++------------- core/types/transaction.go | 18 ++++++++++++++++++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 832eba973..572b80bab 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2270,8 +2270,8 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { oldChain types.Blocks commonBlock *types.Block - deletedTxs types.Transactions - addedTxs types.Transactions + deletedTxs []common.Hash + addedTxs []common.Hash deletedLogs [][]*types.Log rebirthLogs [][]*types.Log @@ -2281,7 +2281,9 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // Old chain is longer, gather all transactions and logs as deleted ones for ; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1) { oldChain = append(oldChain, oldBlock) - deletedTxs = append(deletedTxs, oldBlock.Transactions()...) + for _, tx := range oldBlock.Transactions() { + deletedTxs = append(deletedTxs, tx.Hash()) + } // Collect deleted logs for notification logs := bc.collectLogs(oldBlock.Hash(), true) @@ -2311,7 +2313,9 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } // Remove an old block as well as stash away a new block oldChain = append(oldChain, oldBlock) - deletedTxs = append(deletedTxs, oldBlock.Transactions()...) + for _, tx := range oldBlock.Transactions() { + deletedTxs = append(deletedTxs, tx.Hash()) + } // Collect deleted logs for notification logs := bc.collectLogs(oldBlock.Hash(), true) @@ -2330,6 +2334,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { return fmt.Errorf("invalid new chain") } } + // Ensure the user sees large reorgs if len(oldChain) > 0 && len(newChain) > 0 { logFn := log.Info @@ -2346,7 +2351,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } else if len(newChain) > 0 { // Special case happens in the post merge stage that current head is // the ancestor of new head while these two blocks are not consecutive - log.Info("Extend chain", "add", len(newChain), "number", newChain[0].NumberU64(), "hash", newChain[0].Hash()) + log.Info("Extend chain", "add", len(newChain), "number", newChain[0].Number(), "hash", newChain[0].Hash()) blockReorgAddMeter.Mark(int64(len(newChain))) } else { // len(newChain) == 0 && len(oldChain) > 0 @@ -2359,19 +2364,17 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // Insert the block in the canonical way, re-writing history bc.writeHeadBlock(newChain[i]) - // Collect reborn logs due to chain reorg - logs := bc.collectLogs(newChain[i].Hash(), false) - if len(logs) > 0 { - rebirthLogs = append(rebirthLogs, logs) - } // Collect the new added transactions. - addedTxs = append(addedTxs, newChain[i].Transactions()...) + for _, tx := range newChain[i].Transactions() { + addedTxs = append(addedTxs, tx.Hash()) + } } + // Delete useless indexes right now which includes the non-canonical // transaction indexes, canonical chain indexes which above the head. indexesBatch := bc.db.NewBatch() - for _, tx := range types.TxDifference(deletedTxs, addedTxs) { - rawdb.DeleteTxLookupEntry(indexesBatch, tx.Hash()) + for _, tx := range types.HashDifference(deletedTxs, addedTxs) { + rawdb.DeleteTxLookupEntry(indexesBatch, tx) } // Delete any canonical number assignments above the new head number := bc.CurrentBlock().NumberU64() @@ -2385,6 +2388,15 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { if err := indexesBatch.Write(); err != nil { log.Crit("Failed to delete useless indexes", "err", err) } + + // Collect the logs + for i := len(newChain) - 1; i >= 1; i-- { + // Collect reborn logs due to chain reorg + logs := bc.collectLogs(newChain[i].Hash(), false) + if len(logs) > 0 { + rebirthLogs = append(rebirthLogs, logs) + } + } // If any logs need to be fired, do it now. In theory we could avoid creating // this goroutine if there are no events to fire, but realistcally that only // ever happens if we're reorging empty blocks, which will only happen on idle diff --git a/core/types/transaction.go b/core/types/transaction.go index 1e6c45cd7..e828c8dcb 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -449,6 +449,24 @@ func TxDifference(a, b Transactions) Transactions { return keep } +// HashDifference returns a new set which is the difference between a and b. +func HashDifference(a, b []common.Hash) []common.Hash { + keep := make([]common.Hash, 0, len(a)) + + remove := make(map[common.Hash]struct{}) + for _, hash := range b { + remove[hash] = struct{}{} + } + + for _, hash := range a { + if _, ok := remove[hash]; !ok { + keep = append(keep, hash) + } + } + + return keep +} + // TxByNonce implements the sort interface to allow sorting a list of transactions // by their nonces. This is usually only useful for sorting transactions from a // single account, otherwise a nonce comparison doesn't make much sense. From 0e17e627eed4446add19ef949cae384205a8332d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boqin=20Qin=28=E7=A7=A6=20=E4=BC=AF=E9=92=A6=29?= Date: Tue, 31 May 2022 02:35:37 +0800 Subject: [PATCH 13/61] eth/filters: use buffered channel to avoid goroutine leak (#24928) --- eth/filters/filter_system_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 220513405..c60a688a3 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -592,7 +592,7 @@ func TestPendingLogsSubscription(t *testing.T) { // (some) events are posted. for i := range testCases { testCases[i].c = make(chan []*types.Log) - testCases[i].err = make(chan error) + testCases[i].err = make(chan error, 1) var err error testCases[i].sub, err = api.events.SubscribeLogs(testCases[i].crit, testCases[i].c) From 2904f20dfc449372a45fb307c1cd6bb10ce668cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 3 Jun 2022 10:40:14 +0200 Subject: [PATCH 14/61] core/vm: optimize jumpdest analysis (#23500) core/vm: optimize PUSH opcode discrimination --- core/vm/analysis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 3733bab6a..4aa8cfe70 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -76,7 +76,7 @@ func codeBitmapInternal(code, bits bitvec) bitvec { for pc := uint64(0); pc < uint64(len(code)); { op := OpCode(code[pc]) pc++ - if op < PUSH1 || op > PUSH32 { + if int8(op) < int8(PUSH1) { // If not PUSH (the int8(op) > int(PUSH32) is always false). continue } numbits := op - PUSH1 + 1 From ea52f6c440c1bcd11215cd9df098f287ff6b938a Mon Sep 17 00:00:00 2001 From: aaronbuchwald Date: Tue, 7 Jun 2022 02:02:04 -0400 Subject: [PATCH 15/61] trie: move locking into trieDB insert method (#25030) Move locking into trieDB insert function --- trie/committer.go | 4 ---- trie/database.go | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/trie/committer.go b/trie/committer.go index 221681f2e..5d9a27a50 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -193,9 +193,7 @@ func (c *committer) store(n node, db *Database) node { } else if db != nil { // No leaf-callback used, but there's still a database. Do serial // insertion - db.lock.Lock() db.insert(common.BytesToHash(hash), size, n) - db.lock.Unlock() } return hash } @@ -209,9 +207,7 @@ func (c *committer) commitLoop(db *Database) { n = item.node ) // We are pooling the trie nodes into an intermediate memory cache - db.lock.Lock() db.insert(hash, size, n) - db.lock.Unlock() if c.onleaf != nil { switch n := n.(type) { diff --git a/trie/database.go b/trie/database.go index 7504eb2c9..e38850611 100644 --- a/trie/database.go +++ b/trie/database.go @@ -316,6 +316,9 @@ func (db *Database) DiskDB() ethdb.KeyValueStore { // All nodes inserted by this function will be reference tracked // and in theory should only used for **trie nodes** insertion. func (db *Database) insert(hash common.Hash, size int, node node) { + db.lock.Lock() + defer db.lock.Unlock() + // If the node's already cached, skip if _, ok := db.dirties[hash]; ok { return From a429a50be56bfe1df727290da61e3df308800493 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi <1591639+s1na@users.noreply.github.com> Date: Tue, 7 Jun 2022 08:31:19 +0200 Subject: [PATCH 16/61] eth/filters: fix getLogs for pending block (#24949) * eth/filters: fix pending for getLogs * add pending method to test backend * fix block range validation --- accounts/abi/bind/backends/simulated.go | 25 +++++++++----- eth/filters/filter.go | 46 ++++++++++++++++++++----- eth/filters/filter_system_test.go | 4 +++ internal/ethapi/backend.go | 1 + 4 files changed, 59 insertions(+), 17 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index ff7c7e97f..f8ceec883 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -63,9 +63,10 @@ type SimulatedBackend struct { database ethdb.Database // In memory database to store our testing data blockchain *core.BlockChain // Ethereum blockchain to handle the consensus - mu sync.Mutex - pendingBlock *types.Block // Currently pending block that will be imported on request - pendingState *state.StateDB // Currently pending state that will be the active on request + mu sync.Mutex + pendingBlock *types.Block // Currently pending block that will be imported on request + pendingState *state.StateDB // Currently pending state that will be the active on request + pendingReceipts types.Receipts // Currently receipts for the pending block events *filters.EventSystem // Event system for filtering log events live @@ -84,8 +85,8 @@ func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.Genesis database: database, blockchain: blockchain, config: genesis.Config, - events: filters.NewEventSystem(&filterBackend{database, blockchain}, false), } + backend.events = filters.NewEventSystem(&filterBackend{database, blockchain, backend}, false) backend.rollback(blockchain.CurrentBlock()) return backend } @@ -662,7 +663,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa return fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce) } // Include tx in chain - blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { + blocks, receipts := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { for _, tx := range b.pendingBlock.Transactions() { block.AddTxWithChain(b.blockchain, tx) } @@ -672,6 +673,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa b.pendingBlock = blocks[0] b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil) + b.pendingReceipts = receipts[0] return nil } @@ -683,7 +685,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter var filter *filters.Filter if query.BlockHash != nil { // Block filter requested, construct a single-shot filter - filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics) + filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain, b}, *query.BlockHash, query.Addresses, query.Topics) } else { // Initialize unset filter boundaries to run from genesis to chain head from := int64(0) @@ -695,7 +697,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter to = query.ToBlock.Int64() } // Construct the range filter - filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics, false) + filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain, b}, from, to, query.Addresses, query.Topics, false) } // Run the filter and return all the logs logs, err := filter.Logs(ctx) @@ -816,8 +818,9 @@ func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList } // filterBackend implements filters.Backend to support filtering for logs without // taking bloom-bits acceleration structures into account. type filterBackend struct { - db ethdb.Database - bc *core.BlockChain + db ethdb.Database + bc *core.BlockChain + backend *SimulatedBackend } func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db } @@ -834,6 +837,10 @@ func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*t return fb.bc.GetHeaderByHash(hash), nil } +func (fb *filterBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { + return fb.backend.pendingBlock, fb.backend.pendingReceipts +} + func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { number := rawdb.ReadHeaderNumber(fb.db, hash) if number == nil { diff --git a/eth/filters/filter.go b/eth/filters/filter.go index e3ccf7d89..a354eb976 100644 --- a/eth/filters/filter.go +++ b/eth/filters/filter.go @@ -39,6 +39,7 @@ type Backend interface { HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) + PendingBlockAndReceipts() (*types.Block, types.Receipts) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription @@ -134,18 +135,27 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { } return f.blockLogs(ctx, header) } + // Short-cut if all we care about is pending logs + if f.begin == rpc.PendingBlockNumber.Int64() { + if f.end != rpc.PendingBlockNumber.Int64() { + return nil, errors.New("invalid block range") + } + return f.pendingLogs() + } // Figure out the limits of the filter range header, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) if header == nil { return nil, nil } - head := header.Number.Uint64() - - if f.begin == -1 { + var ( + head = header.Number.Uint64() + end = uint64(f.end) + pending = f.end == rpc.PendingBlockNumber.Int64() + ) + if f.begin == rpc.LatestBlockNumber.Int64() { f.begin = int64(head) } - end := uint64(f.end) - if f.end == -1 { + if f.end == rpc.LatestBlockNumber.Int64() || f.end == rpc.PendingBlockNumber.Int64() { end = head } if f.rangeLimit && (int64(end)-f.begin) > maxFilterBlockRange { @@ -153,10 +163,10 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { } // Gather all indexed logs, and finish with non indexed ones var ( - logs []*types.Log - err error + logs []*types.Log + err error + size, sections = f.backend.BloomStatus() ) - size, sections := f.backend.BloomStatus() if indexed := sections * size; indexed > uint64(f.begin) { if indexed > end { logs, err = f.indexedLogs(ctx, end) @@ -169,6 +179,13 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { } rest, err := f.unindexedLogs(ctx, end) logs = append(logs, rest...) + if pending { + pendingLogs, err := f.pendingLogs() + if err != nil { + return nil, err + } + logs = append(logs, pendingLogs...) + } return logs, err } @@ -281,6 +298,19 @@ func (f *Filter) checkMatches(ctx context.Context, header *types.Header) (logs [ return nil, nil } +// pendingLogs returns the logs matching the filter criteria within the pending block. +func (f *Filter) pendingLogs() ([]*types.Log, error) { + block, receipts := f.backend.PendingBlockAndReceipts() + if bloomFilter(block.Bloom(), f.addresses, f.topics) { + var unfiltered []*types.Log + for _, r := range receipts { + unfiltered = append(unfiltered, r.Logs...) + } + return filterLogs(unfiltered, nil, nil, f.addresses, f.topics), nil + } + return nil, nil +} + func includes(addresses []common.Address, a common.Address) bool { for _, addr := range addresses { if addr == a { diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index c60a688a3..7435a19e8 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -106,6 +106,10 @@ func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types return logs, nil } +func (b *testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { + return nil, nil +} + func (b *testBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { return b.txFeed.Subscribe(ch) } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 99e7ccce6..889370440 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -67,6 +67,7 @@ type Backend interface { BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) + PendingBlockAndReceipts() (*types.Block, types.Receipts) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetTd(ctx context.Context, hash common.Hash) *big.Int GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) From 7bfcc7ef31fc6753ed8ed1effa0cc8d3f4cea136 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 7 Jun 2022 12:15:22 +0200 Subject: [PATCH 17/61] p2p/discover: fix panicky test (#25038) --- p2p/discover/v4_udp_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index e36912f01..977fa85a0 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -284,6 +284,7 @@ func TestUDPv4_findnode(t *testing.T) { test.waitPacketOut(func(p *v4wire.Neighbors, to *net.UDPAddr, hash []byte) { if len(p.Nodes) != len(want) { t.Errorf("wrong number of results: got %d, want %d", len(p.Nodes), bucketSize) + return } for i, n := range p.Nodes { if n.ID.ID() != want[i].ID() { From d3f26984b5c1f4e80f7594c3f79ebf49a4bccc40 Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Tue, 7 Jun 2022 19:46:27 +0900 Subject: [PATCH 18/61] accounts: increase parseURL test coverage (#25033) accounts/url: add test logic what check null string to parseURL() --- accounts/url_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/accounts/url_test.go b/accounts/url_test.go index bd6f35fa2..239aa06d2 100644 --- a/accounts/url_test.go +++ b/accounts/url_test.go @@ -32,9 +32,10 @@ func TestURLParsing(t *testing.T) { t.Errorf("expected: %v, got: %v", "ethereum.org", url.Path) } - _, err = parseURL("ethereum.org") - if err == nil { - t.Error("expected err, got: nil") + for _, u := range []string{"ethereum.org", ""} { + if _, err = parseURL(u); err == nil { + t.Errorf("input %v, expected err, got: nil", u) + } } } From 978790b0b6a851b2ea6464edb0bc43f6f4a845fb Mon Sep 17 00:00:00 2001 From: Rajaram Gaunker Date: Wed, 8 Jun 2022 09:31:43 -0700 Subject: [PATCH 19/61] core/types: remove unused field 'td' in Block (#25010) --- core/types/block.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/types/block.go b/core/types/block.go index a63666a76..f70978e9b 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -202,10 +202,6 @@ type Block struct { hash atomic.Value size atomic.Value - // Td is used by package core to store the total difficulty - // of the chain up to and including the block. - td *big.Int - // These fields are used by package eth to track // inter-peer block relay. ReceivedAt time.Time @@ -227,7 +223,7 @@ type extblock struct { // are ignored and set to values derived from the given txs, uncles // and receipts. func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt, hasher TrieHasher) *Block { - b := &Block{header: CopyHeader(header), td: new(big.Int)} + b := &Block{header: CopyHeader(header)} // TODO: panic if len(txs) != len(receipts) if len(txs) == 0 { From 5d21a7c7c8df229f15f430ce3081d307f565b42b Mon Sep 17 00:00:00 2001 From: s7v7nislands Date: Tue, 14 Jun 2022 19:47:11 +0800 Subject: [PATCH 20/61] cmd/ethkey: use accounts.TextHash (#25069) --- cmd/ethkey/message.go | 5 +++-- cmd/ethkey/utils.go | 13 ------------- signer/core/signed_data.go | 8 ++++---- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/cmd/ethkey/message.go b/cmd/ethkey/message.go index 69c8cf092..fbd80d6e6 100644 --- a/cmd/ethkey/message.go +++ b/cmd/ethkey/message.go @@ -21,6 +21,7 @@ import ( "fmt" "io/ioutil" + "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" @@ -68,7 +69,7 @@ To sign a message contained in a file, use the --msgfile flag. utils.Fatalf("Error decrypting key: %v", err) } - signature, err := crypto.Sign(signHash(message), key.PrivateKey) + signature, err := crypto.Sign(accounts.TextHash(message), key.PrivateKey) if err != nil { utils.Fatalf("Failed to sign message: %v", err) } @@ -113,7 +114,7 @@ It is possible to refer to a file containing the message.`, utils.Fatalf("Signature encoding is not hexadecimal: %v", err) } - recoveredPubkey, err := crypto.SigToPub(signHash(message), signature) + recoveredPubkey, err := crypto.SigToPub(accounts.TextHash(message), signature) if err != nil || recoveredPubkey == nil { utils.Fatalf("Signature verification failed: %v", err) } diff --git a/cmd/ethkey/utils.go b/cmd/ethkey/utils.go index 70baae92f..f5e87f922 100644 --- a/cmd/ethkey/utils.go +++ b/cmd/ethkey/utils.go @@ -23,7 +23,6 @@ import ( "strings" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/crypto" "gopkg.in/urfave/cli.v1" ) @@ -46,18 +45,6 @@ func getPassphrase(ctx *cli.Context, confirmation bool) string { return utils.GetPassPhrase("", confirmation) } -// signHash is a helper function that calculates a hash for the given message -// that can be safely used to calculate a signature from. -// -// The hash is calculated as -// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}). -// -// This gives context to the signed message and prevents signing of transactions. -func signHash(data []byte) []byte { - msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data) - return crypto.Keccak256([]byte(msg)) -} - // mustPrintJSON prints the JSON encoding of the given object and // exits the program with an error message when the marshaling fails. func mustPrintJSON(jsonObject interface{}) { diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go index 0bfd4f9ee..59a69b365 100644 --- a/signer/core/signed_data.go +++ b/signer/core/signed_data.go @@ -208,7 +208,7 @@ func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType req = &SignDataRequest{ContentType: mediaType, Rawdata: parliaRlp, Messages: messages, Hash: sighash} default: // also case TextPlain.Mime: // Calculates an Ethereum ECDSA signature for: - // hash = keccak256("\x19${byteVersion}Ethereum Signed Message:\n${message length}${message}") + // hash = keccak256("\x19Ethereum Signed Message:\n${message length}${message}") // We expect it to be a string if stringData, ok := data.(string); !ok { return nil, useEthereumV, fmt.Errorf("input for text/plain must be an hex-encoded string") @@ -233,7 +233,7 @@ func (api *SignerAPI) determineSignatureFormat(ctx context.Context, contentType return req, useEthereumV, nil } -// SignTextWithValidator signs the given message which can be further recovered +// SignTextValidator signs the given message which can be further recovered // with the given validator. // hash = keccak256("\x19\x00"${address}${data}). func SignTextValidator(validatorData apitypes.ValidatorData) (hexutil.Bytes, string) { @@ -320,11 +320,11 @@ func (api *SignerAPI) EcRecover(ctx context.Context, data hexutil.Bytes, sig hex // // Note, this function is compatible with eth_sign and personal_sign. As such it recovers // the address of: - // hash = keccak256("\x19${byteVersion}Ethereum Signed Message:\n${message length}${message}") + // hash = keccak256("\x19Ethereum Signed Message:\n${message length}${message}") // addr = ecrecover(hash, signature) // // Note, the signature must conform to the secp256k1 curve R, S and V values, where - // the V value must be be 27 or 28 for legacy reasons. + // the V value must be 27 or 28 for legacy reasons. // // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover if len(sig) != 65 { From bd79e2d3df2f07f8fde0777252bbc8b646504625 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 14 Jun 2022 14:08:43 +0200 Subject: [PATCH 21/61] common: improve pretty duration regex (#25073) * common: improve pretty duration regex * common: improve pretty duration regex --- common/format.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/format.go b/common/format.go index 6fc21af71..7af41f52d 100644 --- a/common/format.go +++ b/common/format.go @@ -27,12 +27,12 @@ import ( // the unnecessary precision off from the formatted textual representation. type PrettyDuration time.Duration -var prettyDurationRe = regexp.MustCompile(`\.[0-9]+`) +var prettyDurationRe = regexp.MustCompile(`\.[0-9]{4,}`) // String implements the Stringer interface, allowing pretty printing of duration // values rounded to three decimals. func (d PrettyDuration) String() string { - label := fmt.Sprintf("%v", time.Duration(d)) + label := time.Duration(d).String() if match := prettyDurationRe.FindString(label); len(match) > 4 { label = strings.Replace(label, match, match[:4], 1) } From 2003d543e8c1986230caf84f11466b6222ec1d96 Mon Sep 17 00:00:00 2001 From: lmittmann Date: Tue, 14 Jun 2022 14:09:48 +0200 Subject: [PATCH 22/61] all: prefer `new(big.Int)` over `big.NewInt(0)` (#25087) minor performance improvement: `big.NewInt(0).Xxx` -> `new(big.Int).Xxx` --- accounts/abi/unpack.go | 10 ++++------ accounts/abi/unpack_test.go | 2 +- cmd/devp2p/internal/ethtest/chain.go | 4 ++-- cmd/evm/internal/t8ntool/execution.go | 2 +- consensus/ethash/consensus_test.go | 2 +- core/blockchain_test.go | 6 +++--- internal/ethapi/api.go | 2 +- rlp/decode_test.go | 2 +- rlp/encode_test.go | 6 +++--- signer/core/api_test.go | 2 +- signer/fourbyte/validation_test.go | 4 ++-- signer/rules/rules_test.go | 4 ++-- 12 files changed, 22 insertions(+), 24 deletions(-) diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index 43cd6c645..28c5c82bb 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -255,7 +255,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) { // lengthPrefixPointsTo interprets a 32 byte slice as an offset and then determines which indices to look to decode the type. func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) { - bigOffsetEnd := big.NewInt(0).SetBytes(output[index : index+32]) + bigOffsetEnd := new(big.Int).SetBytes(output[index : index+32]) bigOffsetEnd.Add(bigOffsetEnd, common.Big32) outputLength := big.NewInt(int64(len(output))) @@ -268,11 +268,9 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err } offsetEnd := int(bigOffsetEnd.Uint64()) - lengthBig := big.NewInt(0).SetBytes(output[offsetEnd-32 : offsetEnd]) + lengthBig := new(big.Int).SetBytes(output[offsetEnd-32 : offsetEnd]) - totalSize := big.NewInt(0) - totalSize.Add(totalSize, bigOffsetEnd) - totalSize.Add(totalSize, lengthBig) + totalSize := new(big.Int).Add(bigOffsetEnd, lengthBig) if totalSize.BitLen() > 63 { return 0, 0, fmt.Errorf("abi: length larger than int64: %v", totalSize) } @@ -287,7 +285,7 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err // tuplePointsTo resolves the location reference for dynamic tuple. func tuplePointsTo(index int, output []byte) (start int, err error) { - offset := big.NewInt(0).SetBytes(output[index : index+32]) + offset := new(big.Int).SetBytes(output[index : index+32]) outputLen := big.NewInt(int64(len(output))) if offset.Cmp(outputLen) > 0 { diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index bf40c301b..ae3565c71 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -424,7 +424,7 @@ func TestMultiReturnWithStringArray(t *testing.T) { } buff := new(bytes.Buffer) buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000005c1b78ea0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000001a055690d9db80000000000000000000000000000ab1257528b3782fb40d7ed5f72e624b744dffb2f00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001048656c6c6f2c20457468657265756d2100000000000000000000000000000000")) - temp, _ := big.NewInt(0).SetString("30000000000000000000", 10) + temp, _ := new(big.Int).SetString("30000000000000000000", 10) ret1, ret1Exp := new([3]*big.Int), [3]*big.Int{big.NewInt(1545304298), big.NewInt(6), temp} ret2, ret2Exp := new(common.Address), common.HexToAddress("ab1257528b3782fb40d7ed5f72e624b744dffb2f") ret3, ret3Exp := new([2]string), [2]string{"Ethereum", "Hello, Ethereum!"} diff --git a/cmd/devp2p/internal/ethtest/chain.go b/cmd/devp2p/internal/ethtest/chain.go index d0d55a455..f283154c8 100644 --- a/cmd/devp2p/internal/ethtest/chain.go +++ b/cmd/devp2p/internal/ethtest/chain.go @@ -48,7 +48,7 @@ func (c *Chain) Len() int { // TD calculates the total difficulty of the chain at the // chain head. func (c *Chain) TD() *big.Int { - sum := big.NewInt(0) + sum := new(big.Int) for _, block := range c.blocks[:c.Len()] { sum.Add(sum, block.Difficulty()) } @@ -58,7 +58,7 @@ func (c *Chain) TD() *big.Int { // TotalDifficultyAt calculates the total difficulty of the chain // at the given block height. func (c *Chain) TotalDifficultyAt(height int) *big.Int { - sum := big.NewInt(0) + sum := new(big.Int) if height >= c.Len() { return sum } diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 9eaead387..56d6a9b5f 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -241,7 +241,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, minerReward.Add(minerReward, perOmmer) // Add (8-delta)/8 reward := big.NewInt(8) - reward.Sub(reward, big.NewInt(0).SetUint64(ommer.Delta)) + reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) reward.Mul(reward, blockReward) reward.Div(reward, big.NewInt(8)) statedb.AddBalance(ommer.Address, reward) diff --git a/consensus/ethash/consensus_test.go b/consensus/ethash/consensus_test.go index 6f6dc79fd..fb7f5f818 100644 --- a/consensus/ethash/consensus_test.go +++ b/consensus/ethash/consensus_test.go @@ -103,7 +103,7 @@ func TestDifficultyCalculators(t *testing.T) { for i := 0; i < 5000; i++ { // 1 to 300 seconds diff var timeDelta = uint64(1 + rand.Uint32()%3000) - diffBig := big.NewInt(0).SetBytes(randSlice(2, 10)) + diffBig := new(big.Int).SetBytes(randSlice(2, 10)) if diffBig.Cmp(params.MinimumDifficulty) < 0 { diffBig.Set(params.MinimumDifficulty) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index e0e6f9e03..c5cdfa78a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -2898,7 +2898,7 @@ func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) { numBlocks = 1 ) recipientFn := func(nonce uint64) common.Address { - return common.BigToAddress(big.NewInt(0).SetUint64(1337 + nonce)) + return common.BigToAddress(new(big.Int).SetUint64(1337 + nonce)) } dataFn := func(nonce uint64) []byte { return nil @@ -2915,7 +2915,7 @@ func BenchmarkBlockChain_1x1000ValueTransferToExisting(b *testing.B) { b.ResetTimer() recipientFn := func(nonce uint64) common.Address { - return common.BigToAddress(big.NewInt(0).SetUint64(1337)) + return common.BigToAddress(new(big.Int).SetUint64(1337)) } dataFn := func(nonce uint64) []byte { return nil @@ -2932,7 +2932,7 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { b.ResetTimer() recipientFn := func(nonce uint64) common.Address { - return common.BigToAddress(big.NewInt(0).SetUint64(0xc0de)) + return common.BigToAddress(new(big.Int).SetUint64(0xc0de)) } dataFn := func(nonce uint64) []byte { return nil diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index d7c01be1f..704ee3781 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1511,7 +1511,7 @@ type RPCTransaction struct { // newRPCTransaction returns a transaction that will serialize to the RPC // representation, with the given location metadata set (if available). func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { - signer := types.MakeSigner(config, big.NewInt(0).SetUint64(blockNumber)) + signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber)) from, _ := types.Sender(signer, tx) v, r, s := tx.RawSignatureValues() result := &RPCTransaction{ diff --git a/rlp/decode_test.go b/rlp/decode_test.go index babdf3891..192c0aa50 100644 --- a/rlp/decode_test.go +++ b/rlp/decode_test.go @@ -452,7 +452,7 @@ type ignoredField struct { var ( veryBigInt = new(big.Int).Add( - big.NewInt(0).Lsh(big.NewInt(0xFFFFFFFFFFFFFF), 16), + new(big.Int).Lsh(big.NewInt(0xFFFFFFFFFFFFFF), 16), big.NewInt(0xFFFF), ) veryVeryBigInt = new(big.Int).Exp(veryBigInt, big.NewInt(8), nil) diff --git a/rlp/encode_test.go b/rlp/encode_test.go index 1d715e377..df02add99 100644 --- a/rlp/encode_test.go +++ b/rlp/encode_test.go @@ -120,15 +120,15 @@ var encTests = []encTest{ {val: big.NewInt(0xFFFFFFFFFFFF), output: "86FFFFFFFFFFFF"}, {val: big.NewInt(0xFFFFFFFFFFFFFF), output: "87FFFFFFFFFFFFFF"}, { - val: big.NewInt(0).SetBytes(unhex("102030405060708090A0B0C0D0E0F2")), + val: new(big.Int).SetBytes(unhex("102030405060708090A0B0C0D0E0F2")), output: "8F102030405060708090A0B0C0D0E0F2", }, { - val: big.NewInt(0).SetBytes(unhex("0100020003000400050006000700080009000A000B000C000D000E01")), + val: new(big.Int).SetBytes(unhex("0100020003000400050006000700080009000A000B000C000D000E01")), output: "9C0100020003000400050006000700080009000A000B000C000D000E01", }, { - val: big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000")), + val: new(big.Int).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000")), output: "A1010000000000000000000000000000000000000000000000000000000000000000", }, { diff --git a/signer/core/api_test.go b/signer/core/api_test.go index 9f44ca319..990c4bc03 100644 --- a/signer/core/api_test.go +++ b/signer/core/api_test.go @@ -63,7 +63,7 @@ func (ui *headlessUi) ApproveTx(request *core.SignTxRequest) (core.SignTxRespons case "M": // modify // The headless UI always modifies the transaction old := big.Int(request.Transaction.Value) - newVal := big.NewInt(0).Add(&old, big.NewInt(1)) + newVal := new(big.Int).Add(&old, big.NewInt(1)) request.Transaction.Value = hexutil.Big(*newVal) return core.SignTxResponse{request.Transaction, true}, nil default: diff --git a/signer/fourbyte/validation_test.go b/signer/fourbyte/validation_test.go index c3085696f..2e6d9f2d9 100644 --- a/signer/fourbyte/validation_test.go +++ b/signer/fourbyte/validation_test.go @@ -29,11 +29,11 @@ func mixAddr(a string) (*common.MixedcaseAddress, error) { return common.NewMixedcaseAddressFromString(a) } func toHexBig(h string) hexutil.Big { - b := big.NewInt(0).SetBytes(common.FromHex(h)) + b := new(big.Int).SetBytes(common.FromHex(h)) return hexutil.Big(*b) } func toHexUint(h string) hexutil.Uint64 { - b := big.NewInt(0).SetBytes(common.FromHex(h)) + b := new(big.Int).SetBytes(common.FromHex(h)) return hexutil.Uint64(b.Uint64()) } func dummyTxArgs(t txtestcase) *apitypes.SendTxArgs { diff --git a/signer/rules/rules_test.go b/signer/rules/rules_test.go index 0ab246eea..af4ed2d7e 100644 --- a/signer/rules/rules_test.go +++ b/signer/rules/rules_test.go @@ -449,7 +449,7 @@ func dummyTx(value hexutil.Big) *core.SignTxRequest { } func dummyTxWithV(value uint64) *core.SignTxRequest { - v := big.NewInt(0).SetUint64(value) + v := new(big.Int).SetUint64(value) h := hexutil.Big(*v) return dummyTx(h) } @@ -469,7 +469,7 @@ func TestLimitWindow(t *testing.T) { return } // 0.3 ether: 429D069189E0000 wei - v := big.NewInt(0).SetBytes(common.Hex2Bytes("0429D069189E0000")) + v := new(big.Int).SetBytes(common.Hex2Bytes("0429D069189E0000")) h := hexutil.Big(*v) // The first three should succeed for i := 0; i < 3; i++ { From c93b90563380e168546c043214788dfec5a38b29 Mon Sep 17 00:00:00 2001 From: lwh Date: Tue, 7 Jun 2022 14:38:54 +0800 Subject: [PATCH 23/61] accounts/abi/bind: fix duplicate field names in the generated go struct (#24924) * accounts/abi/bind: fix duplicate field names in the generated go struct #24627 * accounts, cmd/abigen: resolve name conflicts * ci lint, accounts/abi: remove unused function overloadedArgName Co-authored-by: Gary Rong --- accounts/abi/abi.go | 23 +++----------- accounts/abi/bind/bind.go | 25 +++++++++++++-- accounts/abi/bind/bind_test.go | 48 +++++++++++++++++++++++++++++ accounts/abi/error.go | 6 ++-- accounts/abi/event.go | 7 +++-- accounts/abi/type.go | 56 +++++++++++++++++++++++----------- accounts/abi/utils.go | 41 +++++++++++++++++++++++++ cmd/abigen/main.go | 6 +++- 8 files changed, 168 insertions(+), 44 deletions(-) create mode 100644 accounts/abi/utils.go diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index cd2f4d797..ed5b6e92e 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -164,7 +164,7 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { case "constructor": abi.Constructor = NewMethod("", "", Constructor, field.StateMutability, field.Constant, field.Payable, field.Inputs, nil) case "function": - name := overloadedName(field.Name, func(s string) bool { _, ok := abi.Methods[s]; return ok }) + name := ResolveNameConflict(field.Name, func(s string) bool { _, ok := abi.Methods[s]; return ok }) abi.Methods[name] = NewMethod(name, field.Name, Function, field.StateMutability, field.Constant, field.Payable, field.Inputs, field.Outputs) case "fallback": // New introduced function type in v0.6.0, check more detail @@ -184,9 +184,11 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { } abi.Receive = NewMethod("", "", Receive, field.StateMutability, field.Constant, field.Payable, nil, nil) case "event": - name := overloadedName(field.Name, func(s string) bool { _, ok := abi.Events[s]; return ok }) + name := ResolveNameConflict(field.Name, func(s string) bool { _, ok := abi.Events[s]; return ok }) abi.Events[name] = NewEvent(name, field.Name, field.Anonymous, field.Inputs) case "error": + // Errors cannot be overloaded or overridden but are inherited, + // no need to resolve the name conflict here. abi.Errors[field.Name] = NewError(field.Name, field.Inputs) default: return fmt.Errorf("abi: could not recognize type %v of field %v", field.Type, field.Name) @@ -251,20 +253,3 @@ func UnpackRevert(data []byte) (string, error) { } return unpacked[0].(string), nil } - -// overloadedName returns the next available name for a given thing. -// Needed since solidity allows for overloading. -// -// e.g. if the abi contains Methods send, send1 -// overloadedName would return send2 for input send. -// -// overloadedName works for methods, events and errors. -func overloadedName(rawName string, isAvail func(string) bool) string { - name := rawName - ok := isAvail(name) - for idx := 0; ok; idx++ { - name = fmt.Sprintf("%s%d", rawName, idx) - ok = isAvail(name) - } - return name -} diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index ff69a78c6..2b02a6344 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -99,6 +99,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] // Normalize the method for capital cases and non-anonymous inputs/outputs normalized := original normalizedName := methodNormalizer[lang](alias(aliases, original.Name)) + // Ensure there is no duplicated identifier var identifiers = callIdentifiers if !original.IsConstant() { @@ -108,6 +109,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName) } identifiers[normalizedName] = true + normalized.Name = normalizedName normalized.Inputs = make([]abi.Argument, len(original.Inputs)) copy(normalized.Inputs, original.Inputs) @@ -152,12 +154,22 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] eventIdentifiers[normalizedName] = true normalized.Name = normalizedName + used := make(map[string]bool) normalized.Inputs = make([]abi.Argument, len(original.Inputs)) copy(normalized.Inputs, original.Inputs) for j, input := range normalized.Inputs { if input.Name == "" { normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) } + // Event is a bit special, we need to define event struct in binding, + // ensure there is no camel-case-style name conflict. + for index := 0; ; index++ { + if !used[capitalise(normalized.Inputs[j].Name)] { + used[capitalise(normalized.Inputs[j].Name)] = true + break + } + normalized.Inputs[j].Name = fmt.Sprintf("%s%d", normalized.Inputs[j].Name, index) + } if hasStruct(input.Type) { bindStructType[lang](input.Type, structs) } @@ -432,15 +444,22 @@ func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string { if s, exist := structs[id]; exist { return s.Name } - var fields []*tmplField + var ( + names = make(map[string]bool) + fields []*tmplField + ) for i, elem := range kind.TupleElems { - field := bindStructTypeGo(*elem, structs) - fields = append(fields, &tmplField{Type: field, Name: capitalise(kind.TupleRawNames[i]), SolKind: *elem}) + name := capitalise(kind.TupleRawNames[i]) + name = abi.ResolveNameConflict(name, func(s string) bool { return names[s] }) + names[name] = true + fields = append(fields, &tmplField{Type: bindStructTypeGo(*elem, structs), Name: name, SolKind: *elem}) } name := kind.TupleRawName if name == "" { name = fmt.Sprintf("Struct%d", len(structs)) } + name = capitalise(name) + structs[id] = &tmplStruct{ Name: name, Fields: fields, diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 6b72cc456..03d760076 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -1949,6 +1949,54 @@ var bindTests = []struct { } sim.Commit() + if _, err = bind.WaitDeployed(nil, sim, tx); err != nil { + t.Logf("Deployment tx: %+v", tx) + t.Errorf("bind.WaitDeployed(nil, %T, ) got err %v; want nil err", sim, err) + } + `, + }, + { + name: `NameConflict`, + contract: ` + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.4.22 <0.9.0; + contract oracle { + struct request { + bytes data; + bytes _data; + } + event log (int msg, int _msg); + function addRequest(request memory req) public pure {} + function getRequest() pure public returns (request memory) { + return request("", ""); + } + } + `, + bytecode: []string{`0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033`}, + abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`}, + imports: ` + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/ethconfig" + `, + tester: ` + var ( + key, _ = crypto.GenerateKey() + user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) + sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil) + ) + defer sim.Close() + + _, tx, _, err := DeployNameConflict(user, sim) + if err != nil { + t.Fatalf("DeployNameConflict() got err %v; want nil err", err) + } + sim.Commit() + if _, err = bind.WaitDeployed(nil, sim, tx); err != nil { t.Logf("Deployment tx: %+v", tx) t.Errorf("bind.WaitDeployed(nil, %T, ) got err %v; want nil err", sim, err) diff --git a/accounts/abi/error.go b/accounts/abi/error.go index 3d1a4877d..f2c44d2de 100644 --- a/accounts/abi/error.go +++ b/accounts/abi/error.go @@ -30,11 +30,13 @@ type Error struct { Name string Inputs Arguments str string + // Sig contains the string signature according to the ABI spec. - // e.g. event foo(uint32 a, int b) = "foo(uint32,int256)" + // e.g. error foo(uint32 a, int b) = "foo(uint32,int256)" // Please note that "int" is substitute for its canonical representation "int256" Sig string - // ID returns the canonical representation of the event's signature used by the + + // ID returns the canonical representation of the error's signature used by the // abi definition to identify event names and types. ID common.Hash } diff --git a/accounts/abi/event.go b/accounts/abi/event.go index b238a36d7..f9457b86a 100644 --- a/accounts/abi/event.go +++ b/accounts/abi/event.go @@ -29,24 +29,27 @@ import ( // don't get the signature canonical representation as the first LOG topic. type Event struct { // Name is the event name used for internal representation. It's derived from - // the raw name and a suffix will be added in the case of a event overload. + // the raw name and a suffix will be added in the case of event overloading. // // e.g. // These are two events that have the same name: // * foo(int,int) // * foo(uint,uint) - // The event name of the first one wll be resolved as foo while the second one + // The event name of the first one will be resolved as foo while the second one // will be resolved as foo0. Name string + // RawName is the raw event name parsed from ABI. RawName string Anonymous bool Inputs Arguments str string + // Sig contains the string signature according to the ABI spec. // e.g. event foo(uint32 a, int b) = "foo(uint32,int256)" // Please note that "int" is substitute for its canonical representation "int256" Sig string + // ID returns the canonical representation of the event's signature used by the // abi definition to identify event names and types. ID common.Hash diff --git a/accounts/abi/type.go b/accounts/abi/type.go index ffa3acafe..7d4e63083 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -23,6 +23,8 @@ import ( "regexp" "strconv" "strings" + "unicode" + "unicode/utf8" "github.com/ethereum/go-ethereum/common" ) @@ -161,19 +163,26 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty elems []*Type names []string expression string // canonical parameter expression + used = make(map[string]bool) ) expression += "(" - overloadedNames := make(map[string]string) for idx, c := range components { cType, err := NewType(c.Type, c.InternalType, c.Components) if err != nil { return Type{}, err } - fieldName, err := overloadedArgName(c.Name, overloadedNames) + name := ToCamelCase(c.Name) + if name == "" { + return Type{}, errors.New("abi: purely anonymous or underscored field is not supported") + } + fieldName := ResolveNameConflict(name, func(s string) bool { return used[s] }) if err != nil { return Type{}, err } - overloadedNames[fieldName] = fieldName + used[fieldName] = true + if !isValidFieldName(fieldName) { + return Type{}, fmt.Errorf("field %d has invalid name", idx) + } fields = append(fields, reflect.StructField{ Name: fieldName, // reflect.StructOf will panic for any exported field. Type: cType.GetType(), @@ -250,20 +259,6 @@ func (t Type) GetType() reflect.Type { } } -func overloadedArgName(rawName string, names map[string]string) (string, error) { - fieldName := ToCamelCase(rawName) - if fieldName == "" { - return "", errors.New("abi: purely anonymous or underscored field is not supported") - } - // Handle overloaded fieldNames - _, ok := names[fieldName] - for idx := 0; ok; idx++ { - fieldName = fmt.Sprintf("%s%d", ToCamelCase(rawName), idx) - _, ok = names[fieldName] - } - return fieldName, nil -} - // String implements Stringer. func (t Type) String() (out string) { return t.stringKind @@ -399,3 +394,30 @@ func getTypeSize(t Type) int { } return 32 } + +// isLetter reports whether a given 'rune' is classified as a Letter. +// This method is copied from reflect/type.go +func isLetter(ch rune) bool { + return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch) +} + +// isValidFieldName checks if a string is a valid (struct) field name or not. +// +// According to the language spec, a field name should be an identifier. +// +// identifier = letter { letter | unicode_digit } . +// letter = unicode_letter | "_" . +// This method is copied from reflect/type.go +func isValidFieldName(fieldName string) bool { + for i, c := range fieldName { + if i == 0 && !isLetter(c) { + return false + } + + if !(isLetter(c) || unicode.IsDigit(c)) { + return false + } + } + + return len(fieldName) > 0 +} diff --git a/accounts/abi/utils.go b/accounts/abi/utils.go new file mode 100644 index 000000000..e24df5b70 --- /dev/null +++ b/accounts/abi/utils.go @@ -0,0 +1,41 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package abi + +import "fmt" + +// ResolveNameConflict returns the next available name for a given thing. +// This helper can be used for lots of purposes: +// +// - In solidity function overloading is supported, this function can fix +// the name conflicts of overloaded functions. +// - In golang binding generation, the parameter(in function, event, error, +// and struct definition) name will be converted to camelcase style which +// may eventually lead to name conflicts. +// +// Name conflicts are mostly resolved by adding number suffix. +// e.g. if the abi contains Methods send, send1 +// ResolveNameConflict would return send2 for input send. +func ResolveNameConflict(rawName string, used func(string) bool) string { + name := rawName + ok := used(name) + for idx := 0; ok; idx++ { + name = fmt.Sprintf("%s%d", rawName, idx) + ok = used(name) + } + return name +} diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index 7b3b35e4e..9547101ef 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -237,7 +237,11 @@ func abigen(c *cli.Context) error { nameParts := strings.Split(name, ":") types = append(types, nameParts[len(nameParts)-1]) - libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] + // Derive the library placeholder which is a 34 character prefix of the + // hex encoding of the keccak256 hash of the fully qualified library name. + // Note that the fully qualified library name is the path of its source + // file and the library name separated by ":". + libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] // the first 2 chars are 0x libs[libPattern] = nameParts[len(nameParts)-1] } } From caf9d0a5e6541b91c90fc5b0c246147ce4ff0fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Anda=20Estensen?= Date: Tue, 7 Jun 2022 17:27:21 +0200 Subject: [PATCH 24/61] p2p: use errors.Is for error comparison (#24882) Co-authored-by: Felix Lange --- p2p/discover/lookup.go | 3 ++- p2p/discover/v4_udp.go | 4 ++-- p2p/discover/v5_udp.go | 4 ++-- p2p/discover/v5wire/encoding.go | 2 +- p2p/dnsdisc/client.go | 5 +++-- p2p/enr/entries.go | 12 ++++++++++-- p2p/peer.go | 2 +- p2p/peer_error.go | 2 +- p2p/simulations/http.go | 3 ++- 9 files changed, 24 insertions(+), 13 deletions(-) diff --git a/p2p/discover/lookup.go b/p2p/discover/lookup.go index f6f125d94..4aa3e8889 100644 --- a/p2p/discover/lookup.go +++ b/p2p/discover/lookup.go @@ -18,6 +18,7 @@ package discover import ( "context" + "errors" "time" "github.com/ethereum/go-ethereum/common/gopool" @@ -144,7 +145,7 @@ func (it *lookup) slowdown() { func (it *lookup) query(n *node, reply chan<- []*node) { fails := it.tab.db.FindFails(n.ID(), n.IP()) r, err := it.queryfunc(n) - if err == errClosed { + if errors.Is(err, errClosed) { // Avoid recording failures on shutdown. reply <- nil return diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 3d044f021..d743cc741 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -329,7 +329,7 @@ func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubke // enough nodes the reply matcher will time out waiting for the second reply, but // there's no need for an error in that case. err := <-rm.errc - if err == errTimeout && rm.reply != nil { + if errors.Is(err, errTimeout) && rm.reply != nil { err = nil } return nodes, err @@ -529,7 +529,7 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { continue } else if err != nil { // Shut down the loop for permament errors. - if err != io.EOF { + if !errors.Is(err, io.EOF) { t.log.Debug("UDP read error", "err", err) } return diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 71a39ea5a..1e9909559 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -305,7 +305,7 @@ func (t *UDPv5) lookupWorker(destNode *node, target enode.ID) ([]*node, error) { ) var r []*enode.Node r, err = t.findnode(unwrapNode(destNode), dists) - if err == errClosed { + if errors.Is(err, errClosed) { return nil, err } for _, n := range r { @@ -623,7 +623,7 @@ func (t *UDPv5) readLoop() { continue } else if err != nil { // Shut down the loop for permament errors. - if err != io.EOF { + if !errors.Is(err, io.EOF) { t.log.Debug("UDP read error", "err", err) } return diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index f502339e1..b5ed94187 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -596,7 +596,7 @@ func (c *Codec) decodeMessage(fromAddr string, head *Header, headerData, msgData // Try decrypting the message. key := c.sc.readKey(auth.SrcID, fromAddr) msg, err := c.decryptMessage(msgData, head.Nonce[:], headerData, key) - if err == errMessageDecrypt { + if errors.Is(err, errMessageDecrypt) { // It didn't work. Start the handshake since this is an ordinary message packet. return &Unknown{Nonce: head.Nonce}, nil } diff --git a/p2p/dnsdisc/client.go b/p2p/dnsdisc/client.go index 096df06a5..5aeb5a52f 100644 --- a/p2p/dnsdisc/client.go +++ b/p2p/dnsdisc/client.go @@ -19,6 +19,7 @@ package dnsdisc import ( "bytes" "context" + "errors" "fmt" "math/rand" "net" @@ -204,7 +205,7 @@ func (c *Client) doResolveEntry(ctx context.Context, domain, hash string) (entry } for _, txt := range txts { e, err := parseEntry(txt, c.cfg.ValidSchemes) - if err == errUnknownEntry { + if errors.Is(err, errUnknownEntry) { continue } if !bytes.HasPrefix(crypto.Keccak256([]byte(txt)), wantHash) { @@ -281,7 +282,7 @@ func (it *randomIterator) nextNode() *enode.Node { } n, err := ct.syncRandom(it.ctx) if err != nil { - if err == it.ctx.Err() { + if errors.Is(err, it.ctx.Err()) { return nil // context canceled. } it.c.cfg.Logger.Debug("Error in DNS random node sync", "tree", ct.loc.domain, "err", err) diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go index f2118401a..a8b0a3839 100644 --- a/p2p/enr/entries.go +++ b/p2p/enr/entries.go @@ -17,6 +17,7 @@ package enr import ( + "errors" "fmt" "io" "net" @@ -180,9 +181,16 @@ func (err *KeyError) Error() string { return fmt.Sprintf("ENR key %q: %v", err.Key, err.Err) } +func (err *KeyError) Unwrap() error { + return err.Err +} + // IsNotFound reports whether the given error means that a key/value pair is // missing from a record. func IsNotFound(err error) bool { - kerr, ok := err.(*KeyError) - return ok && kerr.Err == errNotFound + var ke *KeyError + if errors.As(err, &ke) { + return ke.Err == errNotFound + } + return false } diff --git a/p2p/peer.go b/p2p/peer.go index 144a32e7d..84efde6a4 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -434,7 +434,7 @@ func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) if err == nil { p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version)) err = errProtocolReturned - } else if err != io.EOF { + } else if !errors.Is(err, io.EOF) { p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err) } p.protoErr <- err diff --git a/p2p/peer_error.go b/p2p/peer_error.go index 302868504..ebc59de25 100644 --- a/p2p/peer_error.go +++ b/p2p/peer_error.go @@ -103,7 +103,7 @@ func discReasonForError(err error) DiscReason { if reason, ok := err.(DiscReason); ok { return reason } - if err == errProtocolReturned { + if errors.Is(err, errProtocolReturned) { return DiscQuitting } peerError, ok := err.(*peerError) diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go index 45c12f743..16aeb4a15 100644 --- a/p2p/simulations/http.go +++ b/p2p/simulations/http.go @@ -21,6 +21,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "html" "io" @@ -560,7 +561,7 @@ func (s *Server) CreateNode(w http.ResponseWriter, req *http.Request) { config := &adapters.NodeConfig{} err := json.NewDecoder(req.Body).Decode(config) - if err != nil && err != io.EOF { + if err != nil && !errors.Is(err, io.EOF) { http.Error(w, err.Error(), http.StatusBadRequest) return } From c46671df97038edf83ddaef8eeeaa978f2a63d71 Mon Sep 17 00:00:00 2001 From: Jolly Zhao Date: Thu, 20 Oct 2022 01:45:32 +0800 Subject: [PATCH 25/61] parlia: the newChainHead mights not be imported to Pralia.Snapshot ASAP --- consensus/parlia/parlia.go | 6 +++--- miner/worker.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 33ed15a62..fee0fe129 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -929,8 +929,8 @@ func (p *Parlia) IsLocalBlock(header *types.Header) bool { return p.val == header.Coinbase } -func (p *Parlia) SignRecently(chain consensus.ChainReader, parent *types.Header) (bool, error) { - snap, err := p.snapshot(chain, parent.Number.Uint64(), parent.ParentHash, nil) +func (p *Parlia) SignRecently(chain consensus.ChainReader, parent *types.Block) (bool, error) { + snap, err := p.snapshot(chain, parent.NumberU64(), parent.Hash(), nil) if err != nil { return true, err } @@ -941,7 +941,7 @@ func (p *Parlia) SignRecently(chain consensus.ChainReader, parent *types.Header) } // If we're amongst the recent signers, wait for the next block - number := parent.Number.Uint64() + 1 + number := parent.NumberU64() + 1 for seen, recent := range snap.Recents { if recent == p.val { // Signer is among recents, only wait if the current block doesn't shift it out diff --git a/miner/worker.go b/miner/worker.go index 7a7eaf14c..5577a5c05 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -470,7 +470,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { clearPending(head.Block.NumberU64()) timestamp = time.Now().Unix() if p, ok := w.engine.(*parlia.Parlia); ok { - signedRecent, err := p.SignRecently(w.chain, head.Block.Header()) + signedRecent, err := p.SignRecently(w.chain, head.Block) if err != nil { log.Info("Not allowed to propose block", "err", err) continue From bed1a57766cd91c8db2a4aba8dcf03d364a09802 Mon Sep 17 00:00:00 2001 From: Leon <316032931@qq.com> Date: Mon, 31 Oct 2022 14:03:45 +0800 Subject: [PATCH 26/61] core:remove redundant func (#1159) --- core/block_validator.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index e710d7469..de82d0702 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -86,12 +86,6 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { } validateFuns := []func() error{ - func() error { - if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) { - return ErrKnownBlock - } - return nil - }, func() error { if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash { return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash) From 72f6acc49f825bfa235bf5e47f323cc45980384d Mon Sep 17 00:00:00 2001 From: Kai Date: Mon, 31 Oct 2022 15:04:13 +0800 Subject: [PATCH 27/61] ci: specify bind-tools version (#1126) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index fa1044326..08b480346 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,7 @@ ENV HOME=${BSC_HOME} ENV DATA_DIR=/data ENV PACKAGES ca-certificates~=20220614 jq~=1.6 \ - bash~=5.1.16-r2 bind-tools tini~=0.19.0 \ + bash~=5.1.16-r2 bind-tools~=9.16.33 tini~=0.19.0 \ grep~=3.7 curl~=7.83.1-r2 sed~=4.8-r0 curl~=7.83 RUN apk add --no-cache $PACKAGES \ From 8b7b87c23217191b16c81e9a90da9097053d6c96 Mon Sep 17 00:00:00 2001 From: Leon <316032931@qq.com> Date: Wed, 2 Nov 2022 16:47:14 +0800 Subject: [PATCH 28/61] release: update version and changelogs (#1161) --- CHANGELOG.md | 17 +++++++++++++++++ cmd/utils/flags.go | 6 ++---- params/version.go | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca749d5e6..f52d48670 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,23 @@ # Changelog +## v1.1.17 +IMPROVEMENT + +* [\#1114](https://github.com/bnb-chain/bsc/pull/1114) typo: .github fix job name +* [\#1126](https://github.com/bnb-chain/bsc/pull/1126) ci: specify bind-tools version +* [\#1140](https://github.com/bnb-chain/bsc/pull/1140) p2p: upstream go-ethereum: use errors.Is for error comparison +* [\#1141](https://github.com/bnb-chain/bsc/pull/1141) all: prefer new(big.Int) over big.NewInt(0) +* [\#1159](https://github.com/bnb-chain/bsc/pull/1159) core: remove redundant func + +BUGFIX + +* [\#1138](https://github.com/bnb-chain/bsc/pull/1138) fix: upstream patches from go-ethereum 1.10.19 +* [\#1139](https://github.com/bnb-chain/bsc/pull/1139) fix: upstream go-ethereum: fix duplicate fields names in the generted go struct +* [\#1145](https://github.com/bnb-chain/bsc/pull/1145) consensus: the newChainHead mights not be imported to Parlia.Snapshot +* [\#1146](https://github.com/bnb-chain/bsc/pull/1146) fix: upstream patches from go-ethereum 1.10.20 + ## v1.1.16 + * [\#1121](https://github.com/bnb-chain/bsc/pull/1121) vm: add two proof verifier to fix the vulnerability in range proof ## v1.1.15 diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5a9dd0697..c48c1bcfc 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -975,10 +975,8 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { urls = params.RinkebyBootnodes case ctx.GlobalBool(GoerliFlag.Name): urls = params.GoerliBootnodes - } - // don't apply defaults if BootstrapNodes is already set - if cfg.BootstrapNodes != nil { - return + case cfg.BootstrapNodes != nil: + return // already set, don't apply defaults. } cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls)) for _, url := range urls { diff --git a/params/version.go b/params/version.go index a1d2e8bde..cb4ddea21 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 16 // Patch version component of the current release + VersionPatch = 17 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From fa563982cd3b210d4dde0996334e337dcf79627a Mon Sep 17 00:00:00 2001 From: j75689 Date: Wed, 2 Nov 2022 19:55:42 +0800 Subject: [PATCH 29/61] docker: fix dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 02d8f52bc..6a049c1f3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,7 +28,7 @@ ENV DATA_DIR=/data ENV PACKAGES ca-certificates~=20220614-r0 jq~=1.6 \ bash~=5.1.16-r2 bind-tools~=9.16.33 tini~=0.19.0 \ - grep~=3.7 curl=~7.83.1-r3 sed~=4.8-r0 + grep~=3.7 curl~=7.83.1 sed~=4.8-r0 RUN apk add --no-cache $PACKAGES \ && rm -rf /var/cache/apk/* \ From 01b78d47897cbdffe5fbe72cbf22979b7c7329b6 Mon Sep 17 00:00:00 2001 From: Leon <316032931@qq.com> Date: Mon, 7 Nov 2022 10:42:05 +0800 Subject: [PATCH 30/61] miner: disable enforceTip when get txs from txpool (#1166) --- miner/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index dca827f6d..32d8dbd72 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1109,7 +1109,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { func (w *worker) fillTransactions(interrupt *int32, env *environment) { // Split the pending transactions into locals and remotes // Fill the block with all available pending transactions. - pending := w.eth.TxPool().Pending(true) + pending := w.eth.TxPool().Pending(false) localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending for _, account := range w.eth.TxPool().Locals() { if txs := remoteTxs[account]; len(txs) > 0 { From c2c22c59470c4749485b2e0df4e2e93911209c1c Mon Sep 17 00:00:00 2001 From: henridf Date: Thu, 14 Jul 2022 14:55:54 +0200 Subject: [PATCH 31/61] core: remove lock in BlockChain.ExportN (#25254) * Remove locking in (*BlockChain).ExportN Since ExportN is read-only, it shouldn't need the lock. (?) * Add hash check to detect reorgs during export. * fix check order * Update blockchain.go * Update blockchain.go Co-authored-by: rjl493456442 --- core/blockchain.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 572b80bab..96bdac890 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -898,22 +898,25 @@ func (bc *BlockChain) Export(w io.Writer) error { // ExportN writes a subset of the active chain to the given writer. func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error { - if !bc.chainmu.TryLock() { - return errChainStopped - } - defer bc.chainmu.Unlock() - if first > last { return fmt.Errorf("export failed: first (%d) is greater than last (%d)", first, last) } log.Info("Exporting batch of blocks", "count", last-first+1) - start, reported := time.Now(), time.Now() + var ( + parentHash common.Hash + start = time.Now() + reported = time.Now() + ) for nr := first; nr <= last; nr++ { block := bc.GetBlockByNumber(nr) if block == nil { return fmt.Errorf("export failed on #%d: not found", nr) } + if nr > first && block.ParentHash() != parentHash { + return fmt.Errorf("export failed: chain reorg during export") + } + parentHash = block.Hash() if err := block.EncodeRLP(w); err != nil { return err } From e91c40ddefead31da2764d7d2f45fcb024885539 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 14 Jul 2022 04:17:25 -0600 Subject: [PATCH 32/61] internal/ethapi: error if tx args includes chain id that doesn't match local (#25157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * internal/ethapi: error if tx args includes chain id that doesn't match local * internal/ethapi: simplify code a bit Co-authored-by: Péter Szilágyi --- internal/ethapi/transaction_args.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 201479ccc..928443916 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -165,9 +165,15 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error { args.Gas = &estimated log.Trace("Estimate gas usage automatically", "gas", args.Gas) } - if args.ChainID == nil { - id := (*hexutil.Big)(b.ChainConfig().ChainID) - args.ChainID = id + // If chain id is provided, ensure it matches the local chain id. Otherwise, set the local + // chain id as the default. + want := b.ChainConfig().ChainID + if args.ChainID != nil { + if have := (*big.Int)(args.ChainID); have.Cmp(want) != 0 { + return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, want) + } + } else { + args.ChainID = (*hexutil.Big)(want) } return nil } From 0f96641ae4a58214ef7aee96480a58f6e009aea7 Mon Sep 17 00:00:00 2001 From: "Seungbae.yu" <72970043+dbadoy@users.noreply.github.com> Date: Tue, 12 Jul 2022 16:08:45 +0900 Subject: [PATCH 33/61] core, eth: pre-allocate map in storage copy (#25279) --- core/state/state_object.go | 2 +- eth/tracers/logger/logger.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index fc89a4f90..1ede96ec6 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -50,7 +50,7 @@ func (s Storage) String() (str string) { } func (s Storage) Copy() Storage { - cpy := make(Storage) + cpy := make(Storage, len(s)) for key, value := range s { cpy[key] = value } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index c4dec9f36..aea44801d 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -40,7 +40,7 @@ type Storage map[common.Hash]common.Hash // Copy duplicates the current storage. func (s Storage) Copy() Storage { - cpy := make(Storage) + cpy := make(Storage, len(s)) for key, value := range s { cpy[key] = value } From d07a706affdab14d934dcaf7f31c6327504bc2e5 Mon Sep 17 00:00:00 2001 From: Brion <4777457+cifer76@users.noreply.github.com> Date: Sat, 9 Jul 2022 03:25:12 +0800 Subject: [PATCH 34/61] rpc: add graceful shutdown timeout for HTTP server (#25258) This change ensures the HTTP server will always terminate within at most 5s, even when all connections are busy and do not become idle. Co-authored-by: Felix Lange --- node/rpcstack.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/node/rpcstack.go b/node/rpcstack.go index 30957c46d..80dbd87a7 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -28,6 +28,7 @@ import ( "strings" "sync" "sync/atomic" + "time" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" @@ -80,6 +81,10 @@ type httpServer struct { handlerNames map[string]string } +const ( + shutdownTimeout = 5 * time.Second +) + func newHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *httpServer { h := &httpServer{log: log, timeouts: timeouts, handlerNames: make(map[string]string)} @@ -260,7 +265,13 @@ func (h *httpServer) doStop() { h.wsHandler.Store((*rpcHandler)(nil)) wsHandler.server.Stop() } - h.server.Shutdown(context.Background()) + ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout) + defer cancel() + err := h.server.Shutdown(ctx) + if err == ctx.Err() { + h.log.Warn("HTTP server graceful shutdown timed out") + h.server.Close() + } h.listener.Close() h.log.Info("HTTP server stopped", "endpoint", h.listener.Addr()) From bf1dbd923338ce9c2a27f5cc25d2a4c91c67b53a Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 19 Jul 2022 11:44:48 +0200 Subject: [PATCH 35/61] accounts/abi: substitude arg%d to the range keyword (#25307) * accounts/abi: substitude arg%d to the range keyword * support more keywords * review feedback --- accounts/abi/bind/bind.go | 41 ++++++++++++++++++++++++++++++++-- accounts/abi/bind/bind_test.go | 39 +++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index 2b02a6344..afad15e56 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -43,6 +43,43 @@ const ( LangObjC ) +func isKeyWord(arg string) bool { + switch arg { + case "break": + case "case": + case "chan": + case "const": + case "continue": + case "default": + case "defer": + case "else": + case "fallthrough": + case "for": + case "func": + case "go": + case "goto": + case "if": + case "import": + case "interface": + case "iota": + case "map": + case "make": + case "new": + case "package": + case "range": + case "return": + case "select": + case "struct": + case "switch": + case "type": + case "var": + default: + return false + } + + return true +} + // Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant // to be used as is in client code, but rather as an intermediate struct which // enforces compile time type safety and naming convention opposed to having to @@ -114,7 +151,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] normalized.Inputs = make([]abi.Argument, len(original.Inputs)) copy(normalized.Inputs, original.Inputs) for j, input := range normalized.Inputs { - if input.Name == "" { + if input.Name == "" || isKeyWord(input.Name) { normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) } if hasStruct(input.Type) { @@ -158,7 +195,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string] normalized.Inputs = make([]abi.Argument, len(original.Inputs)) copy(normalized.Inputs, original.Inputs) for j, input := range normalized.Inputs { - if input.Name == "" { + if input.Name == "" || isKeyWord(input.Name) { normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j) } // Event is a bit special, we need to define event struct in binding, diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 866b7f184..926670575 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -1972,7 +1972,7 @@ var bindTests = []struct { } } `, - bytecode: []string{`0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033`}, + bytecode: []string{"0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033"}, abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`}, imports: ` "math/big" @@ -2003,6 +2003,43 @@ var bindTests = []struct { } `, }, + { + name: "RangeKeyword", + contract: ` + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.4.22 <0.9.0; + contract keywordcontract { + function functionWithKeywordParameter(range uint256) public pure {} + } + `, + bytecode: []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"}, + abi: []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`}, + imports: ` + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/ethconfig" + `, + tester: ` + var ( + key, _ = crypto.GenerateKey() + user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) + sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil) + ) + _, tx, _, err := DeployRangeKeyword(user, sim) + if err != nil { + t.Fatalf("error deploying contract: %v", err) + } + sim.Commit() + + if _, err = bind.WaitDeployed(nil, sim, tx); err != nil { + t.Errorf("error deploying the contract: %v", err) + } + `, + }, } // Tests that packages generated by the binder can be successfully compiled and From b4dcff5772d48e61cf783f41d2fb8dce8ce60236 Mon Sep 17 00:00:00 2001 From: setunapo Date: Thu, 10 Nov 2022 11:07:12 +0800 Subject: [PATCH 36/61] worker: remove the code of resubmit interval adjust resubmit intervalAdjust is for PoW only, to remove it to make worker simpler. With PoW, there will be a periodic timer to check if it is the time to stop packing transaction and start calculating the desired hash value, since other miner could succeed in hash compute if it spends too much time packing transactions. It will commit the current fruit to calculate root at a reasonable time. And it will schedule a new work to get a big block if new transaction was received. When there are too many transactions in the TxPool, the interval of the resubmit timer would be increased and vice versa. But it is not needed with PoS related consensus, since the block interval is determined in PoS, and there is already a timer to stop too long packing. --- miner/worker.go | 78 ------------------------------------ miner/worker_test.go | 95 -------------------------------------------- 2 files changed, 173 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 32d8dbd72..0838defdb 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -53,9 +53,6 @@ const ( // chainSideChanSize is the size of channel listening to ChainSideEvent. chainSideChanSize = 10 - // resubmitAdjustChanSize is the size of resubmitting interval adjustment channel. - resubmitAdjustChanSize = 10 - // sealingLogAtDepth is the number of confirmations before logging successful mining. sealingLogAtDepth = 11 @@ -63,18 +60,6 @@ const ( // any newly arrived transactions. minRecommitInterval = 1 * time.Second - // maxRecommitInterval is the maximum time interval to recreate the sealing block with - // any newly arrived transactions. - maxRecommitInterval = 15 * time.Second - - // intervalAdjustRatio is the impact a single interval adjustment has on sealing work - // resubmitting interval. - intervalAdjustRatio = 0.1 - - // intervalAdjustBias is applied during the new resubmit interval calculation in favor of - // increasing upper limit or decreasing lower limit so that the limit can be reachable. - intervalAdjustBias = 200 * 1000.0 * 1000.0 - // staleThreshold is the maximum depth of the acceptable stale block. staleThreshold = 11 ) @@ -177,12 +162,6 @@ type getWorkReq struct { result chan *types.Block } -// intervalAdjust represents a resubmitting interval adjustment. -type intervalAdjust struct { - ratio float64 - inc bool -} - // worker is the main object which takes care of submitting new work to consensus engine // and gathering the sealing result. type worker struct { @@ -213,7 +192,6 @@ type worker struct { startCh chan struct{} exitCh chan struct{} resubmitIntervalCh chan time.Duration - resubmitAdjustCh chan *intervalAdjust wg sync.WaitGroup @@ -279,7 +257,6 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus exitCh: make(chan struct{}), startCh: make(chan struct{}, 1), resubmitIntervalCh: make(chan time.Duration), - resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize), } // Subscribe NewTxsEvent for tx pool worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh) @@ -396,28 +373,6 @@ func (w *worker) close() { w.wg.Wait() } -// recalcRecommit recalculates the resubmitting interval upon feedback. -func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) time.Duration { - var ( - prevF = float64(prev.Nanoseconds()) - next float64 - ) - if inc { - next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias) - max := float64(maxRecommitInterval.Nanoseconds()) - if next > max { - next = max - } - } else { - next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias) - min := float64(minRecommit.Nanoseconds()) - if next < min { - next = min - } - } - return time.Duration(int64(next)) -} - // newWorkLoop is a standalone goroutine to submit new sealing work upon received events. func (w *worker) newWorkLoop(recommit time.Duration) { defer w.wg.Done() @@ -508,23 +463,6 @@ func (w *worker) newWorkLoop(recommit time.Duration) { w.resubmitHook(minRecommit, recommit) } - case adjust := <-w.resubmitAdjustCh: - // Adjust resubmit interval by feedback. - if adjust.inc { - before := recommit - target := float64(recommit.Nanoseconds()) / adjust.ratio - recommit = recalcRecommit(minRecommit, recommit, target, true) - log.Trace("Increase miner recommit interval", "from", before, "to", recommit) - } else { - before := recommit - recommit = recalcRecommit(minRecommit, recommit, float64(minRecommit.Nanoseconds()), false) - log.Trace("Decrease miner recommit interval", "from", before, "to", recommit) - } - - if w.resubmitHook != nil { - w.resubmitHook(minRecommit, recommit) - } - case <-w.exitCh: return } @@ -901,17 +839,6 @@ LOOP: // For the first two cases, the semi-finished work will be discarded. // For the third case, the semi-finished work will be submitted to the consensus engine. if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { - // Notify resubmit loop to increase resubmitting interval due to too frequent commits. - if atomic.LoadInt32(interrupt) == commitInterruptResubmit { - ratio := float64(gasLimit-env.gasPool.Gas()) / float64(gasLimit) - if ratio < 0.1 { - ratio = 0.1 - } - w.resubmitAdjustCh <- &intervalAdjust{ - ratio: ratio, - inc: true, - } - } return atomic.LoadInt32(interrupt) == commitInterruptNewHead } // If we don't have enough gas for any further transactions then we're done @@ -998,11 +925,6 @@ LOOP: } w.pendingLogsFeed.Send(cpy) } - // Notify resubmit loop to decrease resubmitting interval if current interval is larger - // than the user-specified one. - if interrupt != nil { - w.resubmitAdjustCh <- &intervalAdjust{inc: false} - } return false } diff --git a/miner/worker_test.go b/miner/worker_test.go index 2cdd4284e..e405788c6 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -20,7 +20,6 @@ import ( "errors" "math/big" "math/rand" - "sync/atomic" "testing" "time" @@ -270,100 +269,6 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) { } } -func TestAdjustIntervalEthash(t *testing.T) { - testAdjustInterval(t, ethashChainConfig, ethash.NewFaker()) -} - -func TestAdjustIntervalClique(t *testing.T) { - testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase())) -} - -func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) { - defer engine.Close() - - w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0) - defer w.close() - - w.skipSealHook = func(task *task) bool { - return true - } - w.fullTaskHook = func() { - time.Sleep(100 * time.Millisecond) - } - var ( - progress = make(chan struct{}, 10) - result = make([]float64, 0, 10) - index = 0 - start uint32 - ) - w.resubmitHook = func(minInterval time.Duration, recommitInterval time.Duration) { - // Short circuit if interval checking hasn't started. - if atomic.LoadUint32(&start) == 0 { - return - } - var wantMinInterval, wantRecommitInterval time.Duration - - switch index { - case 0: - wantMinInterval, wantRecommitInterval = 3*time.Second, 3*time.Second - case 1: - origin := float64(3 * time.Second.Nanoseconds()) - estimate := origin*(1-intervalAdjustRatio) + intervalAdjustRatio*(origin/0.8+intervalAdjustBias) - wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond - case 2: - estimate := result[index-1] - min := float64(3 * time.Second.Nanoseconds()) - estimate = estimate*(1-intervalAdjustRatio) + intervalAdjustRatio*(min-intervalAdjustBias) - wantMinInterval, wantRecommitInterval = 3*time.Second, time.Duration(estimate)*time.Nanosecond - case 3: - wantMinInterval, wantRecommitInterval = time.Second, time.Second - } - - // Check interval - if minInterval != wantMinInterval { - t.Errorf("resubmit min interval mismatch: have %v, want %v ", minInterval, wantMinInterval) - } - if recommitInterval != wantRecommitInterval { - t.Errorf("resubmit interval mismatch: have %v, want %v", recommitInterval, wantRecommitInterval) - } - result = append(result, float64(recommitInterval.Nanoseconds())) - index += 1 - progress <- struct{}{} - } - w.start() - - time.Sleep(time.Second) // Ensure two tasks have been summitted due to start opt - atomic.StoreUint32(&start, 1) - - w.setRecommitInterval(3 * time.Second) - select { - case <-progress: - case <-time.NewTimer(time.Second).C: - t.Error("interval reset timeout") - } - - w.resubmitAdjustCh <- &intervalAdjust{inc: true, ratio: 0.8} - select { - case <-progress: - case <-time.NewTimer(time.Second).C: - t.Error("interval reset timeout") - } - - w.resubmitAdjustCh <- &intervalAdjust{inc: false} - select { - case <-progress: - case <-time.NewTimer(time.Second).C: - t.Error("interval reset timeout") - } - - w.setRecommitInterval(500 * time.Millisecond) - select { - case <-progress: - case <-time.NewTimer(time.Second).C: - t.Error("interval reset timeout") - } -} - func TestGetSealingWorkEthash(t *testing.T) { testGetSealingWork(t, ethashChainConfig, ethash.NewFaker(), false) } From d1ed977d898479281d3eb2b2adbea8dd901ae515 Mon Sep 17 00:00:00 2001 From: setunapo Date: Thu, 10 Nov 2022 15:05:56 +0800 Subject: [PATCH 37/61] worker: change interrupt type from *int to chan channel operation is preferred than atomic value check in golang. And it will help for the further refactor on worker. --- miner/worker.go | 63 ++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 0838defdb..3e0d225f7 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -143,16 +143,15 @@ type task struct { } const ( - commitInterruptNone int32 = iota - commitInterruptNewHead - commitInterruptResubmit + commitInterruptNewHead int32 = 1 + commitInterruptResubmit int32 = 2 ) // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. type newWorkReq struct { - interrupt *int32 - noempty bool - timestamp int64 + interruptCh chan int32 + noempty bool + timestamp int64 } // getWorkReq represents a request for getting a new sealing work with provided parameters. @@ -377,7 +376,7 @@ func (w *worker) close() { func (w *worker) newWorkLoop(recommit time.Duration) { defer w.wg.Done() var ( - interrupt *int32 + interruptCh chan int32 minRecommit = recommit // minimal resubmit interval specified by user. timestamp int64 // timestamp for each round of sealing. ) @@ -387,13 +386,15 @@ func (w *worker) newWorkLoop(recommit time.Duration) { <-timer.C // discard the initial tick // commit aborts in-flight transaction execution with given signal and resubmits a new one. - commit := func(noempty bool, s int32) { - if interrupt != nil { - atomic.StoreInt32(interrupt, s) + commit := func(noempty bool, reason int32) { + if interruptCh != nil { + // each commit work will have its own interruptCh to stop work with a reason + interruptCh <- reason + close(interruptCh) } - interrupt = new(int32) + interruptCh = make(chan int32, 1) select { - case w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp}: + case w.newWorkCh <- &newWorkReq{interruptCh: interruptCh, noempty: noempty, timestamp: timestamp}: case <-w.exitCh: return } @@ -489,7 +490,7 @@ func (w *worker) mainLoop() { for { select { case req := <-w.newWorkCh: - w.commitWork(req.interrupt, req.noempty, req.timestamp) + w.commitWork(req.interruptCh, req.noempty, req.timestamp) case req := <-w.getWorkCh: block, err := w.generateWork(req.params) @@ -796,7 +797,7 @@ func (w *worker) commitTransaction(env *environment, tx *types.Transaction, rece return receipt.Logs, nil } -func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, interrupt *int32) bool { +func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, interruptCh chan int32) bool { gasLimit := env.header.GasLimit if env.gasPool == nil { env.gasPool = new(core.GasPool).AddGas(gasLimit) @@ -822,24 +823,32 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP } bloomProcessors := core.NewAsyncReceiptBloomGenerator(processorCapacity) - interruptCh := make(chan struct{}) - defer close(interruptCh) + stopPrefetchCh := make(chan struct{}) + defer close(stopPrefetchCh) //prefetch txs from all pending txs txsPrefetch := txs.Copy() tx := txsPrefetch.Peek() txCurr := &tx - w.prefetcher.PrefetchMining(txsPrefetch, env.header, env.gasPool.Gas(), env.state.CopyDoPrefetch(), *w.chain.GetVMConfig(), interruptCh, txCurr) + w.prefetcher.PrefetchMining(txsPrefetch, env.header, env.gasPool.Gas(), env.state.CopyDoPrefetch(), *w.chain.GetVMConfig(), stopPrefetchCh, txCurr) LOOP: for { // In the following three cases, we will interrupt the execution of the transaction. - // (1) new head block event arrival, the interrupt signal is 1 - // (2) worker start or restart, the interrupt signal is 1 - // (3) worker recreate the sealing block with any newly arrived transactions, the interrupt signal is 2. + // (1) new head block event arrival, the reason is 1 + // (2) worker start or restart, the reason is 1 + // (3) worker recreate the sealing block with any newly arrived transactions, the reason is 2. // For the first two cases, the semi-finished work will be discarded. // For the third case, the semi-finished work will be submitted to the consensus engine. - if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { - return atomic.LoadInt32(interrupt) == commitInterruptNewHead + if interruptCh != nil { + select { + case reason, ok := <-interruptCh: + if !ok { + // should never be here, since interruptCh should not be read before + log.Warn("commit transactions stopped unknown") + } + return reason == commitInterruptNewHead + default: + } } // If we don't have enough gas for any further transactions then we're done if env.gasPool.Gas() < params.TxGas { @@ -1028,7 +1037,7 @@ 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(interruptCh chan int32, env *environment) { // Split the pending transactions into locals and remotes // Fill the block with all available pending transactions. pending := w.eth.TxPool().Pending(false) @@ -1041,13 +1050,13 @@ func (w *worker) fillTransactions(interrupt *int32, env *environment) { } if len(localTxs) > 0 { txs := types.NewTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) - if w.commitTransactions(env, txs, interrupt) { + if w.commitTransactions(env, txs, interruptCh) { return } } if len(remoteTxs) > 0 { txs := types.NewTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee) - if w.commitTransactions(env, txs, interrupt) { + if w.commitTransactions(env, txs, interruptCh) { return } } @@ -1068,7 +1077,7 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, error) { // 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(interruptCh chan int32, noempty bool, timestamp int64) { start := time.Now() // Set the coinbase if the worker is running or it's required @@ -1094,7 +1103,7 @@ func (w *worker) commitWork(interrupt *int32, noempty bool, timestamp int64) { w.commit(work, nil, false, start) } // Fill pending transactions from the txpool - w.fillTransactions(interrupt, work) + w.fillTransactions(interruptCh, work) w.commit(work, w.fullTaskHook, true, start) // Swap out the old work with the new one, terminating any leftover From fe1c8622f6d1c35815bcbe199f451911ba2ec0f8 Mon Sep 17 00:00:00 2001 From: setunapo Date: Tue, 15 Nov 2022 15:42:29 +0800 Subject: [PATCH 38/61] parlia: Delay() with DelayLeftOver Right now, DelayLeftOver is used to reserve time for block finalize, not block broadcast. And the code does not work as expected. The general block generation could be described as: |- fillTransactions -|- finalize a block -|- wait until the period(3s) reached -|- broadcast -| --- cmd/utils/flags.go | 2 +- consensus/beacon/consensus.go | 2 +- consensus/clique/clique.go | 2 +- consensus/consensus.go | 2 +- consensus/ethash/consensus.go | 2 +- consensus/parlia/parlia.go | 14 +++++++++++++- miner/miner.go | 2 +- miner/worker.go | 25 ++++++++++++++----------- 8 files changed, 33 insertions(+), 18 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index c48c1bcfc..cb6741bac 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -548,7 +548,7 @@ var ( } MinerDelayLeftoverFlag = cli.DurationFlag{ Name: "miner.delayleftover", - Usage: "Time interval to for broadcast block", + Usage: "Time reserved to finalize a block", Value: ethconfig.Defaults.Miner.DelayLeftOver, } MinerNoVerfiyFlag = cli.BoolFlag{ diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index cd493f3d6..8282ed7cb 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -264,7 +264,7 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H return nil } -func (beacon *Beacon) Delay(_ consensus.ChainReader, _ *types.Header) *time.Duration { +func (beacon *Beacon) Delay(_ consensus.ChainReader, _ *types.Header, _ *time.Duration) *time.Duration { return nil } diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 75ed916a8..a258f1fe5 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -591,7 +591,7 @@ func (c *Clique) Authorize(signer common.Address, signFn SignerFn) { c.signFn = signFn } -func (c *Clique) Delay(chain consensus.ChainReader, header *types.Header) *time.Duration { +func (c *Clique) Delay(chain consensus.ChainReader, header *types.Header, leftOver *time.Duration) *time.Duration { return nil } diff --git a/consensus/consensus.go b/consensus/consensus.go index c3e7b4870..87632a9d0 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -126,7 +126,7 @@ type Engine interface { APIs(chain ChainHeaderReader) []rpc.API // Delay returns the max duration the miner can commit txs - Delay(chain ChainReader, header *types.Header) *time.Duration + Delay(chain ChainReader, header *types.Header, leftOver *time.Duration) *time.Duration // Close terminates any background threads maintained by the consensus engine. Close() error diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index be6085c71..12a69c127 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -610,7 +610,7 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), receipts, nil } -func (ethash *Ethash) Delay(_ consensus.ChainReader, _ *types.Header) *time.Duration { +func (ethash *Ethash) Delay(_ consensus.ChainReader, _ *types.Header, _ *time.Duration) *time.Duration { return nil } diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index fee0fe129..2e544803e 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -793,13 +793,25 @@ func (p *Parlia) Authorize(val common.Address, signFn SignerFn, signTxFn SignerT p.signTxFn = signTxFn } -func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header) *time.Duration { +// Argument leftOver is the time reserved for block finalize(calculate root, distribute income...) +func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOver *time.Duration) *time.Duration { number := header.Number.Uint64() snap, err := p.snapshot(chain, number-1, header.ParentHash, nil) if err != nil { return nil } delay := p.delayForRamanujanFork(snap, header) + + if *leftOver >= time.Duration(p.config.Period)*time.Second { + // ignore invalid leftOver + log.Error("Delay invalid argument", "leftOver", leftOver.String(), "Period", p.config.Period) + } else if *leftOver >= delay { + delay = time.Duration(0) + return &delay + } else { + delay = delay - *leftOver + } + // The blocking time should be no more than half of period half := time.Duration(p.config.Period) * time.Second / 2 if delay > half { diff --git a/miner/miner.go b/miner/miner.go index 4b20599d6..0ea2c0ea1 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -48,7 +48,7 @@ type Config struct { Notify []string `toml:",omitempty"` // HTTP URL list to be notified of new work packages (only useful in ethash). NotifyFull bool `toml:",omitempty"` // Notify with pending block headers instead of work packages ExtraData hexutil.Bytes `toml:",omitempty"` // Block extra data set by the miner - DelayLeftOver time.Duration // Time for broadcast block + DelayLeftOver time.Duration // Time reserved to finalize a block(calculate root, distribute income...) GasFloor uint64 // Target gas floor for mined blocks. GasCeil uint64 // Target gas ceiling for mined blocks. GasPrice *big.Int // Minimum gas price for mining a transaction diff --git a/miner/worker.go b/miner/worker.go index 3e0d225f7..8b646d35c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -560,7 +560,7 @@ func (w *worker) mainLoop() { } txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee) tcount := w.current.tcount - w.commitTransactions(w.current, txset, nil) + w.commitTransactions(w.current, txset, nil, nil) commitTxsTimer.UpdateSince(start) // Only update the snapshot if any new transactions were added @@ -797,7 +797,8 @@ func (w *worker) commitTransaction(env *environment, tx *types.Transaction, rece return receipt.Logs, nil } -func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, interruptCh chan int32) bool { +func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, + interruptCh chan int32, stopTimer *time.Timer) bool { gasLimit := env.header.GasLimit if env.gasPool == nil { env.gasPool = new(core.GasPool).AddGas(gasLimit) @@ -809,13 +810,6 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP } var coalescedLogs []*types.Log - var stopTimer *time.Timer - delay := w.engine.Delay(w.chain, env.header) - if delay != nil { - stopTimer = time.NewTimer(*delay - w.config.DelayLeftOver) - log.Debug("Time left for mining work", "left", (*delay - w.config.DelayLeftOver).String(), "leftover", w.config.DelayLeftOver) - defer stopTimer.Stop() - } // initilise bloom processors processorCapacity := 100 if txs.CurrentSize() < processorCapacity { @@ -1048,15 +1042,24 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment) { localTxs[account] = txs } } + + var stopTimer *time.Timer + delay := w.engine.Delay(w.chain, env.header, &w.config.DelayLeftOver) + if delay != nil { + stopTimer = time.NewTimer(*delay) + log.Debug("Time left for mining work", "delay", delay.String()) + defer stopTimer.Stop() + } + if len(localTxs) > 0 { txs := types.NewTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) - if w.commitTransactions(env, txs, interruptCh) { + if w.commitTransactions(env, txs, interruptCh, stopTimer) { return } } if len(remoteTxs) > 0 { txs := types.NewTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee) - if w.commitTransactions(env, txs, interruptCh) { + if w.commitTransactions(env, txs, interruptCh, stopTimer) { return } } From 086a99b4077e562be86961d4b2e334a52984c09f Mon Sep 17 00:00:00 2001 From: setunapo Date: Tue, 15 Nov 2022 17:30:49 +0800 Subject: [PATCH 39/61] worker: no need to add more transaction if not mining It could be a very old PoW logic, which try to add more transaction into the pending block when mining is stopped. Mining can be stopped when: 1.download started. 2.manually stopped by RPC. It is unnecessary to add more transaction into the pending block if a validator is stopped. And updateSnapshot() is not needed as well, it is to get the pending mining snapshot. --- miner/worker.go | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 8b646d35c..4e25d048a 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -65,7 +65,6 @@ const ( ) var ( - commitTxsTimer = metrics.NewRegisteredTimer("worker/committxs", nil) writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil) finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil) ) @@ -542,33 +541,7 @@ func (w *worker) mainLoop() { } case ev := <-w.txsCh: - // Apply transactions to the pending state if we're not sealing - // - // Note all transactions received may not be continuous with transactions - // already included in the current sealing block. These transactions will - // be automatically eliminated. - if !w.isRunning() && w.current != nil { - start := time.Now() - // If block is already full, abort - if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas { - continue - } - txs := make(map[common.Address]types.Transactions) - for _, tx := range ev.Txs { - acc, _ := types.Sender(w.current.signer, tx) - txs[acc] = append(txs[acc], tx) - } - txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee) - tcount := w.current.tcount - w.commitTransactions(w.current, txset, nil, nil) - commitTxsTimer.UpdateSince(start) - - // Only update the snapshot if any new transactions were added - // to the pending block - if tcount != w.current.tcount { - w.updateSnapshot(w.current) - } - } else { + if w.isRunning() { // Special case, if the consensus engine is 0 period clique(dev mode), // submit sealing work here since all empty submission will be rejected // by clique. Of course the advance sealing(empty submission) is disabled. @@ -577,6 +550,7 @@ func (w *worker) mainLoop() { w.commitWork(nil, true, time.Now().Unix()) } } + atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) // System stopped From 0789afe6e7b57fc4f940acb02a48a44f28d54550 Mon Sep 17 00:00:00 2001 From: setunapo Date: Wed, 16 Nov 2022 17:17:50 +0800 Subject: [PATCH 40/61] worker: remove pre-seal empty block pre-seal empty block is for PoW to deliver an empty block ASAP to gain the block mine reward. It is useless for PoS consensus and it does not work for BSC either. Delete the code to make worker simpler. --- miner/miner.go | 17 ----------------- miner/worker.go | 39 ++++++++------------------------------- 2 files changed, 8 insertions(+), 48 deletions(-) diff --git a/miner/miner.go b/miner/miner.go index 0ea2c0ea1..7f0f1583e 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -240,23 +240,6 @@ func (miner *Miner) SetGasCeil(ceil uint64) { miner.worker.setGasCeil(ceil) } -// EnablePreseal turns on the preseal mining feature. It's enabled by default. -// Note this function shouldn't be exposed to API, it's unnecessary for users -// (miners) to actually know the underlying detail. It's only for outside project -// which uses this library. -func (miner *Miner) EnablePreseal() { - miner.worker.enablePreseal() -} - -// DisablePreseal turns off the preseal mining feature. It's necessary for some -// fake consensus engine which can seal blocks instantaneously. -// Note this function shouldn't be exposed to API, it's unnecessary for users -// (miners) to actually know the underlying detail. It's only for outside project -// which uses this library. -func (miner *Miner) DisablePreseal() { - miner.worker.disablePreseal() -} - // GetSealingBlock retrieves a sealing block based on the given parameters. // The returned block is not sealed but all other fields should be filled. func (miner *Miner) GetSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash) (*types.Block, error) { diff --git a/miner/worker.go b/miner/worker.go index 4e25d048a..2d43f6c86 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -149,7 +149,6 @@ const ( // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. type newWorkReq struct { interruptCh chan int32 - noempty bool timestamp int64 } @@ -214,13 +213,6 @@ type worker struct { running int32 // The indicator whether the consensus engine is running or not. newTxs int32 // New arrival transaction count since last sealing work submitting. - // noempty is the flag used to control whether the feature of pre-seal empty - // block is enabled. The default value is false(pre-seal is enabled by default). - // But in some special scenario the consensus engine will seal blocks instantaneously, - // in this case this feature will add all empty blocks into canonical chain - // non-stop and no real transaction will be included. - noempty uint32 - // External functions isLocalBlock func(header *types.Header) bool // Function used to determine whether the specified block is mined by local miner. @@ -310,16 +302,6 @@ func (w *worker) setRecommitInterval(interval time.Duration) { } } -// disablePreseal disables pre-sealing feature -func (w *worker) disablePreseal() { - atomic.StoreUint32(&w.noempty, 1) -} - -// enablePreseal enables pre-sealing feature -func (w *worker) enablePreseal() { - atomic.StoreUint32(&w.noempty, 0) -} - // pending returns the pending state and corresponding block. func (w *worker) pending() (*types.Block, *state.StateDB) { // return a snapshot to avoid contention on currentMu mutex @@ -385,7 +367,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { <-timer.C // discard the initial tick // commit aborts in-flight transaction execution with given signal and resubmits a new one. - commit := func(noempty bool, reason int32) { + commit := func(reason int32) { if interruptCh != nil { // each commit work will have its own interruptCh to stop work with a reason interruptCh <- reason @@ -393,7 +375,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { } interruptCh = make(chan int32, 1) select { - case w.newWorkCh <- &newWorkReq{interruptCh: interruptCh, noempty: noempty, timestamp: timestamp}: + case w.newWorkCh <- &newWorkReq{interruptCh: interruptCh, timestamp: timestamp}: case <-w.exitCh: return } @@ -416,7 +398,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { case <-w.startCh: clearPending(w.chain.CurrentBlock().NumberU64()) timestamp = time.Now().Unix() - commit(true, commitInterruptNewHead) + commit(commitInterruptNewHead) case head := <-w.chainHeadCh: if !w.isRunning() { @@ -435,7 +417,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { continue } } - commit(true, commitInterruptNewHead) + commit(commitInterruptNewHead) case <-timer.C: // If sealing is running resubmit a new work cycle periodically to pull in @@ -447,7 +429,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { timer.Reset(recommit) continue } - commit(true, commitInterruptResubmit) + commit(commitInterruptResubmit) } case interval := <-w.resubmitIntervalCh: @@ -489,7 +471,7 @@ func (w *worker) mainLoop() { for { select { case req := <-w.newWorkCh: - w.commitWork(req.interruptCh, req.noempty, req.timestamp) + w.commitWork(req.interruptCh, req.timestamp) case req := <-w.getWorkCh: block, err := w.generateWork(req.params) @@ -547,7 +529,7 @@ func (w *worker) mainLoop() { // by clique. Of course the advance sealing(empty submission) is disabled. if (w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0) || (w.chainConfig.Parlia != nil && w.chainConfig.Parlia.Period == 0) { - w.commitWork(nil, true, time.Now().Unix()) + w.commitWork(nil, time.Now().Unix()) } } @@ -1054,7 +1036,7 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, error) { // commitWork generates several new sealing tasks based on the parent block // and submit them to the sealer. -func (w *worker) commitWork(interruptCh chan int32, noempty bool, timestamp int64) { +func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { start := time.Now() // Set the coinbase if the worker is running or it's required @@ -1074,11 +1056,6 @@ func (w *worker) commitWork(interruptCh chan int32, noempty bool, timestamp int6 return } - // 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, nil, false, start) - } // Fill pending transactions from the txpool w.fillTransactions(interruptCh, work) w.commit(work, w.fullTaskHook, true, start) From 139eb3f467782fc732447160ace10a7ccdd2ec4f Mon Sep 17 00:00:00 2001 From: setunapo Date: Wed, 16 Nov 2022 22:30:51 +0800 Subject: [PATCH 41/61] worker: fix a bug of the delay timer. `fillTransactions` will call `commitTransactions` twice, if the delay timer is expired during the first call, it will make the delay timer never be triggered in the second commitTransactions call. Pseudo code: x := time.NewTimer(time.Second) <-x.C fmt.Println("read delay 1") <-x.C fmt.Println("read delay 2") // will never hit --- miner/worker.go | 1 + 1 file changed, 1 insertion(+) diff --git a/miner/worker.go b/miner/worker.go index 2d43f6c86..1d44ee0fa 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -809,6 +809,7 @@ LOOP: select { case <-stopTimer.C: log.Info("Not enough time for further transactions", "txs", len(env.txs)) + stopTimer.Reset(0) // re-active the timer, in case it will be used later. break LOOP default: } From dbc70ee1e2ce6ed192a0b8815e66ada99fa5dd42 Mon Sep 17 00:00:00 2001 From: Leon <316032931@qq.com> Date: Thu, 17 Nov 2022 12:12:12 +0800 Subject: [PATCH 42/61] core/forkid: refactor nextForkHash (#1177) --- core/forkid/forkid.go | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/core/forkid/forkid.go b/core/forkid/forkid.go index 88a7bc1c4..d8fef09a7 100644 --- a/core/forkid/forkid.go +++ b/core/forkid/forkid.go @@ -84,26 +84,20 @@ func NewID(config *params.ChainConfig, genesis common.Hash, head uint64) ID { return ID{Hash: checksumToBytes(hash), Next: next} } +//NextForkHash calculates the forkHash from genesis to the next fork block number func NextForkHash(config *params.ChainConfig, genesis common.Hash, head uint64) [4]byte { // Calculate the starting checksum from the genesis hash hash := crc32.ChecksumIEEE(genesis[:]) - // Calculate the current fork checksum and the next fork block - var next uint64 for _, fork := range gatherForks(config) { - if fork <= head { - // Fork already passed, checksum the previous hash and the fork number - hash = checksumUpdate(hash, fork) - continue + if fork > head { + // Checksum the previous hash and nextFokr number and return + return checksumToBytes(checksumUpdate(hash, fork)) } - next = fork - break - } - if next == 0 { - return checksumToBytes(hash) - } else { - return checksumToBytes(checksumUpdate(hash, next)) + // Fork already passed, checksum the previous hash and the fork number + hash = checksumUpdate(hash, fork) } + return checksumToBytes(hash) } // NewIDWithChain calculates the Ethereum fork ID from an existing chain instance. From b8c2d2e8f81c2a8c58f2b0298f590b09498357ae Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Fri, 19 Aug 2022 01:02:47 -0500 Subject: [PATCH 43/61] eth, les: unlock downloader peerSet if there's an error (#25546) Unlock peerSet if there's an error in the downloader --- eth/downloader/peer.go | 1 + les/downloader/peer.go | 1 + 2 files changed, 2 insertions(+) diff --git a/eth/downloader/peer.go b/eth/downloader/peer.go index 324fdb9cd..2d140abfd 100644 --- a/eth/downloader/peer.go +++ b/eth/downloader/peer.go @@ -237,6 +237,7 @@ func (ps *peerSet) Register(p *peerConnection) error { } p.rates = msgrate.NewTracker(ps.rates.MeanCapacities(), ps.rates.MedianRoundTrip()) if err := ps.rates.Track(p.id, p.rates); err != nil { + ps.lock.Unlock() return err } ps.peers[p.id] = p diff --git a/les/downloader/peer.go b/les/downloader/peer.go index 863294832..bd47acae2 100644 --- a/les/downloader/peer.go +++ b/les/downloader/peer.go @@ -350,6 +350,7 @@ func (ps *peerSet) Register(p *peerConnection) error { } p.rates = msgrate.NewTracker(ps.rates.MeanCapacities(), ps.rates.MedianRoundTrip()) if err := ps.rates.Track(p.id, p.rates); err != nil { + ps.lock.Unlock() return err } ps.peers[p.id] = p From 466e9a2a3d80ceaf0aab22d4edf0ba0a55812fe8 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 19 Aug 2022 06:39:47 +0800 Subject: [PATCH 44/61] trie: improve node rlp decoding performance (#25357) This avoids copying the input []byte while decoding trie nodes. In most cases, particularly when the input slice is provided by the underlying database, this optimization is safe to use. For cases where the origin of the input slice is unclear, the copying version is retained. The new code performs better even when the input must be copied, because it is now only copied once in decodeNode. --- trie/database.go | 14 ++++-- trie/node.go | 30 ++++++++++-- trie/node_test.go | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 7 deletions(-) diff --git a/trie/database.go b/trie/database.go index 527cc4171..db465d4e9 100644 --- a/trie/database.go +++ b/trie/database.go @@ -169,7 +169,10 @@ func (n *cachedNode) rlp() []byte { // or by regenerating it from the rlp encoded blob. func (n *cachedNode) obj(hash common.Hash) node { if node, ok := n.node.(rawNode); ok { - return mustDecodeNode(hash[:], node) + // The raw-blob format nodes are loaded from either from + // clean cache or the database, they are all in their own + // copy and safe to use unsafe decoder. + return mustDecodeNodeUnsafe(hash[:], node) } return expandNode(hash[:], n.node) } @@ -373,7 +376,10 @@ func (db *Database) node(hash common.Hash) node { if enc := db.cleans.Get(nil, hash[:]); enc != nil { memcacheCleanHitMeter.Mark(1) memcacheCleanReadMeter.Mark(int64(len(enc))) - return mustDecodeNode(hash[:], enc) + + // The returned value from cache is in its own copy, + // safe to use mustDecodeNodeUnsafe for decoding. + return mustDecodeNodeUnsafe(hash[:], enc) } } // Retrieve the node from the dirty cache if available @@ -398,7 +404,9 @@ func (db *Database) node(hash common.Hash) node { memcacheCleanMissMeter.Mark(1) memcacheCleanWriteMeter.Mark(int64(len(enc))) } - return mustDecodeNode(hash[:], enc) + // The returned value from database is in its own copy, + // safe to use mustDecodeNodeUnsafe for decoding. + return mustDecodeNodeUnsafe(hash[:], enc) } // Node retrieves an encoded cached trie node from memory. If it cannot be found diff --git a/trie/node.go b/trie/node.go index bf3f024bb..6ce6551de 100644 --- a/trie/node.go +++ b/trie/node.go @@ -99,6 +99,7 @@ func (n valueNode) fstring(ind string) string { return fmt.Sprintf("%x ", []byte(n)) } +// mustDecodeNode is a wrapper of decodeNode and panic if any error is encountered. func mustDecodeNode(hash, buf []byte) node { n, err := decodeNode(hash, buf) if err != nil { @@ -107,8 +108,29 @@ func mustDecodeNode(hash, buf []byte) node { return n } -// decodeNode parses the RLP encoding of a trie node. +// mustDecodeNodeUnsafe is a wrapper of decodeNodeUnsafe and panic if any error is +// encountered. +func mustDecodeNodeUnsafe(hash, buf []byte) node { + n, err := decodeNodeUnsafe(hash, buf) + if err != nil { + panic(fmt.Sprintf("node %x: %v", hash, err)) + } + return n +} + +// decodeNode parses the RLP encoding of a trie node. It will deep-copy the passed +// byte slice for decoding, so it's safe to modify the byte slice afterwards. The- +// decode performance of this function is not optimal, but it is suitable for most +// scenarios with low performance requirements and hard to determine whether the +// byte slice be modified or not. func decodeNode(hash, buf []byte) (node, error) { + return decodeNodeUnsafe(hash, common.CopyBytes(buf)) +} + +// decodeNodeUnsafe parses the RLP encoding of a trie node. The passed byte slice +// will be directly referenced by node without bytes deep copy, so the input MUST +// not be changed after. +func decodeNodeUnsafe(hash, buf []byte) (node, error) { if len(buf) == 0 { return nil, io.ErrUnexpectedEOF } @@ -141,7 +163,7 @@ func decodeShort(hash, elems []byte) (node, error) { if err != nil { return nil, fmt.Errorf("invalid value node: %v", err) } - return &shortNode{key, append(valueNode{}, val...), flag}, nil + return &shortNode{key, valueNode(val), flag}, nil } r, _, err := decodeRef(rest) if err != nil { @@ -164,7 +186,7 @@ func decodeFull(hash, elems []byte) (*fullNode, error) { return n, err } if len(val) > 0 { - n.Children[16] = append(valueNode{}, val...) + n.Children[16] = valueNode(val) } return n, nil } @@ -190,7 +212,7 @@ func decodeRef(buf []byte) (node, []byte, error) { // empty node return nil, rest, nil case kind == rlp.String && len(val) == 32: - return append(hashNode{}, val...), rest, nil + return hashNode(val), rest, nil default: return nil, nil, fmt.Errorf("invalid RLP string size %d (want 0 or 32)", len(val)) } diff --git a/trie/node_test.go b/trie/node_test.go index 52720f1c7..d52b0cee2 100644 --- a/trie/node_test.go +++ b/trie/node_test.go @@ -20,6 +20,7 @@ import ( "bytes" "testing" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" ) @@ -92,3 +93,123 @@ func TestDecodeFullNode(t *testing.T) { t.Fatalf("decode full node err: %v", err) } } + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkEncodeShortNode +// BenchmarkEncodeShortNode-8 16878850 70.81 ns/op 48 B/op 1 allocs/op +func BenchmarkEncodeShortNode(b *testing.B) { + node := &shortNode{ + Key: []byte{0x1, 0x2}, + Val: hashNode(randBytes(32)), + } + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + nodeToBytes(node) + } +} + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkEncodeFullNode +// BenchmarkEncodeFullNode-8 4323273 284.4 ns/op 576 B/op 1 allocs/op +func BenchmarkEncodeFullNode(b *testing.B) { + node := &fullNode{} + for i := 0; i < 16; i++ { + node.Children[i] = hashNode(randBytes(32)) + } + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + nodeToBytes(node) + } +} + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkDecodeShortNode +// BenchmarkDecodeShortNode-8 7925638 151.0 ns/op 157 B/op 4 allocs/op +func BenchmarkDecodeShortNode(b *testing.B) { + node := &shortNode{ + Key: []byte{0x1, 0x2}, + Val: hashNode(randBytes(32)), + } + blob := nodeToBytes(node) + hash := crypto.Keccak256(blob) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + mustDecodeNode(hash, blob) + } +} + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkDecodeShortNodeUnsafe +// BenchmarkDecodeShortNodeUnsafe-8 9027476 128.6 ns/op 109 B/op 3 allocs/op +func BenchmarkDecodeShortNodeUnsafe(b *testing.B) { + node := &shortNode{ + Key: []byte{0x1, 0x2}, + Val: hashNode(randBytes(32)), + } + blob := nodeToBytes(node) + hash := crypto.Keccak256(blob) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + mustDecodeNodeUnsafe(hash, blob) + } +} + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkDecodeFullNode +// BenchmarkDecodeFullNode-8 1597462 761.9 ns/op 1280 B/op 18 allocs/op +func BenchmarkDecodeFullNode(b *testing.B) { + node := &fullNode{} + for i := 0; i < 16; i++ { + node.Children[i] = hashNode(randBytes(32)) + } + blob := nodeToBytes(node) + hash := crypto.Keccak256(blob) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + mustDecodeNode(hash, blob) + } +} + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkDecodeFullNodeUnsafe +// BenchmarkDecodeFullNodeUnsafe-8 1789070 687.1 ns/op 704 B/op 17 allocs/op +func BenchmarkDecodeFullNodeUnsafe(b *testing.B) { + node := &fullNode{} + for i := 0; i < 16; i++ { + node.Children[i] = hashNode(randBytes(32)) + } + blob := nodeToBytes(node) + hash := crypto.Keccak256(blob) + + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + mustDecodeNodeUnsafe(hash, blob) + } +} From 48b6db9f636ff8885c2963a30ea49448e1fe6268 Mon Sep 17 00:00:00 2001 From: ycyraum Date: Fri, 12 Aug 2022 13:58:06 +0200 Subject: [PATCH 45/61] core/genesis: remove calaverasAllocData (#25516) core/genesis: calaverasAllocData no longer used --- core/genesis_alloc.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/genesis_alloc.go b/core/genesis_alloc.go index 3d053904e..52232b1ab 100644 --- a/core/genesis_alloc.go +++ b/core/genesis_alloc.go @@ -25,5 +25,4 @@ const mainnetAllocData = "\xfa\x04]X\u0793\r\x83b\x011\x8e\u0189\x9agT\x06\x908' const ropstenAllocData = "\xf9\x03\xa4\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x80\xc2\v\x80\xc2\f\x80\xc2\r\x80\xc2\x0e\x80\xc2\x0f\x80\xc2\x10\x80\xc2\x11\x80\xc2\x12\x80\xc2\x13\x80\xc2\x14\x80\xc2\x15\x80\xc2\x16\x80\xc2\x17\x80\xc2\x18\x80\xc2\x19\x80\xc2\x1a\x80\xc2\x1b\x80\xc2\x1c\x80\xc2\x1d\x80\xc2\x1e\x80\xc2\x1f\x80\xc2 \x80\xc2!\x80\xc2\"\x80\xc2#\x80\xc2$\x80\xc2%\x80\xc2&\x80\xc2'\x80\xc2(\x80\xc2)\x80\xc2*\x80\xc2+\x80\xc2,\x80\xc2-\x80\xc2.\x80\xc2/\x80\xc20\x80\xc21\x80\xc22\x80\xc23\x80\xc24\x80\xc25\x80\xc26\x80\xc27\x80\xc28\x80\xc29\x80\xc2:\x80\xc2;\x80\xc2<\x80\xc2=\x80\xc2>\x80\xc2?\x80\xc2@\x80\xc2A\x80\xc2B\x80\xc2C\x80\xc2D\x80\xc2E\x80\xc2F\x80\xc2G\x80\xc2H\x80\xc2I\x80\xc2J\x80\xc2K\x80\xc2L\x80\xc2M\x80\xc2N\x80\xc2O\x80\xc2P\x80\xc2Q\x80\xc2R\x80\xc2S\x80\xc2T\x80\xc2U\x80\xc2V\x80\xc2W\x80\xc2X\x80\xc2Y\x80\xc2Z\x80\xc2[\x80\xc2\\\x80\xc2]\x80\xc2^\x80\xc2_\x80\xc2`\x80\xc2a\x80\xc2b\x80\xc2c\x80\xc2d\x80\xc2e\x80\xc2f\x80\xc2g\x80\xc2h\x80\xc2i\x80\xc2j\x80\xc2k\x80\xc2l\x80\xc2m\x80\xc2n\x80\xc2o\x80\xc2p\x80\xc2q\x80\xc2r\x80\xc2s\x80\xc2t\x80\xc2u\x80\xc2v\x80\xc2w\x80\xc2x\x80\xc2y\x80\xc2z\x80\xc2{\x80\xc2|\x80\xc2}\x80\xc2~\x80\xc2\u007f\x80\u00c1\x80\x80\u00c1\x81\x80\u00c1\x82\x80\u00c1\x83\x80\u00c1\x84\x80\u00c1\x85\x80\u00c1\x86\x80\u00c1\x87\x80\u00c1\x88\x80\u00c1\x89\x80\u00c1\x8a\x80\u00c1\x8b\x80\u00c1\x8c\x80\u00c1\x8d\x80\u00c1\x8e\x80\u00c1\x8f\x80\u00c1\x90\x80\u00c1\x91\x80\u00c1\x92\x80\u00c1\x93\x80\u00c1\x94\x80\u00c1\x95\x80\u00c1\x96\x80\u00c1\x97\x80\u00c1\x98\x80\u00c1\x99\x80\u00c1\x9a\x80\u00c1\x9b\x80\u00c1\x9c\x80\u00c1\x9d\x80\u00c1\x9e\x80\u00c1\x9f\x80\u00c1\xa0\x80\u00c1\xa1\x80\u00c1\xa2\x80\u00c1\xa3\x80\u00c1\xa4\x80\u00c1\xa5\x80\u00c1\xa6\x80\u00c1\xa7\x80\u00c1\xa8\x80\u00c1\xa9\x80\u00c1\xaa\x80\u00c1\xab\x80\u00c1\xac\x80\u00c1\xad\x80\u00c1\xae\x80\u00c1\xaf\x80\u00c1\xb0\x80\u00c1\xb1\x80\u00c1\xb2\x80\u00c1\xb3\x80\u00c1\xb4\x80\u00c1\xb5\x80\u00c1\xb6\x80\u00c1\xb7\x80\u00c1\xb8\x80\u00c1\xb9\x80\u00c1\xba\x80\u00c1\xbb\x80\u00c1\xbc\x80\u00c1\xbd\x80\u00c1\xbe\x80\u00c1\xbf\x80\u00c1\xc0\x80\u00c1\xc1\x80\u00c1\u0080\u00c1\u00c0\u00c1\u0100\u00c1\u0140\u00c1\u0180\u00c1\u01c0\u00c1\u0200\u00c1\u0240\u00c1\u0280\u00c1\u02c0\u00c1\u0300\u00c1\u0340\u00c1\u0380\u00c1\u03c0\u00c1\u0400\u00c1\u0440\u00c1\u0480\u00c1\u04c0\u00c1\u0500\u00c1\u0540\u00c1\u0580\u00c1\u05c0\u00c1\u0600\u00c1\u0640\u00c1\u0680\u00c1\u06c0\u00c1\u0700\u00c1\u0740\u00c1\u0780\u00c1\u07c0\u00c1\xe0\x80\u00c1\xe1\x80\u00c1\xe2\x80\u00c1\xe3\x80\u00c1\xe4\x80\u00c1\xe5\x80\u00c1\xe6\x80\u00c1\xe7\x80\u00c1\xe8\x80\u00c1\xe9\x80\u00c1\xea\x80\u00c1\xeb\x80\u00c1\xec\x80\u00c1\xed\x80\u00c1\xee\x80\u00c1\xef\x80\u00c1\xf0\x80\u00c1\xf1\x80\u00c1\xf2\x80\u00c1\xf3\x80\u00c1\xf4\x80\u00c1\xf5\x80\u00c1\xf6\x80\u00c1\xf7\x80\u00c1\xf8\x80\u00c1\xf9\x80\u00c1\xfa\x80\u00c1\xfb\x80\u00c1\xfc\x80\u00c1\xfd\x80\u00c1\xfe\x80\u00c1\xff\x80\u3507KT\xa8\xbd\x15)f\xd6?pk\xae\x1f\xfe\xb0A\x19!\xe5\x8d\f\x9f,\x9c\xd0Ft\xed\xea@\x00\x00\x00" const rinkebyAllocData = "\xf9\x03\xb7\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xf6\x941\xb9\x8d\x14\x00{\xde\xe67)\x80\x86\x98\x8a\v\xbd1\x18E#\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" const goerliAllocData = "\xf9\x04\x06\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xe0\x94L*\xe4\x82Y5\x05\xf0\x16<\xde\xfc\a>\x81\xc6<\xdaA\a\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe0\x94\xa8\xe8\xf1G2e\x8eKQ\xe8q\x191\x05:\x8ai\xba\xf2\xb1\x8a\x15-\x02\xc7\xe1J\xf6\x80\x00\x00\xe1\x94\u0665\x17\x9f\t\x1d\x85\x05\x1d<\x98'\x85\xef\xd1E\\\uc199\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\u08bdBX\xd2v\x887\xba\xa2j(\xfeq\xdc\a\x9f\x84\u01cbJG\xe3\xc1$H\xf4\xad\x00\x00\x00" -const calaverasAllocData = "\xf9\x06\x14\u0080\x01\xc2\x01\x01\xc2\x02\x01\xc2\x03\x01\xc2\x04\x01\xc2\x05\x01\xc2\x06\x01\xc2\a\x01\xc2\b\x01\xc2\t\x01\xc2\n\x01\xc2\v\x01\xc2\f\x01\xc2\r\x01\xc2\x0e\x01\xc2\x0f\x01\xc2\x10\x01\xc2\x11\x01\xc2\x12\x01\xc2\x13\x01\xc2\x14\x01\xc2\x15\x01\xc2\x16\x01\xc2\x17\x01\xc2\x18\x01\xc2\x19\x01\xc2\x1a\x01\xc2\x1b\x01\xc2\x1c\x01\xc2\x1d\x01\xc2\x1e\x01\xc2\x1f\x01\xc2 \x01\xc2!\x01\xc2\"\x01\xc2#\x01\xc2$\x01\xc2%\x01\xc2&\x01\xc2'\x01\xc2(\x01\xc2)\x01\xc2*\x01\xc2+\x01\xc2,\x01\xc2-\x01\xc2.\x01\xc2/\x01\xc20\x01\xc21\x01\xc22\x01\xc23\x01\xc24\x01\xc25\x01\xc26\x01\xc27\x01\xc28\x01\xc29\x01\xc2:\x01\xc2;\x01\xc2<\x01\xc2=\x01\xc2>\x01\xc2?\x01\xc2@\x01\xc2A\x01\xc2B\x01\xc2C\x01\xc2D\x01\xc2E\x01\xc2F\x01\xc2G\x01\xc2H\x01\xc2I\x01\xc2J\x01\xc2K\x01\xc2L\x01\xc2M\x01\xc2N\x01\xc2O\x01\xc2P\x01\xc2Q\x01\xc2R\x01\xc2S\x01\xc2T\x01\xc2U\x01\xc2V\x01\xc2W\x01\xc2X\x01\xc2Y\x01\xc2Z\x01\xc2[\x01\xc2\\\x01\xc2]\x01\xc2^\x01\xc2_\x01\xc2`\x01\xc2a\x01\xc2b\x01\xc2c\x01\xc2d\x01\xc2e\x01\xc2f\x01\xc2g\x01\xc2h\x01\xc2i\x01\xc2j\x01\xc2k\x01\xc2l\x01\xc2m\x01\xc2n\x01\xc2o\x01\xc2p\x01\xc2q\x01\xc2r\x01\xc2s\x01\xc2t\x01\xc2u\x01\xc2v\x01\xc2w\x01\xc2x\x01\xc2y\x01\xc2z\x01\xc2{\x01\xc2|\x01\xc2}\x01\xc2~\x01\xc2\u007f\x01\u00c1\x80\x01\u00c1\x81\x01\u00c1\x82\x01\u00c1\x83\x01\u00c1\x84\x01\u00c1\x85\x01\u00c1\x86\x01\u00c1\x87\x01\u00c1\x88\x01\u00c1\x89\x01\u00c1\x8a\x01\u00c1\x8b\x01\u00c1\x8c\x01\u00c1\x8d\x01\u00c1\x8e\x01\u00c1\x8f\x01\u00c1\x90\x01\u00c1\x91\x01\u00c1\x92\x01\u00c1\x93\x01\u00c1\x94\x01\u00c1\x95\x01\u00c1\x96\x01\u00c1\x97\x01\u00c1\x98\x01\u00c1\x99\x01\u00c1\x9a\x01\u00c1\x9b\x01\u00c1\x9c\x01\u00c1\x9d\x01\u00c1\x9e\x01\u00c1\x9f\x01\u00c1\xa0\x01\u00c1\xa1\x01\u00c1\xa2\x01\u00c1\xa3\x01\u00c1\xa4\x01\u00c1\xa5\x01\u00c1\xa6\x01\u00c1\xa7\x01\u00c1\xa8\x01\u00c1\xa9\x01\u00c1\xaa\x01\u00c1\xab\x01\u00c1\xac\x01\u00c1\xad\x01\u00c1\xae\x01\u00c1\xaf\x01\u00c1\xb0\x01\u00c1\xb1\x01\u00c1\xb2\x01\u00c1\xb3\x01\u00c1\xb4\x01\u00c1\xb5\x01\u00c1\xb6\x01\u00c1\xb7\x01\u00c1\xb8\x01\u00c1\xb9\x01\u00c1\xba\x01\u00c1\xbb\x01\u00c1\xbc\x01\u00c1\xbd\x01\u00c1\xbe\x01\u00c1\xbf\x01\u00c1\xc0\x01\u00c1\xc1\x01\u00c1\xc2\x01\u00c1\xc3\x01\u00c1\xc4\x01\u00c1\xc5\x01\u00c1\xc6\x01\u00c1\xc7\x01\u00c1\xc8\x01\u00c1\xc9\x01\u00c1\xca\x01\u00c1\xcb\x01\u00c1\xcc\x01\u00c1\xcd\x01\u00c1\xce\x01\u00c1\xcf\x01\u00c1\xd0\x01\u00c1\xd1\x01\u00c1\xd2\x01\u00c1\xd3\x01\u00c1\xd4\x01\u00c1\xd5\x01\u00c1\xd6\x01\u00c1\xd7\x01\u00c1\xd8\x01\u00c1\xd9\x01\u00c1\xda\x01\u00c1\xdb\x01\u00c1\xdc\x01\u00c1\xdd\x01\u00c1\xde\x01\u00c1\xdf\x01\u00c1\xe0\x01\u00c1\xe1\x01\u00c1\xe2\x01\u00c1\xe3\x01\u00c1\xe4\x01\u00c1\xe5\x01\u00c1\xe6\x01\u00c1\xe7\x01\u00c1\xe8\x01\u00c1\xe9\x01\u00c1\xea\x01\u00c1\xeb\x01\u00c1\xec\x01\u00c1\xed\x01\u00c1\xee\x01\u00c1\xef\x01\u00c1\xf0\x01\u00c1\xf1\x01\u00c1\xf2\x01\u00c1\xf3\x01\u00c1\xf4\x01\u00c1\xf5\x01\u00c1\xf6\x01\u00c1\xf7\x01\u00c1\xf8\x01\u00c1\xf9\x01\u00c1\xfa\x01\u00c1\xfb\x01\u00c1\xfc\x01\u00c1\xfd\x01\u00c1\xfe\x01\u00c1\xff\x01\xf6\x94\x0e\x89\xe2\xae\xdb\x1c\xfc\u06d4$\xd4\x1a\x1f!\x8fA2s\x81r\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\x10A\xaf\xbc\xb3Y\u0568\xdcX\xc1[/\xf5\x13T\xff\x8a!}\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94#o\xf1\xe9t\x19\xae\x93\xad\x80\xca\xfb\xaa!\"\f]x\xfb}\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94`\xad\xc0\xf8\x9aA\xaf#|\xe75T\xed\xe1p\xd73\xec\x14\xe0\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94y\x9d2\x9e_X4\x19\x16|\xd7\"\x96$\x85\x92n3\x8fJ\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94|\xf5\xb7\x9b\xfe)\x1ag\xab\x02\xb3\x93\xe4V\xcc\xc4\xc2f\xf7S\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\x8a\x8e\xaf\xb1\xcfb\xbf\xbe\xb1t\x17i\xda\xe1\xa9\xddG\x99a\x92\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\x8b\xa1\xf1\tU\x1b\xd42\x800\x12dZ\xc16\xdd\xd6M\xbar\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\xb0*.\xda\x1b1\u007f\xbd\x16v\x01(\x83k\n\u015bV\x0e\x9d\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\xba\xdc\r\xe9\xe0yK\x04\x9b^\xa6<>\x1ei\x8a4v\xc1r\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\xf00\v\ue24a\xe2r\xeb4~\x83i\xac\fv\xdfB\xc9?\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x94\xfe;U~\x8f\xb6+\x89\xf4\x91kr\x1b\xe5\\\ub08d\xbds\xa0\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" const sepoliaAllocData = "\xf9\x01\xee\u0791i\x16\xa8{\x823?BE\x04f#\xb27\x94\xc6\\\x8b\bE\x95\x16\x14\x01HJ\x00\x00\x00\xe1\x94\x10\xf5\xd4XT\xe08\a\x14\x85\xac\x9e@#\b\u03c0\xd2\xd2\xfe\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\u0794y\x9d2\x9e_X4\x19\x16|\xd7\"\x96$\x85\x92n3\x8fJ\x88\r\u0db3\xa7d\x00\x00\xe0\x94|\xf5\xb7\x9b\xfe)\x1ag\xab\x02\xb3\x93\xe4V\xcc\xc4\xc2f\xf7S\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\x8b\u007f\tw\xbbO\x0f\xbepv\xfa\"\xbc$\xac\xa0CX?^\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xa2\xa6\xd949\x14O\xfeM'\xc9\xe0\x88\xdc\u0637\x83\x94bc\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xaa\xec\x869DA\xf9\x15\xbc\xe3\xe6\xab9\x99w\xe9\x90o;i\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\u1532\x1c3\xde\x1f\xab?\xa1T\x99\xc6+Y\xfe\f\xc3%\x00 \u044bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xbc\x11)Y6\xaay\u0554\x13\x9d\xe1\xb2\xe1&)AO;\u06ca\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xbe\xef2\xca[\x9a\x19\x8d'\xb4\xe0/LpC\x9f\xe6\x03V\u03ca\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe1\x94\xd7\xd7lX\xb3\xa5\x19\xe9\xfal\xc4\xd2-\xc0\x17%\x9b\u011f\x1e\x8bR\xb7\xd2\xdc\xc8\f\xd2\xe4\x00\x00\x00\xe0\x94\xd7\xed\xdbx\xed)[<\x96)$\x0e\x89$\xfb\x8d\x88t\xdd\u060a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\u0665\x17\x9f\t\x1d\x85\x05\x1d<\x98'\x85\xef\xd1E\\\uc199\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xe2\xe2e\x90(\x147\x84\xd5W\xbc\xeco\xf3\xa0r\x10H\x88\n\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00\xe0\x94\xf4|\xae\x1c\xf7\x9c\xa6u\x8b\xfcx}\xbd!\u6f7eq\x12\xb8\x8a\xd3\xc2\x1b\xce\xcc\xed\xa1\x00\x00\x00" From fb2e68b79a65eb24931c56fbeb2d2916468bbf46 Mon Sep 17 00:00:00 2001 From: Henry <101552941+henry-0@users.noreply.github.com> Date: Mon, 1 Aug 2022 19:47:21 +0800 Subject: [PATCH 46/61] common/compiler: json unmarshalling error checks (#25449) complier/solidity:add json.Unmarshal err check --- common/compiler/solidity.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/common/compiler/solidity.go b/common/compiler/solidity.go index 01de3d4c6..0b1766054 100644 --- a/common/compiler/solidity.go +++ b/common/compiler/solidity.go @@ -161,13 +161,16 @@ func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion strin contracts := make(map[string]*Contract) for name, info := range output.Contracts { // Parse the individual compilation results. - var abi interface{} + var abi, userdoc, devdoc interface{} if err := json.Unmarshal([]byte(info.Abi), &abi); err != nil { return nil, fmt.Errorf("solc: error reading abi definition (%v)", err) } - var userdoc, devdoc interface{} - json.Unmarshal([]byte(info.Userdoc), &userdoc) - json.Unmarshal([]byte(info.Devdoc), &devdoc) + if err := json.Unmarshal([]byte(info.Userdoc), &userdoc); err != nil { + return nil, fmt.Errorf("solc: error reading userdoc definition (%v)", err) + } + if err := json.Unmarshal([]byte(info.Devdoc), &devdoc); err != nil { + return nil, fmt.Errorf("solc: error reading devdoc definition (%v)", err) + } contracts[name] = &Contract{ Code: "0x" + info.Bin, From de5dd95ada73be53853568ee7b1a385c0fd3edea Mon Sep 17 00:00:00 2001 From: setunapo Date: Fri, 28 Oct 2022 12:01:18 +0800 Subject: [PATCH 47/61] worker: enhancement of the current block generation logic. Currently, validator only try once to get transactions from TxPool to produce the block. However, new transactions could arrive while the validator is committing transaction. Validator should be allowed to add these new arrived transactions as long as Header.Timestamp is not reached This commit will: ** commitTransactions return with error code ** drop current mining block on new block imported ** try fillTransactions several times for the best not use append mode to follow the GasPrice rule. ** check if there is enough time for another fillTransactions. --- consensus/beacon/consensus.go | 4 + consensus/clique/clique.go | 5 + consensus/consensus.go | 6 ++ consensus/ethash/consensus.go | 4 + consensus/parlia/parlia.go | 5 + miner/worker.go | 181 ++++++++++++++++++++++++++++------ 6 files changed, 175 insertions(+), 30 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 8282ed7cb..4f4c272a0 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -363,6 +363,10 @@ func (beacon *Beacon) SetThreads(threads int) { } } +func (p *Beacon) DropOnNewBlock(*types.Header) bool { + return true +} + // IsTTDReached checks if the TotalTerminalDifficulty has been surpassed on the `parentHash` block. // It depends on the parentHash already being stored in the database. // If the parentHash is not stored in the database a UnknownAncestor error is returned. diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index a258f1fe5..11287e74e 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -705,6 +705,11 @@ func (c *Clique) APIs(chain consensus.ChainHeaderReader) []rpc.API { }} } +func (p *Clique) DropOnNewBlock(header *types.Header) bool { + // drop the block if it is not in turn. + return header.Difficulty.Cmp(diffNoTurn) == 0 +} + // SealHash returns the hash of a block prior to it being sealed. func SealHash(header *types.Header) (hash common.Hash) { hasher := sha3.NewLegacyKeccak256() diff --git a/consensus/consensus.go b/consensus/consensus.go index 87632a9d0..367a70367 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -130,6 +130,12 @@ type Engine interface { // Close terminates any background threads maintained by the consensus engine. Close() error + + // DropOnNewBlock determine the action of mining when it is interrupted by new imported block. + // Return + // true: the mining result will be dropped + // false: the mining result will be kept and move on to the next mine step. + DropOnNewBlock(header *types.Header) bool } // PoW is a consensus engine based on proof-of-work. diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 12a69c127..0bf77a8ae 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -647,6 +647,10 @@ var ( big32 = big.NewInt(32) ) +func (p *Ethash) DropOnNewBlock(*types.Header) bool { + return true +} + // AccumulateRewards credits the coinbase of the given block with the mining // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index 2e544803e..c16b36ac1 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -976,6 +976,11 @@ func (p *Parlia) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, return CalcDifficulty(snap, p.val) } +func (p *Parlia) DropOnNewBlock(header *types.Header) bool { + // drop the block if it is not in turn. + return header.Difficulty.Cmp(diffNoTurn) == 0 +} + // 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. diff --git a/miner/worker.go b/miner/worker.go index 1d44ee0fa..407dc7fcc 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -19,6 +19,7 @@ package miner import ( "errors" "fmt" + "math/big" "sync" "sync/atomic" "time" @@ -67,6 +68,11 @@ const ( var ( writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil) finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil) + + errBlockInterruptedByNewHead = errors.New("new head arrived while building block") + errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block") + errBlockInterruptedByTimeout = errors.New("timeout while building block") + errBlockInterruptedByOutOfGas = errors.New("out of gas while building block") ) // environment is the worker's current environment and holds all @@ -142,8 +148,11 @@ type task struct { } const ( - commitInterruptNewHead int32 = 1 - commitInterruptResubmit int32 = 2 + commitInterruptNone int32 = iota + commitInterruptNewHead + commitInterruptResubmit + commitInterruptTimeout + commitInterruptOutOfGas ) // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. @@ -754,7 +763,7 @@ func (w *worker) commitTransaction(env *environment, tx *types.Transaction, rece } func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByPriceAndNonce, - interruptCh chan int32, stopTimer *time.Timer) bool { + interruptCh chan int32, stopTimer *time.Timer) error { gasLimit := env.header.GasLimit if env.gasPool == nil { env.gasPool = new(core.GasPool).AddGas(gasLimit) @@ -766,7 +775,7 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP } var coalescedLogs []*types.Log - // initilise bloom processors + // initialize bloom processors processorCapacity := 100 if txs.CurrentSize() < processorCapacity { processorCapacity = txs.CurrentSize() @@ -781,6 +790,7 @@ func (w *worker) commitTransactions(env *environment, txs *types.TransactionsByP txCurr := &tx w.prefetcher.PrefetchMining(txsPrefetch, env.header, env.gasPool.Gas(), env.state.CopyDoPrefetch(), *w.chain.GetVMConfig(), stopPrefetchCh, txCurr) + signal := commitInterruptNone LOOP: for { // In the following three cases, we will interrupt the execution of the transaction. @@ -791,18 +801,19 @@ LOOP: // For the third case, the semi-finished work will be submitted to the consensus engine. if interruptCh != nil { select { - case reason, ok := <-interruptCh: + case signal, ok := <-interruptCh: if !ok { // should never be here, since interruptCh should not be read before log.Warn("commit transactions stopped unknown") } - return reason == commitInterruptNewHead + return signalToErr(signal) default: } } // If we don't have enough gas for any further transactions then we're done if env.gasPool.Gas() < params.TxGas { log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas) + signal = commitInterruptOutOfGas break } if stopTimer != nil { @@ -810,6 +821,7 @@ LOOP: case <-stopTimer.C: log.Info("Not enough time for further transactions", "txs", len(env.txs)) stopTimer.Reset(0) // re-active the timer, in case it will be used later. + signal = commitInterruptTimeout break LOOP default: } @@ -885,7 +897,7 @@ LOOP: } w.pendingLogsFeed.Send(cpy) } - return false + return signalToErr(signal) } // generateParams wraps various of settings for generating sealing task. @@ -988,7 +1000,7 @@ 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(interruptCh chan int32, env *environment) { +func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stopTimer *time.Timer) (err error) { // Split the pending transactions into locals and remotes // Fill the block with all available pending transactions. pending := w.eth.TxPool().Pending(false) @@ -1000,26 +1012,23 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment) { } } - var stopTimer *time.Timer - delay := w.engine.Delay(w.chain, env.header, &w.config.DelayLeftOver) - if delay != nil { - stopTimer = time.NewTimer(*delay) - log.Debug("Time left for mining work", "delay", delay.String()) - defer stopTimer.Stop() - } - + err = nil if len(localTxs) > 0 { txs := types.NewTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) - if w.commitTransactions(env, txs, interruptCh, stopTimer) { + err = w.commitTransactions(env, txs, interruptCh, stopTimer) + if err == errBlockInterruptedByNewHead || err == errBlockInterruptedByOutOfGas || err == errBlockInterruptedByTimeout { return } } if len(remoteTxs) > 0 { txs := types.NewTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee) - if w.commitTransactions(env, txs, interruptCh, stopTimer) { + err = w.commitTransactions(env, txs, interruptCh, stopTimer) + if err == errBlockInterruptedByNewHead || err == errBlockInterruptedByOutOfGas || err == errBlockInterruptedByTimeout { return } } + + return } // generateWork generates a sealing block based on the given parameters. @@ -1030,7 +1039,7 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, error) { } defer work.discard() - w.fillTransactions(nil, work) + w.fillTransactions(nil, work, nil) block, _, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, work.unclelist(), work.receipts) return block, err } @@ -1049,24 +1058,117 @@ func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { } coinbase = w.coinbase // Use the preset address as the fee recipient } - work, err := w.prepareWork(&generateParams{ - timestamp: uint64(timestamp), - coinbase: coinbase, - }) - if err != nil { - return - } - // Fill pending transactions from the txpool - w.fillTransactions(interruptCh, work) - w.commit(work, w.fullTaskHook, true, start) + stopTimer := time.NewTimer(0) + defer stopTimer.Stop() + <-stopTimer.C // discard the initial tick + + // validator can try several times to get the most profitable block, + // as long as the timestamp is not reached. + workList := make([]*environment, 0, 10) + var bestWork *environment + // workList clean up + defer func() { + for _, w := range workList { + // only keep the best work, discard others. + if w == bestWork { + continue + } + w.discard() + } + }() +LOOP: + for { + work, err := w.prepareWork(&generateParams{ + timestamp: uint64(timestamp), + coinbase: coinbase, + }) + if err != nil { + return + } + + workList = append(workList, work) + + delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) + if delay == nil { + log.Warn("commitWork delay is nil, something is wrong") + stopTimer = nil + } else if *delay <= 0 { + log.Debug("Not enough time for commitWork") + break + } else { + log.Debug("commitWork stopTimer", "block", work.header.Number, + "header time", time.Until(time.Unix(int64(work.header.Time), 0)), + "commit delay", *delay, "DelayLeftOver", w.config.DelayLeftOver) + stopTimer.Reset(*delay) + } + + // subscribe before fillTransactions + txsCh := make(chan core.NewTxsEvent, txChanSize) + sub := w.eth.TxPool().SubscribeNewTxsEvent(txsCh) + defer sub.Unsubscribe() + + // Fill pending transactions from the txpool + fillStart := time.Now() + err = w.fillTransactions(interruptCh, work, stopTimer) + fillDuration := time.Since(fillStart) + switch { + case errors.Is(err, errBlockInterruptedByNewHead): + // For Parlia, it will drop the work on receiving new block if it is not inturn. + if w.engine.DropOnNewBlock(work.header) { + log.Debug("drop the block, when new block is imported") + return + } + case errors.Is(err, errBlockInterruptedByTimeout): + // break the loop to get the best work + log.Debug("commitWork timeout") + break LOOP + case errors.Is(err, errBlockInterruptedByOutOfGas): + log.Debug("commitWork out of gas") + break LOOP + } + + if interruptCh == nil || stopTimer == nil { + // it is single commit work, no need to try several time. + log.Info("commitWork interruptCh or stopTimer is nil") + break + } + + select { + case <-txsCh: + delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) + log.Debug("commitWork txsCh arrived", "fillDuration", fillDuration.String(), "delay", delay.String()) + if fillDuration > *delay { + // there may not have enough time for another fillTransactions + break LOOP + } + case <-stopTimer.C: + log.Debug("commitWork stopTimer expired") + break LOOP + case <-interruptCh: + log.Debug("commitWork interruptCh closed, new block imported or resubmit triggered") + return + } + } + // get the most profitable work + bestWork = workList[0] + bestReward := new(big.Int) + for i, w := range workList { + balance := w.state.GetBalance(consensus.SystemAddress) + log.Debug("Get the most profitable work", "index", i, "balance", balance, "bestReward", bestReward) + if balance.Cmp(bestReward) > 0 { + bestWork = w + bestReward = balance + } + } + w.commit(bestWork, w.fullTaskHook, true, start) // 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 + w.current = bestWork } // commit runs any post-transaction state modifications, assembles the final block @@ -1167,3 +1269,22 @@ func (w *worker) postSideBlock(event core.ChainSideEvent) { case <-w.exitCh: } } + +// signalToErr converts the interruption signal to a concrete error type for return. +// The given signal must be a valid interruption signal. +func signalToErr(signal int32) error { + switch signal { + case commitInterruptNone: + return nil + case commitInterruptNewHead: + return errBlockInterruptedByNewHead + case commitInterruptResubmit: + return errBlockInterruptedByRecommit + case commitInterruptTimeout: + return errBlockInterruptedByTimeout + case commitInterruptOutOfGas: + return errBlockInterruptedByOutOfGas + default: + panic(fmt.Errorf("undefined signal %d", signal)) + } +} From c33f696811f661e7d374c9e1b414e75f2bebd5ed Mon Sep 17 00:00:00 2001 From: setunapo Date: Thu, 17 Nov 2022 15:38:50 +0800 Subject: [PATCH 48/61] worker: do not fillTransactions immediately on new transaction. It may not efficient if schedule fillTransactions when new transactions arrive. It could make the CPU keep running. To make is more efficient: 1.schedule fillTransactions when a certain amount of transaction are arrived. 2.or there is not much time left. --- miner/worker.go | 57 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 407dc7fcc..696cbefdc 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1063,6 +1063,10 @@ func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { defer stopTimer.Stop() <-stopTimer.C // discard the initial tick + stopWaitTimer := time.NewTimer(0) + defer stopWaitTimer.Stop() + <-stopWaitTimer.C // discard the initial tick + // validator can try several times to get the most profitable block, // as long as the timestamp is not reached. workList := make([]*environment, 0, 10) @@ -1134,20 +1138,49 @@ LOOP: break } - select { - case <-txsCh: - delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) - log.Debug("commitWork txsCh arrived", "fillDuration", fillDuration.String(), "delay", delay.String()) - if fillDuration > *delay { - // there may not have enough time for another fillTransactions + newTxsNum := 0 + // stopTimer was the maximum delay for each fillTransactions + // but now it is used to wait until (head.Time - DelayLeftOver) is reached. + stopTimer.Reset(time.Until(time.Unix(int64(work.header.Time), 0)) - w.config.DelayLeftOver) + LOOP_WAIT: + for { + select { + case <-stopTimer.C: + log.Debug("commitWork stopTimer expired") break LOOP + case <-interruptCh: + log.Debug("commitWork interruptCh closed, new block imported or resubmit triggered") + return + case ev := <-txsCh: + delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) + log.Debug("commitWork txsCh arrived", "fillDuration", fillDuration.String(), + "delay", delay.String(), "work.tcount", work.tcount, + "newTxsNum", newTxsNum, "len(ev.Txs)", len(ev.Txs)) + if *delay < fillDuration { + // There may not have enough time for another fillTransactions. + break LOOP + } else if *delay < fillDuration*2 { + // We can schedule another fillTransactions, but the time is limited, + // probably it is the last chance, schedule it immediately. + break LOOP_WAIT + } else { + // There is still plenty of time left. + // We can wait a while to collect more transactions before + // schedule another fillTransaction to reduce CPU cost. + // There will be 2 cases to schedule another fillTransactions: + // 1.newTxsNum >= work.tcount + // 2.no much time left, have to schedule it immediately. + newTxsNum = newTxsNum + len(ev.Txs) + if newTxsNum >= work.tcount { + break LOOP_WAIT + } + stopWaitTimer.Reset(*delay - fillDuration*2) + } + case <-stopWaitTimer.C: + if newTxsNum > 0 { + break LOOP_WAIT + } } - case <-stopTimer.C: - log.Debug("commitWork stopTimer expired") - break LOOP - case <-interruptCh: - log.Debug("commitWork interruptCh closed, new block imported or resubmit triggered") - return } } // get the most profitable work From 21b985c14b32aef35c5411e2f38d731852bff934 Mon Sep 17 00:00:00 2001 From: setunapo Date: Fri, 18 Nov 2022 22:55:17 +0800 Subject: [PATCH 49/61] worker: always drop on new block imported. When new block is imported, there is no need to commit the current work, even the new imported block is offturn and itself is inturn. That is because when offturn block is received, the inturn block is already later to broadcast block, deliver the later block will cause many reorg, which is not reasonable. And also make sure all useless work can be discarded, to avoid goroutine leak. --- consensus/beacon/consensus.go | 4 ---- consensus/clique/clique.go | 5 ----- consensus/consensus.go | 6 ------ consensus/ethash/consensus.go | 4 ---- consensus/parlia/parlia.go | 5 ----- miner/worker.go | 13 ++++--------- 6 files changed, 4 insertions(+), 33 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 4f4c272a0..8282ed7cb 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -363,10 +363,6 @@ func (beacon *Beacon) SetThreads(threads int) { } } -func (p *Beacon) DropOnNewBlock(*types.Header) bool { - return true -} - // IsTTDReached checks if the TotalTerminalDifficulty has been surpassed on the `parentHash` block. // It depends on the parentHash already being stored in the database. // If the parentHash is not stored in the database a UnknownAncestor error is returned. diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 11287e74e..a258f1fe5 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -705,11 +705,6 @@ func (c *Clique) APIs(chain consensus.ChainHeaderReader) []rpc.API { }} } -func (p *Clique) DropOnNewBlock(header *types.Header) bool { - // drop the block if it is not in turn. - return header.Difficulty.Cmp(diffNoTurn) == 0 -} - // SealHash returns the hash of a block prior to it being sealed. func SealHash(header *types.Header) (hash common.Hash) { hasher := sha3.NewLegacyKeccak256() diff --git a/consensus/consensus.go b/consensus/consensus.go index 367a70367..87632a9d0 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -130,12 +130,6 @@ type Engine interface { // Close terminates any background threads maintained by the consensus engine. Close() error - - // DropOnNewBlock determine the action of mining when it is interrupted by new imported block. - // Return - // true: the mining result will be dropped - // false: the mining result will be kept and move on to the next mine step. - DropOnNewBlock(header *types.Header) bool } // PoW is a consensus engine based on proof-of-work. diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 0bf77a8ae..12a69c127 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -647,10 +647,6 @@ var ( big32 = big.NewInt(32) ) -func (p *Ethash) DropOnNewBlock(*types.Header) bool { - return true -} - // AccumulateRewards credits the coinbase of the given block with the mining // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index c16b36ac1..2e544803e 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -976,11 +976,6 @@ func (p *Parlia) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, return CalcDifficulty(snap, p.val) } -func (p *Parlia) DropOnNewBlock(header *types.Header) bool { - // drop the block if it is not in turn. - return header.Difficulty.Cmp(diffNoTurn) == 0 -} - // 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. diff --git a/miner/worker.go b/miner/worker.go index 696cbefdc..7c79b7327 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1118,17 +1118,12 @@ LOOP: fillDuration := time.Since(fillStart) switch { case errors.Is(err, errBlockInterruptedByNewHead): - // For Parlia, it will drop the work on receiving new block if it is not inturn. - if w.engine.DropOnNewBlock(work.header) { - log.Debug("drop the block, when new block is imported") - return - } + log.Debug("commitWork abort", "err", err) + return case errors.Is(err, errBlockInterruptedByTimeout): - // break the loop to get the best work - log.Debug("commitWork timeout") - break LOOP case errors.Is(err, errBlockInterruptedByOutOfGas): - log.Debug("commitWork out of gas") + // break the loop to get the best work + log.Debug("commitWork finish", "reason", err) break LOOP } From aa986b6d4e930ee5a441932aeb939bff973ec19e Mon Sep 17 00:00:00 2001 From: setunapo Date: Mon, 21 Nov 2022 13:30:57 +0800 Subject: [PATCH 50/61] worker: return for resubmit signal. it is not necssary to add more transaction when resubmit is fired. the resubmit logic was for PoW and can be removed later. --- miner/worker.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 7c79b7327..05a93c934 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1016,16 +1016,19 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stop if len(localTxs) > 0 { txs := types.NewTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) err = w.commitTransactions(env, txs, interruptCh, stopTimer) - if err == errBlockInterruptedByNewHead || err == errBlockInterruptedByOutOfGas || err == errBlockInterruptedByTimeout { + // we will abort here when: + // 1.new block was imported + // 2.out of Gas, no more transaction can be added. + // 3.the mining timer has expired, stop adding transactions. + // 4.interrupted resubmit timer, which is by default 10s. + // resubmit is for PoW only, can be deleted for PoS consensus later + if err != nil { return } } if len(remoteTxs) > 0 { txs := types.NewTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee) err = w.commitTransactions(env, txs, interruptCh, stopTimer) - if err == errBlockInterruptedByNewHead || err == errBlockInterruptedByOutOfGas || err == errBlockInterruptedByTimeout { - return - } } return @@ -1120,6 +1123,7 @@ LOOP: case errors.Is(err, errBlockInterruptedByNewHead): log.Debug("commitWork abort", "err", err) return + case errors.Is(err, errBlockInterruptedByRecommit): case errors.Is(err, errBlockInterruptedByTimeout): case errors.Is(err, errBlockInterruptedByOutOfGas): // break the loop to get the best work From db4cb1df261032b165de5078dc43d86801e30659 Mon Sep 17 00:00:00 2001 From: Roshan Date: Mon, 21 Nov 2022 19:42:35 +0800 Subject: [PATCH 51/61] upgrade: update Gibbs fork height and system contract code --- core/systemcontracts/upgrade.go | 16 ++++++++++++++++ params/config.go | 8 +++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/core/systemcontracts/upgrade.go b/core/systemcontracts/upgrade.go index 94eb014d7..e37898738 100644 --- a/core/systemcontracts/upgrade.go +++ b/core/systemcontracts/upgrade.go @@ -364,6 +364,22 @@ func init() { }, } + gibbsUpgrade[mainNet] = &Upgrade{ + UpgradeName: "gibbs", + Configs: []*UpgradeConfig{ + { + ContractAddr: common.HexToAddress(TokenHubContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/8cfa94e657670d60ac1ff0563cddcf4664f77227", + Code: "60806040526004361061036f5760003560e01c80639a854bbd116101c6578063bd466461116100f7578063f014847211610095578063fc1a598f1161006f578063fc1a598f14610d58578063fc3e590814610a3b578063fd6a687914610d8b578063ff9c0027146106ec576103b7565b8063f014847214610d19578063f9a2bbc714610d2e578063fa9e915914610d43576103b7565b8063d9e6dae9116100d1578063d9e6dae91461066e578063dc927faf14610cda578063e1c7392a14610cef578063ebf71d5314610d04576103b7565b8063bd46646114610c0d578063c81b166214610c40578063c8509d8114610c55576103b7565b8063aa7415f511610164578063b99328c51161013e578063b99328c514610b77578063b9fd21e314610bb0578063ba35ead614610bc5578063bbface1f14610bda576103b7565b8063aa7415f514610a50578063ab51bb9614610a97578063ac43175114610aac576103b7565b8063a1a11bf5116101a0578063a1a11bf5146109fc578063a496fba214610a11578063a78abc1614610a26578063a7c9f02d14610a3b576103b7565b80639a854bbd146109995780639a99b4f0146109ae5780639dc09262146109e7576103b7565b806361368475116102a0578063727be1f81161023e578063831d65d111610218578063831d65d1146108c05780638b87b21f146105ed5780638eff336c1461094557806396713da914610984576103b7565b8063727be1f81461086c57806375d47a0a146108965780637942fd05146108ab576103b7565b80636e47b4821161027a5780636e47b4821461082d57806370fd5bad146106ec578063718a8aa81461084257806371d3086314610857576103b7565b8063613684751461066e57806366dea52a146106ec5780636e05652014610701576103b7565b806343a368b91161030d57806350432d32116102e757806350432d321461068357806351e806721461069857806359b92789146106ad5780635d499b1b146106d7576103b7565b806343a368b91461062d578063493279b1146106425780634bf6c8821461066e576103b7565b8063149d14d911610349578063149d14d9146105155780633d7132231461053c5780633dffc387146105ed57806343756e5c14610618576103b7565b80630bee7a67146103bc5780630e2374a5146103ea5780631182b8751461041b576103b7565b366103b75734156103b5576040805133815234602082015281517f6c98249d85d88c3753a04a22230f595e4dc8d3dc86c34af35deeeedc861b89db929181900390910190a15b005b600080fd5b3480156103c857600080fd5b506103d1610da0565b6040805163ffffffff9092168252519081900360200190f35b3480156103f657600080fd5b506103ff610da5565b604080516001600160a01b039092168252519081900360200190f35b34801561042757600080fd5b506104a06004803603604081101561043e57600080fd5b60ff8235169190810190604081016020820135600160201b81111561046257600080fd5b82018360208201111561047457600080fd5b803590602001918460018302840111600160201b8311171561049557600080fd5b509092509050610dab565b6040805160208082528351818301528351919283929083019185019080838360005b838110156104da5781810151838201526020016104c2565b50505050905090810190601f1680156105075780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561052157600080fd5b5061052a610ed9565b60408051918252519081900360200190f35b34801561054857600080fd5b506103ff6004803603602081101561055f57600080fd5b810190602081018135600160201b81111561057957600080fd5b82018360208201111561058b57600080fd5b803590602001918460018302840111600160201b831117156105ac57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610edf945050505050565b3480156105f957600080fd5b50610602610f03565b6040805160ff9092168252519081900360200190f35b34801561062457600080fd5b506103ff610f08565b34801561063957600080fd5b5061052a610f0e565b34801561064e57600080fd5b50610657610f1a565b6040805161ffff9092168252519081900360200190f35b34801561067a57600080fd5b50610602610f1f565b34801561068f57600080fd5b5061052a610f24565b3480156106a457600080fd5b506103ff610f2f565b3480156106b957600080fd5b506103ff600480360360208110156106d057600080fd5b5035610f35565b3480156106e357600080fd5b5061052a610f50565b3480156106f857600080fd5b50610602610f59565b6108196004803603608081101561071757600080fd5b810190602081018135600160201b81111561073157600080fd5b82018360208201111561074357600080fd5b803590602001918460208302840111600160201b8311171561076457600080fd5b919390929091602081019035600160201b81111561078157600080fd5b82018360208201111561079357600080fd5b803590602001918460208302840111600160201b831117156107b457600080fd5b919390929091602081019035600160201b8111156107d157600080fd5b8201836020820111156107e357600080fd5b803590602001918460208302840111600160201b8311171561080457600080fd5b91935091503567ffffffffffffffff16610f5e565b604080519115158252519081900360200190f35b34801561083957600080fd5b506103ff611433565b34801561084e57600080fd5b50610602611439565b34801561086357600080fd5b5061052a61143e565b34801561087857600080fd5b506108196004803603602081101561088f57600080fd5b5035611444565b3480156108a257600080fd5b506103ff6114c5565b3480156108b757600080fd5b506106026114cb565b3480156108cc57600080fd5b506103b5600480360360408110156108e357600080fd5b60ff8235169190810190604081016020820135600160201b81111561090757600080fd5b82018360208201111561091957600080fd5b803590602001918460018302840111600160201b8311171561093a57600080fd5b5090925090506114d0565b34801561095157600080fd5b506103b56004803603606081101561096857600080fd5b508035906001600160a01b036020820135169060400135611619565b34801561099057600080fd5b5061060261169f565b3480156109a557600080fd5b5061052a6116a4565b3480156109ba57600080fd5b5061052a600480360360408110156109d157600080fd5b506001600160a01b0381351690602001356116b0565b3480156109f357600080fd5b506103ff6117ee565b348015610a0857600080fd5b506103ff6117f4565b348015610a1d57600080fd5b506106026117fa565b348015610a3257600080fd5b506108196117ff565b348015610a4757600080fd5b50610602611808565b61081960048036036080811015610a6657600080fd5b5080356001600160a01b03908116916020810135909116906040810135906060013567ffffffffffffffff1661180d565b348015610aa357600080fd5b506103d16117fa565b348015610ab857600080fd5b506103b560048036036040811015610acf57600080fd5b810190602081018135600160201b811115610ae957600080fd5b820183602082011115610afb57600080fd5b803590602001918460018302840111600160201b83111715610b1c57600080fd5b919390929091602081019035600160201b811115610b3957600080fd5b820183602082011115610b4b57600080fd5b803590602001918460018302840111600160201b83111715610b6c57600080fd5b509092509050611ece565b348015610b8357600080fd5b506103b560048036036040811015610b9a57600080fd5b50803590602001356001600160a01b031661213d565b348015610bbc57600080fd5b5061052a6121b3565b348015610bd157600080fd5b5061052a6121bd565b348015610be657600080fd5b5061052a60048036036020811015610bfd57600080fd5b50356001600160a01b03166121c3565b348015610c1957600080fd5b5061052a60048036036020811015610c3057600080fd5b50356001600160a01b03166121d5565b348015610c4c57600080fd5b506103ff6121f0565b348015610c6157600080fd5b506103b560048036036040811015610c7857600080fd5b60ff8235169190810190604081016020820135600160201b811115610c9c57600080fd5b820183602082011115610cae57600080fd5b803590602001918460018302840111600160201b83111715610ccf57600080fd5b5090925090506121f6565b348015610ce657600080fd5b506103ff6122c6565b348015610cfb57600080fd5b506103b56122cc565b348015610d1057600080fd5b5061060261236c565b348015610d2557600080fd5b50610602612371565b348015610d3a57600080fd5b506103ff612376565b348015610d4f57600080fd5b5061052a61237c565b348015610d6457600080fd5b506104a060048036036020811015610d7b57600080fd5b50356001600160a01b0316612382565b348015610d9757600080fd5b506103ff6124a9565b606481565b61200181565b60005460609060ff16610df3576040805162461bcd60e51b8152602060048201526019602482015260008051602061490c833981519152604482015290519081900360640190fd5b3361200014610e335760405162461bcd60e51b815260040180806020018281038252602f8152602001806148ba602f913960400191505060405180910390fd5b60ff841660021415610e8557610e7e83838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506124af92505050565b9050610ed2565b6040805162461bcd60e51b815260206004820152601860248201527f756e7265636f676e697a65642073796e207061636b6167650000000000000000604482015290519081900360640190fd5b9392505050565b60015490565b6020818101516000908152600490915260409020546001600160a01b03165b919050565b600181565b61100181565b670de0b6b3a764000081565b603881565b600881565b66071afd498d000081565b61200081565b6000908152600460205260409020546001600160a01b031690565b6402540be40081565b600281565b6000805460ff16610fa4576040805162461bcd60e51b8152602060048201526019602482015260008051602061490c833981519152604482015290519081900360640190fd5b868514610fe25760405162461bcd60e51b815260040180806020018281038252603b81526020018061487f603b913960400191505060405180910390fd5b8683146110205760405162461bcd60e51b815260040180806020018281038252603f815260200180614752603f913960400191505060405180910390fd5b426078018267ffffffffffffffff16101561106c5760405162461bcd60e51b81526004018080602001828103825260248152602001806146426024913960400191505060405180910390fd5b6402540be4003406156110b05760405162461bcd60e51b81526004018080602001828103825260408152602001806149826040913960400191505060405180910390fd5b604080518681526020808802820101909152859060009081906060908480156110e3578160200160208202803683370190505b50905060005b848110156111be576402540be4008b8b8381811061110357fe5b905060200201358161111157fe5b061561114e5760405162461bcd60e51b815260040180806020018281038252603c815260200180614791603c913960400191505060405180910390fd5b6111738b8b8381811061115d57fe5b90506020020135856125d390919063ffffffff16565b935061119f6402540be4008c8c8481811061118a57fe5b9050602002013561262d90919063ffffffff16565b8282815181106111ab57fe5b60209081029190910101526001016110e9565b506001546111e3906111d6908663ffffffff61266f16565b849063ffffffff6125d316565b3410156112215760405162461bcd60e51b815260040180806020018281038252605681526020018061492c6056913960600191505060405180910390fd5b611231348463ffffffff6126c816565b915061123b614468565b6040518060c001604052806221272160e91b60001b815260200160006001600160a01b031681526020018381526020018e8e808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505050908252506040805160208c810282810182019093528c82529283019290918d918d91829185019084908082843760009201919091525050509082525067ffffffffffffffff8916602090910152905061200063f7a251d760036112ff8461270a565b611314876402540be40063ffffffff61262d16565b6040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b8381101561137257818101518382015260200161135a565b50505050905090810190601f16801561139f5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b1580156113c057600080fd5b505af11580156113d4573d6000803e3d6000fd5b505060408051600081523360208201528082018890526060810187905290517f74eab09b0e53aefc23f2e1b16da593f95c2dd49c6f5a23720463d10d9c330b2a9350908190036080019150a15060019c9b505050505050505050505050565b61100581565b601081565b60015481565b600033612001146114865760405162461bcd60e51b81526004018080602001828103825260338152602001806145826033913960400191505060405180910390fd5b81156114bd576040516120019083156108fc029084906000818181858888f193505050501580156114bb573d6000803e3d6000fd5b505b506001919050565b61100881565b600b81565b60005460ff16611515576040805162461bcd60e51b8152602060048201526019602482015260008051602061490c833981519152604482015290519081900360640190fd5b33612000146115555760405162461bcd60e51b815260040180806020018281038252602f8152602001806148ba602f913960400191505060405180910390fd5b60ff8316600314156115a5576115a082828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506129c592505050565b611614565b7f41ce201247b6ceb957dcdb217d0b8acb50b9ea0e12af9af4f5e7f38902101605838383604051808460ff1660ff168152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f1916909201829003965090945050505050a15b505050565b33611008146116595760405162461bcd60e51b81526004018080602001828103825260238152602001806148e96023913960400191505060405180910390fd5b600083815260046020908152604080832080546001600160a01b039096166001600160a01b03199096168617905593825260038152838220949094556002909352912055565b600981565b677ce66c50e284000081565b6000805460ff166116f6576040805162461bcd60e51b8152602060048201526019602482015260008051602061490c833981519152604482015290519081900360640190fd5b33611005146117365760405162461bcd60e51b815260040180806020018281038252602f8152602001806145b5602f913960400191505060405180910390fd5b60004783106117455747611747565b825b9050670de0b6b3a76400008111156117635760009150506117e8565b80156117e5576040516001600160a01b0385169082156108fc029083906000818181858888f1935050505015801561179f573d6000803e3d6000fd5b50604080516001600160a01b03861681526020810183905281517ff8b71c64315fc33b2ead2adfa487955065152a8ac33d9d5193aafd7f45dc15a0929181900390910190a15b90505b92915050565b61100781565b61100681565b600081565b60005460ff1681565b600381565b6000805460ff16611853576040805162461bcd60e51b8152602060048201526019602482015260008051602061490c833981519152604482015290519081900360640190fd5b426078018267ffffffffffffffff16101561189f5760405162461bcd60e51b81526004018080602001828103825260248152602001806146426024913960400191505060405180910390fd5b6402540be4003406156118e35760405162461bcd60e51b81526004018080602001828103825260408152602001806149826040913960400191505060405180910390fd5b600080806001600160a01b0388166119c25760015461190990879063ffffffff6125d316565b3410156119475760405162461bcd60e51b81526004018080602001828103825260618152602001806146cc6061913960800191505060405180910390fd5b6402540be40086061561198b5760405162461bcd60e51b815260040180806020018281038252603c815260200180614791603c913960400191505060405180910390fd5b61199b348763ffffffff6126c816565b90506119b2866402540be40063ffffffff61262d16565b6221272160e91b93509150611c65565b6001600160a01b038816600090815260036020526040902054925082611a195760405162461bcd60e51b815260040180806020018281038252603181526020018061469b6031913960400191505060405180910390fd5b600154341015611a5a5760405162461bcd60e51b815260040180806020018281038252603f8152602001806147ee603f913960400191505060405180910390fd5b506001600160a01b0387166000908152600260205260409020543490600881111580611aa55750600881118015611aa55750611aa3876007198301600a0a63ffffffff612a2116565b155b611ae05760405162461bcd60e51b815260040180806020018281038252603c815260200180614791603c913960400191505060405180910390fd5b611aea8782612a63565b9250611af584612aa3565b15611b3d576305f5e100831015611b3d5760405162461bcd60e51b815260040180806020018281038252603a8152602001806145e4603a913960400191505060405180910390fd5b600881101580611b575750600881108015611b5757508683115b611b925760405162461bcd60e51b815260040180806020018281038252602581526020018061472d6025913960400191505060405180910390fd5b677ce66c50e2840000831115611bd95760405162461bcd60e51b81526004018080602001828103825260358152602001806146666035913960400191505060405180910390fd5b604080516323b872dd60e01b81523360048201523060248201526044810189905290516001600160a01b038b16916323b872dd9160648083019260209291908290030181600087803b158015611c2e57600080fd5b505af1158015611c42573d6000803e3d6000fd5b505050506040513d6020811015611c5857600080fd5b5051611c6357600080fd5b505b611c6d614468565b6040805160c0810182528581526001600160a01b038b166020820152815160018082528184018452919283019181602001602082028036833750505081526040805160018082528183019092526020928301929091908083019080368337505050815260408051600180825281830190925260209283019290919080830190803683370190505081526020018767ffffffffffffffff168152509050828160400151600081518110611d1b57fe5b602002602001018181525050878160600151600081518110611d3957fe5b60200260200101906001600160a01b031690816001600160a01b031681525050338160800151600081518110611d6b57fe5b6001600160a01b039092166020928302919091019091015261200063f7a251d76003611d968461270a565b611dab866402540be40063ffffffff61262d16565b6040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b83811015611e09578181015183820152602001611df1565b50505050905090810190601f168015611e365780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b158015611e5757600080fd5b505af1158015611e6b573d6000803e3d6000fd5b5050604080516001600160a01b038d1681523360208201528082018b90526060810186905290517f74eab09b0e53aefc23f2e1b16da593f95c2dd49c6f5a23720463d10d9c330b2a9350908190036080019150a150600198975050505050505050565b3361100714611f0e5760405162461bcd60e51b815260040180806020018281038252602e81526020018061482d602e913960400191505060405180910390fd5b60208114611f63576040805162461bcd60e51b815260206004820152601b60248201527f65787065637465642076616c7565206c656e6774682069732033320000000000604482015290519081900360640190fd5b606084848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8801819004810282018101909252868152939450606093925086915085908190840183828082843760009201919091525050505060208301519091506772656c617946656560c01b81141561206b576020820151670de0b6b3a7640000811180159061201257506402540be4008106155b612063576040805162461bcd60e51b815260206004820152601960248201527f7468652072656c6179466565206f7574206f662072616e676500000000000000604482015290519081900360640190fd5b6001556120a8565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a878787876040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050505050565b336110081461217d5760405162461bcd60e51b81526004018080602001828103825260238152602001806148e96023913960400191505060405180910390fd5b600091825260046020908152604080842080546001600160a01b03191690556001600160a01b0392909216835260039052812055565b6221272160e91b81565b61c35081565b60026020526000908152604090205481565b6001600160a01b031660009081526003602052604090205490565b61100281565b60005460ff1661223b576040805162461bcd60e51b8152602060048201526019602482015260008051602061490c833981519152604482015290519081900360640190fd5b336120001461227b5760405162461bcd60e51b815260040180806020018281038252602f8152602001806148ba602f913960400191505060405180910390fd5b60ff8316600314156115a5576115a082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612ba992505050565b61100381565b60005460ff1615612324576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e747261637420616c726561647920696e697400000000000000604482015290519081900360640190fd5b66071afd498d000060019081556000808052600260205260127fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b55805460ff19169091179055565b600481565b600581565b61100081565b61271081565b6001600160a01b03811660009081526003602090815260409182902054825182815280840190935260609290918391906020820181803683375050506020810183905290506000805b60208160ff16101561241257828160ff16815181106123e657fe5b01602001516001600160f81b031916156124055760019091019061240a565b612412565b6001016123cb565b5060608160ff166040519080825280601f01601f191660200182016040528015612443576020820181803683370190505b50905060005b8260ff168160ff16101561249f57838160ff168151811061246657fe5b602001015160f81c60f81b828260ff168151811061248057fe5b60200101906001600160f81b031916908160001a905350600101612449565b5095945050505050565b61100481565b60606124b96144b4565b60006124c484612ca7565b915091508061251a576040805162461bcd60e51b815260206004820152601f60248201527f756e7265636f676e697a6564207472616e73666572496e207061636b61676500604482015290519081900360640190fd5b600061252583612de6565b905063ffffffff8116156125b9576040808401516020808601516001600160a01b031660009081526002909152918220546125609190612a63565b905061256a6144e9565b60405180608001604052808660000151815260200183815260200186608001516001600160a01b031681526020018463ffffffff1681525090506125ad81613133565b95505050505050610efe565b50506040805160008152602081019091529150610efe9050565b6000828201838110156117e5576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60006117e583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061320f565b60008261267e575060006117e8565b8282028284828161268b57fe5b04146117e55760405162461bcd60e51b81526004018080602001828103825260218152602001806147cd6021913960400191505060405180910390fd5b60006117e583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506132b1565b60408051600680825260e08201909252606091829190816020015b606081526020019060019003908161272557505083519091506127479061330b565b8160008151811061275457fe5b602002602001018190525061277583602001516001600160a01b031661331e565b8160018151811061278257fe5b6020026020010181905250600083604001515190506060816040519080825280602002602001820160405280156127cd57816020015b60608152602001906001900390816127b85790505b50905060005b8281101561281a576127fb866040015182815181106127ee57fe5b602002602001015161330b565b82828151811061280757fe5b60209081029190910101526001016127d3565b5061282481613341565b8360028151811061283157fe5b602002602001018190525060608260405190808252806020026020018201604052801561287257816020015b606081526020019060019003908161285d5790505b50905060005b838110156128c8576128a98760600151828151811061289357fe5b60200260200101516001600160a01b031661331e565b8282815181106128b557fe5b6020908102919091010152600101612878565b506128d281613341565b846003815181106128df57fe5b602002602001018190525060608360405190808252806020026020018201604052801561292057816020015b606081526020019060019003908161290b5790505b50905060005b84811015612960576129418860800151828151811061289357fe5b82828151811061294d57fe5b6020908102919091010152600101612926565b5061296a81613341565b8560048151811061297757fe5b60200260200101819052506129998760a0015167ffffffffffffffff1661330b565b856005815181106129a657fe5b60200260200101819052506129ba85613341565b979650505050505050565b6129cd614510565b60006129d8836133cb565b9150915080612a185760405162461bcd60e51b815260040180806020018281038252602481526020018061485b6024913960400191505060405180910390fd5b61161482613596565b60006117e583836040518060400160405280601881526020017f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000815250613a1a565b60006008821115612a8c57612a85836007198401600a0a63ffffffff61262d16565b90506117e8565b6117e5836008849003600a0a63ffffffff61266f16565b604080516020808252818301909252600091606091906020820181803683375050506020810184905290506000805b60208160ff161015612b1957828160ff1681518110612aed57fe5b01602001516001600160f81b03191615612b0c57600190910190612b11565b612b19565b600101612ad2565b50600760ff82161015612b3157600092505050610efe565b816005820360ff1681518110612b4357fe5b6020910101516001600160f81b031916602d60f81b14612b6857600092505050610efe565b816001820360ff1681518110612b7a57fe5b6020910101516001600160f81b031916604d60f81b14612b9f57600092505050610efe565b5060019392505050565b612bb1614468565b6000612bbc83613a7c565b9150915080612bfc5760405162461bcd60e51b815260040180806020018281038252602481526020018061461e6024913960400191505060405180910390fd5b612c04614510565b602080840180516001600160a01b0390811684526040808701518585015291511660009081526002909252812054905b846040015151811015612c8557612c6285604001518281518110612c5457fe5b602002602001015183613ce0565b85604001518281518110612c7257fe5b6020908102919091010152600101612c34565b506080840151604083015260056060830152612ca082613596565b5050505050565b612caf6144b4565b6000612cb96144b4565b612cc1614547565b612cd2612ccd86613d19565b613d3e565b90506000805b612ce183613d88565b15612dd95780612d0357612cfc612cf784613da9565b613df7565b8452612dd1565b8060011415612d3057612d1d612d1884613da9565b613eae565b6001600160a01b03166020850152612dd1565b8060021415612d4f57612d45612cf784613da9565b6040850152612dd1565b8060031415612d7757612d64612d1884613da9565b6001600160a01b03166060850152612dd1565b8060041415612d9f57612d8c612d1884613da9565b6001600160a01b03166080850152612dd1565b8060051415612dcc57612db4612cf784613da9565b67ffffffffffffffff1660a085015260019150612dd1565b612dd9565b600101612cd8565b5091935090915050915091565b60208101516000906001600160a01b0316612f1d578160a0015167ffffffffffffffff16421115612e1957506001610efe565b8160400151471015612e2d57506003610efe565b606082015160408084015190516000926001600160a01b0316916127109184818181858888f193505050503d8060008114612e84576040519150601f19603f3d011682016040523d82523d6000602084013e612e89565b606091505b5050905080612e9c575060049050610efe565b7f471eb9cc1ffe55ffadf15b32595415eb9d80f22e761d24bd6dffc607e1284d5983602001518460600151856040015160405180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b03168152602001828152602001935050505060405180910390a15060009050610efe565b8160a0015167ffffffffffffffff16421115612f3b57506001610efe565b81516020808401516001600160a01b031660009081526003909152604090205414612f6857506002610efe565b602080830151604080516370a0823160e01b815230600482015290516000936001600160a01b03909316926370a082319261c3509260248083019392829003018187803b158015612fb857600080fd5b5086fa158015612fcc573d6000803e3d6000fd5b50505050506040513d6020811015612fe357600080fd5b50516040840151909150811015612ffe575060039050610efe565b600083602001516001600160a01b031663a9059cbb61c350866060015187604001516040518463ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600088803b15801561306f57600080fd5b5087f1158015613083573d6000803e3d6000fd5b50505050506040513d602081101561309a57600080fd5b505190508015613127577f471eb9cc1ffe55ffadf15b32595415eb9d80f22e761d24bd6dffc607e1284d5984602001518560600151866040015160405180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b03168152602001828152602001935050505060405180910390a15060009150610efe9050565b5060059150610efe9050565b60408051600480825260a08201909252606091829190816020015b606081526020019060019003908161314e57505083519091506131709061330b565b8160008151811061317d57fe5b6020026020010181905250613195836020015161330b565b816001815181106131a257fe5b60200260200101819052506131c383604001516001600160a01b031661331e565b816002815181106131d057fe5b60200260200101819052506131ee836060015163ffffffff1661330b565b816003815181106131fb57fe5b6020026020010181905250610ed281613341565b6000818361329b5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613260578181015183820152602001613248565b50505050905090810190601f16801561328d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816132a757fe5b0495945050505050565b600081848411156133035760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613260578181015183820152602001613248565b505050900390565b60606117e861331983613ec8565b613fae565b60408051600560a21b8318601482015260348101909152606090610ed281613fae565b60608151600014156133625750604080516000815260208101909152610efe565b60608260008151811061337157fe5b602002602001015190506000600190505b83518110156133b2576133a88285838151811061339b57fe5b6020026020010151614000565b9150600101613382565b50610ed26133c5825160c060ff1661407d565b82614000565b6133d3614510565b60006133dd614510565b6133e5614547565b6133f1612ccd86613d19565b90506000805b61340083613d88565b15612dd9578061342657613416612d1884613da9565b6001600160a01b0316845261358e565b80600114156134c757606061344261343d85613da9565b614175565b9050805160405190808252806020026020018201604052801561346f578160200160208202803683370190505b50602086015260005b81518110156134c05761349d82828151811061349057fe5b6020026020010151613df7565b866020015182815181106134ad57fe5b6020908102919091010152600101613478565b505061358e565b80600214156135695760606134de61343d85613da9565b9050805160405190808252806020026020018201604052801561350b578160200160208202803683370190505b50604086015260005b81518110156134c05761353982828151811061352c57fe5b6020026020010151613eae565b8660400151828151811061354957fe5b6001600160a01b0390921660209283029190910190910152600101613514565b8060031415612dcc5761357e612cf784613da9565b63ffffffff166060850152600191505b6001016133f7565b80516001600160a01b03166137c05760005b8160200151518110156137ba576000826040015182815181106135c757fe5b60200260200101516001600160a01b0316612710846020015184815181106135eb57fe5b60209081029190910101516040516000818181858888f193505050503d8060008114613633576040519150601f19603f3d011682016040523d82523d6000602084013e613638565b606091505b50509050806136fb577f203f9f67a785f4f81be4d48b109aa0c498d1bc8097ecc2627063f480cc5fe73e83600001518460400151848151811061367757fe5b60200260200101518560200151858151811061368f57fe5b6020026020010151866060015160405180856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b031681526020018381526020018263ffffffff1663ffffffff16815260200194505050505060405180910390a16137b1565b7fd468d4fa5e8fb4adc119b29a983fd0785e04af5cb8b7a3a69a47270c54b6901a83600001518460400151848151811061373157fe5b60200260200101518560200151858151811061374957fe5b6020026020010151866060015160405180856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b031681526020018381526020018263ffffffff1663ffffffff16815260200194505050505060405180910390a15b506001016135a8565b50613a17565b60005b816020015151811015613a1557600082600001516001600160a01b031663a9059cbb61c350856040015185815181106137f857fe5b60200260200101518660200151868151811061381057fe5b60200260200101516040518463ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600088803b15801561386757600080fd5b5087f115801561387b573d6000803e3d6000fd5b50505050506040513d602081101561389257600080fd5b505190508015613956577fd468d4fa5e8fb4adc119b29a983fd0785e04af5cb8b7a3a69a47270c54b6901a8360000151846040015184815181106138d257fe5b6020026020010151856020015185815181106138ea57fe5b6020026020010151866060015160405180856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b031681526020018381526020018263ffffffff1663ffffffff16815260200194505050505060405180910390a1613a0c565b7f203f9f67a785f4f81be4d48b109aa0c498d1bc8097ecc2627063f480cc5fe73e83600001518460400151848151811061398c57fe5b6020026020010151856020015185815181106139a457fe5b6020026020010151866060015160405180856001600160a01b03166001600160a01b03168152602001846001600160a01b03166001600160a01b031681526020018381526020018263ffffffff1663ffffffff16815260200194505050505060405180910390a15b506001016137c3565b505b50565b60008183613a695760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613260578181015183820152602001613248565b50828481613a7357fe5b06949350505050565b613a84614468565b6000613a8e614468565b613a96614547565b613aa2612ccd86613d19565b90506000805b613ab183613d88565b15612dd95780613ace57613ac7612cf784613da9565b8452613cd8565b8060011415613af657613ae3612d1884613da9565b6001600160a01b03166020850152613cd8565b8060021415613b85576060613b0d61343d85613da9565b90508051604051908082528060200260200182016040528015613b3a578160200160208202803683370190505b50604086015260005b8151811015613b7e57613b5b82828151811061349057fe5b86604001518281518110613b6b57fe5b6020908102919091010152600101613b43565b5050613cd8565b8060031415613c1a576060613b9c61343d85613da9565b90508051604051908082528060200260200182016040528015613bc9578160200160208202803683370190505b50606086015260005b8151811015613b7e57613bea82828151811061352c57fe5b86606001518281518110613bfa57fe5b6001600160a01b0390921660209283029190910190910152600101613bd2565b8060041415613caf576060613c3161343d85613da9565b90508051604051908082528060200260200182016040528015613c5e578160200160208202803683370190505b50608086015260005b8151811015613b7e57613c7f82828151811061352c57fe5b86608001518281518110613c8f57fe5b6001600160a01b0390921660209283029190910190910152600101613c67565b8060051415612dcc57613cc4612cf784613da9565b67ffffffffffffffff1660a0850152600191505b600101613aa8565b60006008821115613d0257612a85836007198401600a0a63ffffffff61266f16565b6117e5836008849003600a0a63ffffffff61262d16565b613d21614567565b506040805180820190915281518152602082810190820152919050565b613d46614547565b613d4f82614246565b613d5857600080fd5b6000613d678360200151614276565b60208085015160408051808201909152868152920190820152915050919050565b6000613d92614567565b505080518051602091820151919092015191011190565b613db1614567565b613dba82613d88565b613dc357600080fd5b60208201516000613dd3826142d9565b80830160209586015260408051808201909152908152938401919091525090919050565b805160009015801590613e0c57508151602110155b613e1557600080fd5b6000613e248360200151614276565b90508083600001511015613e7f576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b825160208085015183018051928490039291831015613ea557826020036101000a820491505b50949350505050565b8051600090601514613ebf57600080fd5b6117e882613df7565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff198416613f0c57506018613f30565b6fffffffffffffffffffffffffffffffff198416613f2c57506010613f30565b5060005b6020811015613f6657818181518110613f4557fe5b01602001516001600160f81b03191615613f5e57613f66565b600101613f30565b60008160200390506060816040519080825280601f01601f191660200182016040528015613f9b576020820181803683370190505b5080830196909652508452509192915050565b606081516001148015613fe05750607f60f81b82600081518110613fce57fe5b01602001516001600160f81b03191611155b15613fec575080610efe565b6117e8613ffe8351608060ff1661407d565b835b6060806040519050835180825260208201818101602087015b81831015614031578051835260209283019201614019565b50855184518101855292509050808201602086015b8183101561405e578051835260209283019201614046565b508651929092011591909101601f01601f191660405250905092915050565b60606801000000000000000083106140cd576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b604080516001808252818301909252606091602082018180368337019050509050603784116141275782840160f81b8160008151811061410957fe5b60200101906001600160f81b031916908160001a90535090506117e8565b606061413285613ec8565b90508381510160370160f81b8260008151811061414b57fe5b60200101906001600160f81b031916908160001a90535061416c8282614000565b95945050505050565b606061418082614246565b61418957600080fd5b60006141948361440c565b90506060816040519080825280602002602001820160405280156141d257816020015b6141bf614567565b8152602001906001900390816141b75790505b50905060006141e48560200151614276565b60208601510190506000805b8481101561423b57614201836142d9565b915060405180604001604052808381526020018481525084828151811061422457fe5b6020908102919091010152918101916001016141f0565b509195945050505050565b805160009061425757506000610efe565b6020820151805160001a9060c0821015612b9f57600092505050610efe565b8051600090811a6080811015614290576000915050610efe565b60b88110806142ab575060c081108015906142ab575060f881105b156142ba576001915050610efe565b60c08110156142ce5760b519019050610efe565b60f519019050610efe565b80516000908190811a60808110156142f45760019150614405565b60b881101561430957607e1981019150614405565b60c081101561438357600060b78203600186019550806020036101000a86510491506001810182019350508083101561437d576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b50614405565b60f88110156143985760be1981019150614405565b600060f78203600186019550806020036101000a865104915060018101820193505080831015614403576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b805160009061441d57506000610efe565b600080905060006144318460200151614276565b602085015185519181019250015b8082101561445f57614450826142d9565b6001909301929091019061443f565b50909392505050565b6040518060c001604052806000801916815260200160006001600160a01b03168152602001606081526020016060815260200160608152602001600067ffffffffffffffff1681525090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60408051608081018252600080825260208201819052918101829052606081019190915290565b604051806080016040528060006001600160a01b031681526020016060815260200160608152602001600063ffffffff1681525090565b604051806040016040528061455a614567565b8152602001600081525090565b60405180604001604052806000815260200160008152509056fe6f6e6c79207374616b696e672073797374656d20636f6e74726163742063616e2063616c6c20746869732066756e6374696f6e746865206d6573736167652073656e646572206d75737420626520696e63656e746976697a6520636f6e7472616374466f72206d696e69546f6b656e2c20746865207472616e7366657220616d6f756e74206d757374206e6f74206265206c657373207468616e2031756e7265636f676e697a6564207472616e736665724f75742073796e207061636b61676565787069726554696d65206d7573742062652074776f206d696e75746573206c61746572616d6f756e7420697320746f6f206c617267652c20657863656564206d6178696d756d206265703220746f6b656e20616d6f756e7474686520636f6e747261637420686173206e6f74206265656e20626f756e6420746f20616e79206265703220746f6b656e726563656976656420424e4220616d6f756e742073686f756c64206265206e6f206c657373207468616e207468652073756d206f66207472616e736665724f757420424e4220616d6f756e7420616e64206d696e696d756d2072656c6179466565616d6f756e7420697320746f6f206c617267652c2075696e74323536206f766572666c6f774c656e677468206f6620726563697069656e74416464727320646f65736e277420657175616c20746f206c656e677468206f6620726566756e644164647273696e76616c6964207472616e7366657220616d6f756e743a20707265636973696f6e206c6f737320696e20616d6f756e7420636f6e76657273696f6e536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77726563656976656420424e4220616d6f756e742073686f756c64206265206e6f206c657373207468616e20746865206d696e696d756d2072656c6179466565746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e7472616374756e7265636f676e697a6564207472616e736665724f75742061636b207061636b6167654c656e677468206f6620726563697069656e74416464727320646f65736e277420657175616c20746f206c656e677468206f6620616d6f756e7473746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e7472616374746865206d73672073656e646572206d75737420626520746f6b656e4d616e6167657274686520636f6e7472616374206e6f7420696e69742079657400000000000000726563656976656420424e4220616d6f756e742073686f756c64206265206e6f206c657373207468616e207468652073756d206f66207472616e7366657220424e4220616d6f756e7420616e642072656c6179466565696e76616c696420726563656976656420424e4220616d6f756e743a20707265636973696f6e206c6f737320696e20616d6f756e7420636f6e76657273696f6ea264697066735822122012cb49df8f867c0c8903152f4f4e8058086f9ead137f1a15b2400e401b8e252f64736f6c63430006040033", + }, + { + ContractAddr: common.HexToAddress(StakingContract), + CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/8cfa94e657670d60ac1ff0563cddcf4664f77227", + Code: "6080604052600436106103855760003560e01c806370fd5bad116101d1578063b88a802f11610102578063d7ecfcb6116100a0578063f9a2bbc71161006f578063f9a2bbc714610c40578063fa03f79714610c55578063fc3e590814610671578063fd6a687914610c6a5761038c565b8063d7ecfcb614610819578063dc927faf14610bd1578063edc1a5b014610be6578063f45fd80b14610bfb5761038c565b8063c2117d82116100dc578063c2117d8214610ae7578063c81b166214610afc578063c8509d8114610b11578063d61b9b9314610b965761038c565b8063b88a802f14610a82578063baaafd3b14610a97578063bf8546ca14610aac5761038c565b806396713da91161016f578063a78abc1611610149578063a78abc1614610964578063ab51bb961461098d578063ac431751146109a2578063b14315df14610a6d5761038c565b806396713da9146109255780639dc092621461093a578063a1a11bf51461094f5761038c565b806375d47a0a116101ab57806375d47a0a146108765780637942fd051461088b578063831d65d1146108a057806392b888a41461061d5761038c565b806370fd5bad14610819578063718a8aa81461082e57806375aca593146108435761038c565b80633fdfa7e4116102b6578063552aaf931161025457806369b635b61161022357806369b635b6146107865780636bd8f8041461079b5780636e47b482146107d15780636fb7f7eb146107e65761038c565b8063552aaf93146107325780635d17c8bd146107475780635d499b1b1461075c57806362b171d2146107715761038c565b8063493279b111610290578063493279b1146106b05780634bf6c882146106dc5780634d99dd16146106f157806351e806721461071d5761038c565b80633fdfa7e414610671578063413d9c3a1461068657806343756e5c1461069b5761038c565b806311fe9ec6116103235780632fdeb111116102fd5780632fdeb11114610632578063333ad3e71461064757806334c433541461065c5780633dffc3871461061d5761038c565b806311fe9ec6146105bf578063151817e3146105f257806317c9efb01461061d5761038c565b80630bee7a671161035f5780630bee7a67146104515780630c7957151461047f5780630e2374a5146104945780631182b875146104c55761038c565b8063026e402b1461039157806302985992146103bf578063047636d1146103e65761038c565b3661038c57005b600080fd5b6103bd600480360360408110156103a757600080fd5b506001600160a01b038135169060200135610c7f565b005b3480156103cb57600080fd5b506103d46111bc565b60408051918252519081900360200190f35b3480156103f257600080fd5b506104196004803603602081101561040957600080fd5b50356001600160a01b03166111c2565b6040518082606080838360005b8381101561043e578181015183820152602001610426565b5050505090500191505060405180910390f35b34801561045d57600080fd5b50610466611216565b6040805163ffffffff9092168252519081900360200190f35b34801561048b57600080fd5b506103d461121b565b3480156104a057600080fd5b506104a9611221565b604080516001600160a01b039092168252519081900360200190f35b3480156104d157600080fd5b5061054a600480360360408110156104e857600080fd5b60ff8235169190810190604081016020820135600160201b81111561050c57600080fd5b82018360208201111561051e57600080fd5b803590602001918460018302840111600160201b8311171561053f57600080fd5b509092509050611227565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561058457818101518382015260200161056c565b50505050905090810190601f1680156105b15780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156105cb57600080fd5b506103d4600480360360208110156105e257600080fd5b50356001600160a01b03166113e3565b3480156105fe57600080fd5b506106076113fe565b6040805160ff9092168252519081900360200190f35b34801561062957600080fd5b50610607611403565b34801561063e57600080fd5b506103d4611408565b34801561065357600080fd5b5061046661140e565b34801561066857600080fd5b506103d4611413565b34801561067d57600080fd5b5061060761141e565b34801561069257600080fd5b506103d4611423565b3480156106a757600080fd5b506104a961142a565b3480156106bc57600080fd5b506106c5611430565b6040805161ffff9092168252519081900360200190f35b3480156106e857600080fd5b50610607611435565b6103bd6004803603604081101561070757600080fd5b506001600160a01b03813516906020013561143a565b34801561072957600080fd5b506104a9611a62565b34801561073e57600080fd5b50610607611a68565b34801561075357600080fd5b506103d4611a6d565b34801561076857600080fd5b506103d4611a73565b34801561077d57600080fd5b506103d4611a7c565b34801561079257600080fd5b506103d4611c1c565b6103bd600480360360608110156107b157600080fd5b506001600160a01b03813581169160208101359091169060400135611c22565b3480156107dd57600080fd5b506104a961230b565b3480156107f257600080fd5b506103d46004803603602081101561080957600080fd5b50356001600160a01b0316612311565b34801561082557600080fd5b5061060761232c565b34801561083a57600080fd5b50610607612331565b34801561084f57600080fd5b506103d46004803603602081101561086657600080fd5b50356001600160a01b0316612336565b34801561088257600080fd5b506104a9612351565b34801561089757600080fd5b50610607612357565b3480156108ac57600080fd5b506103bd600480360360408110156108c357600080fd5b60ff8235169190810190604081016020820135600160201b8111156108e757600080fd5b8201836020820111156108f957600080fd5b803590602001918460018302840111600160201b8311171561091a57600080fd5b50909250905061235c565b34801561093157600080fd5b50610607612624565b34801561094657600080fd5b506104a9612629565b34801561095b57600080fd5b506104a961262f565b34801561097057600080fd5b50610979612635565b604080519115158252519081900360200190f35b34801561099957600080fd5b50610466611a68565b3480156109ae57600080fd5b506103bd600480360360408110156109c557600080fd5b810190602081018135600160201b8111156109df57600080fd5b8201836020820111156109f157600080fd5b803590602001918460018302840111600160201b83111715610a1257600080fd5b919390929091602081019035600160201b811115610a2f57600080fd5b820183602082011115610a4157600080fd5b803590602001918460018302840111600160201b83111715610a6257600080fd5b50909250905061263e565b348015610a7957600080fd5b50610607612dd0565b348015610a8e57600080fd5b506103d4612dd5565b348015610aa357600080fd5b506103d4612f72565b348015610ab857600080fd5b506103d460048036036040811015610acf57600080fd5b506001600160a01b0381358116916020013516612f7d565b348015610af357600080fd5b506103d4612faa565b348015610b0857600080fd5b506104a9612fb0565b348015610b1d57600080fd5b506103bd60048036036040811015610b3457600080fd5b60ff8235169190810190604081016020820135600160201b811115610b5857600080fd5b820183602082011115610b6a57600080fd5b803590602001918460018302840111600160201b83111715610b8b57600080fd5b509092509050612fb6565b348015610ba257600080fd5b506103d460048036036040811015610bb957600080fd5b506001600160a01b03813581169160200135166131d9565b348015610bdd57600080fd5b506104a9613204565b348015610bf257600080fd5b506103d461320a565b348015610c0757600080fd5b506103d460048036036060811015610c1e57600080fd5b506001600160a01b038135811691602081013582169160409091013516613217565b348015610c4c57600080fd5b506104a961324c565b348015610c6157600080fd5b506103d4613252565b348015610c7657600080fd5b506104a9613258565b60105460ff1660021415610ccb576040805162461bcd60e51b815260206004820152600e60248201526d4e6f2072652d656e7472616e637960901b604482015290519081900360640190fd5b6010805460ff19166002179055806402540be4003406158015610cf357506402540be4008106155b610d44576040805162461bcd60e51b815260206004820152601c60248201527f707265636973696f6e206c6f737320696e20636f6e76657273696f6e00000000604482015290519081900360640190fd5b60005460ff16610d87576638d7ea4c6800006001908155662386f26fc1000060025568056bc75e2d631000006003556108fc6011556000805460ff191690911790555b600354821015610dde576040805162461bcd60e51b815260206004820152601760248201527f696e76616c69642064656c656761746520616d6f756e74000000000000000000604482015290519081900360640190fd5b600154610df290839063ffffffff61325e16565b341015610e3d576040805162461bcd60e51b81526020600482015260146024820152736e6f7420656e6f756768206d73672076616c756560601b604482015290519081900360640190fd5b601154604051600091339183818181818787f1925050503d8060008114610e80576040519150601f19603f3d011682016040523d82523d6000602084013e610e85565b606091505b5050905080610ecf576040805162461bcd60e51b815260206004820152601160248201527034b73b30b634b2103232b632b3b0ba37b960791b604482015290519081900360640190fd5b6000610ee6846402540be40063ffffffff6132bf16565b90506000610efa348663ffffffff61330116565b90506000610f136002548361330190919063ffffffff16565b6040805160038082526080820190925291925060609190816020015b6060815260200190600190039081610f2f579050509050610f4f33613343565b81600081518110610f5c57fe5b6020026020010181905250610f79886001600160a01b0316613343565b81600181518110610f8657fe5b6020026020010181905250610f9a84613366565b81600281518110610fa757fe5b60200260200101819052506060610fc76001610fc284613379565b613403565b8051602080830191909120600f80546000908152600a845260408082209390935581546001908101909255338152600b909352912080549091019055905061200063f7a251d7601083611025876402540be40063ffffffff6132bf16565b6040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b8381101561108357818101518382015260200161106b565b50505050905090810190601f1680156110b05780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b1580156110d157600080fd5b505af11580156110e5573d6000803e3d6000fd5b5061100492506108fc915061110290508a8663ffffffff61325e16565b6040518115909202916000818181858888f1935050505015801561112a573d6000803e3d6000fd5b506002546040516110029180156108fc02916000818181858888f1935050505015801561115b573d6000803e3d6000fd5b50604080518981526020810185905281516001600160a01b038c169233927f5f32ed2794e2e72d19e3cb2320e8820a499c4204887372beba51f5e61c040867929081900390910190a350506010805460ff1916600117905550505050505050565b60035481565b6111ca615193565b6111d2615193565b6001600160a01b0383166000818152600b60209081526040808320548552838352600c82528083205485830152928252600d9052819020549082015290505b919050565b606481565b6108fc81565b61200181565b606033612000146112695760405162461bcd60e51b815260040180806020018281038252602f81526020018061539b602f913960400191505060405180910390fd5b60005460ff166112ac576638d7ea4c6800006001908155662386f26fc1000060025568056bc75e2d631000006003556108fc6011556000805460ff191690911790555b6112b46151b1565b6112fb6112f685858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061348992505050565b6134ae565b9050600061131061130b836134f8565b613546565b90506000606060ff8316600414156113355761132b846135fd565b909250905061138c565b60ff83166005141561134a5761132b846137dd565b6040805162461bcd60e51b8152602060048201526012602482015271756e6b6e6f776e206576656e74207479706560701b604482015290519081900360640190fd5b63ffffffff8216156113d8576040805163ffffffff84168152905160ff8516917f391d6e5ea6ab6c49b9a0abb1782cae5def8d711f973b00c729658c0b2a80b31b919081900360200190a25b979650505050505050565b6001600160a01b031660009081526006602052604090205490565b600581565b600181565b60015481565b606581565b662386f26fc1000081565b600381565b620a8c0081565b61100181565b603881565b600881565b60105460ff1660021415611486576040805162461bcd60e51b815260206004820152600e60248201526d4e6f2072652d656e7472616e637960901b604482015290519081900360640190fd5b6010805460ff19166002179055806402540be40034061580156114ae57506402540be4008106155b6114ff576040805162461bcd60e51b815260206004820152601c60248201527f707265636973696f6e206c6f737320696e20636f6e76657273696f6e00000000604482015290519081900360640190fd5b60005460ff16611542576638d7ea4c6800006001908155662386f26fc1000060025568056bc75e2d631000006003556108fc6011556000805460ff191690911790555b600154341015611590576040805162461bcd60e51b81526020600482015260146024820152736e6f7420656e6f7567682072656c61792066656560601b604482015290519081900360640190fd5b60035482101561164b573360009081526005602090815260408083206001600160a01b03871684529091529020548214611602576040805162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a5908185b5bdd5b9d60921b604482015290519081900360640190fd5b600254821161164b576040805162461bcd60e51b815260206004820152601060248201526f6e6f7420656e6f7567682066756e647360801b604482015290519081900360640190fd5b3360009081526007602090815260408083206001600160a01b03871684529091529020544210156116c3576040805162461bcd60e51b815260206004820152601a60248201527f70656e64696e6720756e64656c65676174696f6e206578697374000000000000604482015290519081900360640190fd5b604080518082018252601081526f6e6f7420656e6f7567682066756e647360801b602080830191909152336000908152600582528381206001600160a01b03881682529091529182205461171e91859063ffffffff6139f916565b905080156117665760025481116117665760405162461bcd60e51b81526004018080602001828103825260258152602001806153766025913960400191505060405180910390fd5b600061177d846402540be40063ffffffff6132bf16565b600254909150349060009061179990839063ffffffff61330116565b6040805160038082526080820190925291925060609190816020015b60608152602001906001900390816117b55790505090506117d533613343565b816000815181106117e257fe5b60200260200101819052506117ff886001600160a01b0316613343565b8160018151811061180c57fe5b602002602001018190525061182084613366565b8160028151811061182d57fe5b602002602001018190525060606118486002610fc284613379565b8051602080830191909120600f80546000908152600a845260408082209390935581546001908101909255338152600c909352912080549091019055905061189942620a8c0063ffffffff61325e16565b3360009081526007602090815260408083206001600160a01b038e16845290915290205561200063f7a251d76010836118dd876402540be40063ffffffff6132bf16565b6040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b8381101561193b578181015183820152602001611923565b50505050905090810190601f1680156119685780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b15801561198957600080fd5b505af115801561199d573d6000803e3d6000fd5b5050604051611004925085156108fc02915085906000818181858888f193505050501580156119d0573d6000803e3d6000fd5b506002546040516110029180156108fc02916000818181858888f19350505050158015611a01573d6000803e3d6000fd5b50604080518981526020810185905281516001600160a01b038c169233927fdf0b6ac27f3f3bb31cee3dab0f4fe40cc19c6a3f8daaec52e06b261e58a12519929081900390910190a350506010805460ff1916600117905550505050505050565b61200081565b600081565b60025481565b6402540be40081565b60105460009060ff1660021415611acb576040805162461bcd60e51b815260206004820152600e60248201526d4e6f2072652d656e7472616e637960901b604482015290519081900360640190fd5b506010805460ff191660021790553360009081526008602052604090205480611b32576040805162461bcd60e51b81526020600482015260146024820152736e6f20756e64656c6567617465642066756e647360601b604482015290519081900360640190fd5b336000818152600860205260408082208290556011549051919291849084818181858888f193505050503d8060008114611b88576040519150601f19603f3d011682016040523d82523d6000602084013e611b8d565b606091505b5050905080611bd5576040805162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b60408051838152905133917fc712d133b8d448221aaed2198ed1f0db6dfc860fb01bc3a630916fe6cbef946f919081900360200190a2506010805460ff1916600117905590565b60035490565b60105460ff1660021415611c6e576040805162461bcd60e51b815260206004820152600e60248201526d4e6f2072652d656e7472616e637960901b604482015290519081900360640190fd5b6010805460ff19166002179055806402540be4003406158015611c9657506402540be4008106155b611ce7576040805162461bcd60e51b815260206004820152601c60248201527f707265636973696f6e206c6f737320696e20636f6e76657273696f6e00000000604482015290519081900360640190fd5b60005460ff16611d2a576638d7ea4c6800006001908155662386f26fc1000060025568056bc75e2d631000006003556108fc6011556000805460ff191690911790555b826001600160a01b0316846001600160a01b03161415611d88576040805162461bcd60e51b815260206004820152601460248201527334b73b30b634b2103932b232b632b3b0ba34b7b760611b604482015290519081900360640190fd5b600154341015611dd6576040805162461bcd60e51b81526020600482015260146024820152736e6f7420656e6f7567682072656c61792066656560601b604482015290519081900360640190fd5b600354821015611e1e576040805162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a5908185b5bdd5b9d60921b604482015290519081900360640190fd5b3360009081526009602090815260408083206001600160a01b03888116855290835281842090871684529091529020544210801590611e8c57503360009081526009602090815260408083206001600160a01b03878116855290835281842090881684529091529020544210155b611edd576040805162461bcd60e51b815260206004820152601a60248201527f70656e64696e6720726564656c65676174696f6e206578697374000000000000604482015290519081900360640190fd5b604080518082018252601081526f6e6f7420656e6f7567682066756e647360801b602080830191909152336000908152600582528381206001600160a01b038916825290915291822054611f3891859063ffffffff6139f916565b90508015611f80576002548111611f805760405162461bcd60e51b815260040180806020018281038252602581526020018061527a6025913960400191505060405180910390fd5b6000611f97846402540be40063ffffffff6132bf16565b6002549091503490600090611fb390839063ffffffff61330116565b60408051600480825260a0820190925291925060609190816020015b6060815260200190600190039081611fcf579050509050611fef33613343565b81600081518110611ffc57fe5b6020026020010181905250612019896001600160a01b0316613343565b8160018151811061202657fe5b6020026020010181905250612043886001600160a01b0316613343565b8160028151811061205057fe5b602002602001018190525061206484613366565b8160038151811061207157fe5b6020026020010181905250606061208c6003610fc284613379565b8051602080830191909120600f80546000908152600a845260408082209390935581546001908101909255338152600d90935291208054909101905590506120dd42620a8c0063ffffffff61325e16565b3360009081526009602090815260408083206001600160a01b038e81168552908352818420908f16845290915290205561212042620a8c0063ffffffff61325e16565b3360009081526009602090815260408083206001600160a01b038f81168552908352818420908e16845290915290205561200063f7a251d7601083612170876402540be40063ffffffff6132bf16565b6040518463ffffffff1660e01b8152600401808460ff1660ff16815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156121ce5781810151838201526020016121b6565b50505050905090810190601f1680156121fb5780820380516001836020036101000a031916815260200191505b50945050505050600060405180830381600087803b15801561221c57600080fd5b505af1158015612230573d6000803e3d6000fd5b5050604051611004925085156108fc02915085906000818181858888f19350505050158015612263573d6000803e3d6000fd5b506002546040516110029180156108fc02916000818181858888f19350505050158015612294573d6000803e3d6000fd5b50886001600160a01b03168a6001600160a01b0316336001600160a01b03167fdb0d03fdfcb145c486c442659e6a341a8828985505097cb5190afcf541e840158b87604051808381526020018281526020019250505060405180910390a450506010805460ff191660011790555050505050505050565b61100581565b6001600160a01b031660009081526004602052604090205490565b600281565b601081565b6001600160a01b031660009081526008602052604090205490565b61100881565b600b81565b336120001461239c5760405162461bcd60e51b815260040180806020018281038252602f81526020018061539b602f913960400191505060405180910390fd5b60005460ff166123df576638d7ea4c6800006001908155662386f26fc1000060025568056bc75e2d631000006003556108fc6011556000805460ff191690911790555b6123e76151b1565b6124296112f684848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061348992505050565b905060008060606000805b61243d86613a90565b156124a8578061245a5761245361130b876134f8565b94506124a0565b80600114156124765761246f61130b876134f8565b93506124a0565b806002141561249b5761249061248b876134f8565b613ab1565b9250600191506124a0565b6124a8565b600101612434565b816124ee576040805162461bcd60e51b81526020600482015260116024820152701c9b1c08191958dbd9194819985a5b1959607a1b604482015290519081900360640190fd5b6124f783613b21565b61253a576040805162461bcd60e51b815260206004820152600f60248201526e0eee4dedcce40e0c2c6d640d0c2e6d608b1b604482015290519081900360640190fd5b6125466112f684613489565b9550600061255661130b886134f8565b90506125606151b1565b61256988613a90565b1561258c576125856112f661258061248b8b6134f8565b613489565b90506125cd565b6040805162461bcd60e51b8152602060048201526011602482015270656d7074792061636b207061636b61676560781b604482015290519081900360640190fd5b60ff8216600114156125e9576125e4818888613b75565b612617565b60ff821660021415612600576125e4818888613f2c565b60ff82166003141561134a576125e48188886141f9565b5050505050505050505050565b600981565b61100781565b61100681565b60005460ff1681565b60005460ff16612695576040805162461bcd60e51b815260206004820152601960248201527f74686520636f6e7472616374206e6f7420696e69742079657400000000000000604482015290519081900360640190fd5b33611007146126d55760405162461bcd60e51b815260040180806020018281038252602e8152602001806152ec602e913960400191505060405180910390fd5b61273684848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600a81526972656c6179657246656560b01b6020820152915061455e9050565b1561289c5760208114612790576040805162461bcd60e51b815260206004820152601d60248201527f6c656e677468206f662072656c61796572466565206d69736d61746368000000604482015290519081900360640190fd5b604080516020601f84018190048102820181019092528281526000916127ce9185858083850183828082843760009201919091525061464592505050565b905060035481106128105760405162461bcd60e51b815260040180806020018281038252602e81526020018061531a602e913960400191505060405180910390fd5b60025481116128505760405162461bcd60e51b815260040180806020018281038252602e815260200180615348602e913960400191505060405180910390fd5b6402540be4008106156128945760405162461bcd60e51b815260040180806020018281038252602c8152602001806152c0602c913960400191505060405180910390fd5b600155612d3e565b61290084848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600d81526c62534352656c6179657246656560981b6020820152915061455e9050565b15612a62576020811461295a576040805162461bcd60e51b815260206004820181905260248201527f6c656e677468206f662062534352656c61796572466565206d69736d61746368604482015290519081900360640190fd5b604080516020601f84018190048102820181019092528281526000916129989185858083850183828082843760009201919091525061464592505050565b9050806129d65760405162461bcd60e51b81526004018080602001828103825260228152602001806153ca6022913960400191505060405180910390fd5b6001548110612a165760405162461bcd60e51b815260040180806020018281038252602e81526020018061521b602e913960400191505060405180910390fd5b6402540be400810615612a5a5760405162461bcd60e51b815260040180806020018281038252602f8152602001806151ec602f913960400191505060405180910390fd5b600255612d3e565b612ac684848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600d81526c36b4b72232b632b3b0ba34b7b760991b6020820152915061455e9050565b15612ba85760208114612b20576040805162461bcd60e51b815260206004820181905260248201527f6c656e677468206f66206d696e44656c65676174696f6e206d69736d61746368604482015290519081900360640190fd5b604080516020601f8401819004810282018101909252828152600091612b5e9185858083850183828082843760009201919091525061464592505050565b90506001548111612ba05760405162461bcd60e51b81526004018080602001828103825260318152602001806152496031913960400191505060405180910390fd5b600355612d3e565b612c0a84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505060408051808201909152600b81526a7472616e7366657247617360a81b6020820152915061455e9050565b15612d015760208114612c64576040805162461bcd60e51b815260206004820152601e60248201527f6c656e677468206f66207472616e73666572476173206d69736d617463680000604482015290519081900360640190fd5b604080516020601f8401819004810282018101909252828152600091612ca29185858083850183828082843760009201919091525061464592505050565b905060008111612cf9576040805162461bcd60e51b815260206004820152601e60248201527f746865207472616e736665724761732063616e6e6f74206265207a65726f0000604482015290519081900360640190fd5b601155612d3e565b6040805162461bcd60e51b815260206004820152600d60248201526c756e6b6e6f776e20706172616d60981b604482015290519081900360640190fd5b7f6cdb0ac70ab7f2e2d035cca5be60d89906f2dede7648ddbd7402189c1eeed17a848484846040518080602001806020018381038352878782818152602001925080828437600083820152601f01601f191690910184810383528581526020019050858580828437600083820152604051601f909101601f19169092018290039850909650505050505050a150505050565b600481565b60105460009060ff1660021415612e24576040805162461bcd60e51b815260206004820152600e60248201526d4e6f2072652d656e7472616e637960901b604482015290519081900360640190fd5b506010805460ff191660021790553360009081526006602052604090205480612e88576040805162461bcd60e51b81526020600482015260116024820152701b9bc81c195b991a5b99c81c995dd85c99607a1b604482015290519081900360640190fd5b336000818152600660205260408082208290556011549051919291849084818181858888f193505050503d8060008114612ede576040519150601f19603f3d011682016040523d82523d6000602084013e612ee3565b606091505b5050905080612f2b576040805162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b604482015290519081900360640190fd5b60408051838152905133917f83b78188b13346b2ffb484da70d42ee27de7fbf9f2bd8045269e10ed643ccd76919081900360200190a2506010805460ff1916600117905590565b6638d7ea4c68000081565b6001600160a01b038083166000908152600760209081526040808320938516835292905220545b92915050565b60015490565b61100281565b3361200014612ff65760405162461bcd60e51b815260040180806020018281038252602f81526020018061539b602f913960400191505060405180910390fd5b60005460ff16613039576638d7ea4c6800006001908155662386f26fc1000060025568056bc75e2d631000006003556108fc6011556000805460ff191690911790555b61307882828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613b2192505050565b6130bb576040805162461bcd60e51b815260206004820152600f60248201526e0eee4dedcce40e0c2c6d640d0c2e6d608b1b604482015290519081900360640190fd5b6130c36151b1565b6131056112f684848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061348992505050565b9050600061311561130b836134f8565b905061311f6151b1565b61312883613a90565b156131465761313f6112f661258061248b866134f8565b905061318c565b6040805162461bcd60e51b8152602060048201526016602482015275656d707479206661696c2061636b207061636b61676560501b604482015290519081900360640190fd5b60ff8216600114156131a6576131a18161464a565b6131d0565b60ff8216600214156131bb576131a181614864565b60ff82166003141561134a576131a18161498e565b5050505b505050565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205490565b61100381565b68056bc75e2d6310000081565b6001600160a01b0392831660009081526009602090815260408083209486168352938152838220929094168152925290205490565b61100081565b60115481565b61100481565b6000828201838110156132b8576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b60006132b883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614af3565b60006132b883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506139f9565b60408051600560a21b83186014820152603481019091526060906132b881614b58565b6060612fa461337483614bae565b614b58565b606081516000141561339a5750604080516000815260208101909152611211565b6060826000815181106133a957fe5b602002602001015190506000600190505b83518110156133ea576133e0828583815181106133d357fe5b6020026020010151614c94565b91506001016133ba565b506132b86133fd825160c060ff16614d11565b82614c94565b6040805160028082526060828101909352829190816020015b606081526020019060019003908161341c57905050905061343f8460ff16613366565b8160008151811061344c57fe5b602002602001018190525061346083614b58565b8160018151811061346d57fe5b602002602001018190525061348181613379565b949350505050565b6134916151d1565b506040805180820190915281518152602082810190820152919050565b6134b66151b1565b6134bf82614e09565b6134c857600080fd5b60006134d78360200151614e43565b60208085015160408051808201909152868152920190820152915050919050565b6135006151d1565b61350982613a90565b61351257600080fd5b6020820151600061352282614ea6565b80830160209586015260408051808201909152908152938401919091525090919050565b80516000901580159061355b57508151602110155b61356457600080fd5b60006135738360200151614e43565b905080836000015110156135ce576040805162461bcd60e51b815260206004820152601a60248201527f6c656e677468206973206c657373207468616e206f6666736574000000000000604482015290519081900360640190fd5b8251602080850151830180519284900392918310156135f457826020036101000a820491505b50949350505050565b600060606000806000805b61361187613a90565b1561366357826136335761362c613627886134f8565b614fd9565b9150613658565b82600114156136535761364861130b886134f8565b905060019350613658565b613663565b826001019250613608565b836136a9576040805162461bcd60e51b81526020600482015260116024820152701c9b1c08191958dbd9194819985a5b1959607a1b604482015290519081900360640190fd5b60006110046001600160a01b031663727be1f8836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b1580156136f357600080fd5b505af1158015613707573d6000803e3d6000fd5b505050506040513d602081101561371d57600080fd5b505190508061374257613734600484846065614ff3565b9650965050505050506137d8565b6001600160a01b03831660009081526006602052604090205461376b908363ffffffff61325e16565b6001600160a01b038416600081815260066020908152604091829020939093558051858152905191927f7cc266c7b444f808013fa187f7b904d470a051a6564e78f482aa496581ba4bf892918290030190a260408051600080825260208201909252909750955050505050505b915091565b6000606060008060008060005b6137f388613a90565b1561385c578361381057613809613627896134f8565b9250613851565b836001141561382c57613825613627896134f8565b9150613851565b836002141561384c5761384161130b896134f8565b905060019450613851565b61385c565b8360010193506137ea565b846138a2576040805162461bcd60e51b81526020600482015260116024820152701c9b1c08191958dbd9194819985a5b1959607a1b604482015290519081900360640190fd5b60006110046001600160a01b031663727be1f8836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b1580156138ec57600080fd5b505af1158015613900573d6000803e3d6000fd5b505050506040513d602081101561391657600080fd5b505190508061393c5761392d600585846065614ff3565b975097505050505050506137d8565b6001600160a01b038085166000818152600760209081526040808320948816835293815283822082905591815260089091522054613980908363ffffffff61325e16565b6001600160a01b0380861660008181526008602090815260409182902094909455805186815290519287169391927f35a799836f74fac7eccf5c73902823b970543d2274d3b93d8da3d37a255772a2929181900390910190a3604080516000808252602082019092529098509650505050505050915091565b60008184841115613a885760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613a4d578181015183820152602001613a35565b50505050905090810190601f168015613a7a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000613a9a6151d1565b505080518051602091820151919092015191011190565b8051606090613abf57600080fd5b6000613ace8360200151614e43565b83516040805191839003808352601f19601f8201168301602001909152919250606090828015613b05576020820181803683370190505b50905060008160200190506135f48487602001510182856150ef565b8051602080830191909120600e546000908152600a9092526040822054808214613b5057600092505050611211565b5050600e80546000908152600a60205260408120558054600190810190915592915050565b60008060008060005b613b8788613a90565b15613bf05783613ba457613b9d613627896134f8565b9250613be5565b8360011415613bc057613bb9613627896134f8565b9150613be5565b8360021415613be057613bd561130b896134f8565b905060019450613be5565b613bf0565b836001019350613b7e565b84613c36576040805162461bcd60e51b81526020600482015260116024820152701c9b1c08191958dbd9194819985a5b1959607a1b604482015290519081900360640190fd5b6000613c4d826402540be40063ffffffff61513a16565b6001600160a01b0385166000908152600b602052604090208054600019019055905060ff881660011415613d935760ff871615613cc0576040805162461bcd60e51b815260206004820152600c60248201526b77726f6e672073746174757360a01b604482015290519081900360640190fd5b6001600160a01b038416600090815260046020526040902054613ce9908263ffffffff61325e16565b6001600160a01b03808616600090815260046020908152604080832094909455600581528382209287168252919091522054613d2b908263ffffffff61325e16565b6001600160a01b038086166000818152600560209081526040808320948916808452948252918290209490945580518581529051929391927f9a57c81564ab02642f34fd87e41baa9b074c18342cec3b7268b62bf752018fd1929181900390910190a3613f21565b60ff8816613ee5576001600160a01b038416600090815260086020526040902054613dc4908263ffffffff61325e16565b6001600160a01b0385166000908152600860209081526040808320939093558251630e4f7c3f60e31b81526004810185905292516110049363727be1f89360248083019493928390030190829087803b158015613e2057600080fd5b505af1158015613e34573d6000803e3d6000fd5b505050506040513d6020811015613e4a57600080fd5b5051613e93576040805162461bcd60e51b81526020600482015260136024820152721dda5d1a191c985dc8189b988819985a5b1959606a1b604482015290519081900360640190fd5b6040805182815260ff8916602082015281516001600160a01b0380871693908816927fcbd481ae600289fad8c0484d07ce0ffe4f010d7c844ecfdeaf2a13fead52886e929081900390910190a3613f21565b6040805162461bcd60e51b815260206004820152600c60248201526b77726f6e672073746174757360a01b604482015290519081900360640190fd5b505050505050505050565b60008060008060005b613f3e88613a90565b15613fa75783613f5b57613f54613627896134f8565b9250613f9c565b8360011415613f7757613f70613627896134f8565b9150613f9c565b8360021415613f9757613f8c61130b896134f8565b905060019450613f9c565b613fa7565b836001019350613f35565b84613fed576040805162461bcd60e51b81526020600482015260116024820152701c9b1c08191958dbd9194819985a5b1959607a1b604482015290519081900360640190fd5b6000614004826402540be40063ffffffff61513a16565b6001600160a01b0385166000908152600c602052604090208054600019019055905060ff8816600114156141835760ff871615614077576040805162461bcd60e51b815260206004820152600c60248201526b77726f6e672073746174757360a01b604482015290519081900360640190fd5b6001600160a01b0384166000908152600460205260409020546140a0908263ffffffff61330116565b6001600160a01b038086166000908152600460209081526040808320949094556005815283822092871682529190915220546140e2908263ffffffff61330116565b6001600160a01b0380861660009081526005602090815260408083209388168352929052205561411b42620a8c0063ffffffff61325e16565b6001600160a01b038086166000818152600760209081526040808320948916808452948252918290209490945580518581529051929391927fd6f878a5bcbbe79a64e6418bb0d56aaa20b9a60587d45749819df88dfc7c3c44929181900390910190a3613f21565b60ff8816613ee5576001600160a01b03808516600081815260076020908152604080832094881680845294825280832092909255815185815260ff8c169181019190915281517f4417d10c1e33efa83a770b8d4f47176e78c08c1298d534901ad3b16bb585fa2e929181900390910190a3613f21565b6000806000806000805b61420c89613a90565b156142915784614229576142226136278a6134f8565b9350614286565b84600114156142455761423e6136278a6134f8565b9250614286565b84600214156142615761425a6136278a6134f8565b9150614286565b84600314156142815761427661130b8a6134f8565b905060019550614286565b614291565b846001019450614203565b856142d7576040805162461bcd60e51b81526020600482015260116024820152701c9b1c08191958dbd9194819985a5b1959607a1b604482015290519081900360640190fd5b60006142ee826402540be40063ffffffff61513a16565b6001600160a01b0386166000908152600d602052604090208054600019019055905060ff8916600114156144c15760ff881615614361576040805162461bcd60e51b815260206004820152600c60248201526b77726f6e672073746174757360a01b604482015290519081900360640190fd5b6001600160a01b03808616600090815260056020908152604080832093881683529290522054614397908263ffffffff61330116565b6001600160a01b038681166000908152600560209081526040808320898516845290915280822093909355908516815220546143d3908261325e565b6001600160a01b0380871660009081526005602090815260408083209388168352929052205561440c42620a8c0063ffffffff61325e16565b6001600160a01b038087166000908152600960209081526040808320898516845282528083209388168352929052205561444f42620a8c0063ffffffff61325e16565b6001600160a01b038087166000818152600960209081526040808320898616808552908352818420958b1680855295835292819020959095558451868152945191947f78bffae3f8c6691ac7fc1a3bff800cb2d612f5ad9ae5b0444cfe2eb15c189e18929081900390910190a4614552565b60ff8916613ee5576001600160a01b038581166000818152600960209081526040808320898616808552818452828520968a16808652968452828520859055908352818420818552835281842093909355805186815260ff8e169281019290925280519293927fb93bee5c59f85ede6b074a99f4ffcd3e3fc0d5c3d8156de331de89a49e0ce77c9281900390910190a45b50505050505050505050565b6000816040516020018082805190602001908083835b602083106145935780518252601f199092019160209182019101614574565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120836040516020018082805190602001908083835b602083106146015780518252601f1990920191602091820191016145e2565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012014905092915050565b015190565b60008060008060005b61465c86613a90565b156146c5578361467957614672613627876134f8565b92506146ba565b83600114156146955761468e613627876134f8565b91506146ba565b83600214156146b5576146aa61130b876134f8565b9050600194506146ba565b6146c5565b836001019350614653565b8461470b576040805162461bcd60e51b81526020600482015260116024820152701c9b1c08191958dbd9194819985a5b1959607a1b604482015290519081900360640190fd5b6000614722826402540be40063ffffffff61513a16565b6001600160a01b0385166000908152600b6020908152604080832080546000190190556008909152902054909150614760908263ffffffff61325e16565b6001600160a01b0385166000908152600860209081526040808320939093558251630e4f7c3f60e31b81526004810185905292516110049363727be1f89360248083019493928390030190829087803b1580156147bc57600080fd5b505af11580156147d0573d6000803e3d6000fd5b505050506040513d60208110156147e657600080fd5b505161482f576040805162461bcd60e51b81526020600482015260136024820152721dda5d1a191c985dc8189b988819985a5b1959606a1b604482015290519081900360640190fd5b6040516001907ff83de021914a4585482db5ca47d520a5657165b443fa2c7ef8ed4635f054da9b90600090a250505050505050565b60008060008060005b61487686613a90565b156148df57836148935761488c613627876134f8565b92506148d4565b83600114156148af576148a8613627876134f8565b91506148d4565b83600214156148cf576148c461130b876134f8565b9050600194506148d4565b6148df565b83600101935061486d565b84614925576040805162461bcd60e51b81526020600482015260116024820152701c9b1c08191958dbd9194819985a5b1959607a1b604482015290519081900360640190fd5b6001600160a01b038084166000908152600c60209081526040808320805460001901905560078252808320938616835292905281812081905590516002917ff83de021914a4585482db5ca47d520a5657165b443fa2c7ef8ed4635f054da9b91a2505050505050565b6000806000806000805b6149a187613a90565b15614a2657846149be576149b7613627886134f8565b9350614a1b565b84600114156149da576149d3613627886134f8565b9250614a1b565b84600214156149f6576149ef613627886134f8565b9150614a1b565b8460031415614a1657614a0b61130b886134f8565b905060019550614a1b565b614a26565b846001019450614998565b85614a6c576040805162461bcd60e51b81526020600482015260116024820152701c9b1c08191958dbd9194819985a5b1959607a1b604482015290519081900360640190fd5b6001600160a01b038481166000908152600d602090815260408083208054600019019055600982528083208785168085528184528285209588168552948352818420849055825280832093835292905281812081905590516003917ff83de021914a4585482db5ca47d520a5657165b443fa2c7ef8ed4635f054da9b91a250505050505050565b60008183614b425760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315613a4d578181015183820152602001613a35565b506000838581614b4e57fe5b0495945050505050565b606081516001148015614b8a5750607f60f81b82600081518110614b7857fe5b01602001516001600160f81b03191611155b15614b96575080611211565b612fa4614ba88351608060ff16614d11565b83614c94565b604080516020808252818301909252606091829190602082018180368337505050602081018490529050600067ffffffffffffffff198416614bf257506018614c16565b6fffffffffffffffffffffffffffffffff198416614c1257506010614c16565b5060005b6020811015614c4c57818181518110614c2b57fe5b01602001516001600160f81b03191615614c4457614c4c565b600101614c16565b60008160200390506060816040519080825280601f01601f191660200182016040528015614c81576020820181803683370190505b5080830196909652508452509192915050565b6060806040519050835180825260208201818101602087015b81831015614cc5578051835260209283019201614cad565b50855184518101855292509050808201602086015b81831015614cf2578051835260209283019201614cda565b508651929092011591909101601f01601f191660405250905092915050565b6060680100000000000000008310614d61576040805162461bcd60e51b815260206004820152600e60248201526d696e70757420746f6f206c6f6e6760901b604482015290519081900360640190fd5b60408051600180825281830190925260609160208201818036833701905050905060378411614dbb5782840160f81b81600081518110614d9d57fe5b60200101906001600160f81b031916908160001a9053509050612fa4565b6060614dc685614bae565b90508381510160370160f81b82600081518110614ddf57fe5b60200101906001600160f81b031916908160001a905350614e008282614c94565b95945050505050565b8051600090614e1a57506000611211565b6020820151805160001a9060c0821015614e3957600092505050611211565b5060019392505050565b8051600090811a6080811015614e5d576000915050611211565b60b8811080614e78575060c08110801590614e78575060f881105b15614e87576001915050611211565b60c0811015614e9b5760b519019050611211565b60f519019050611211565b80516000908190811a6080811015614ec15760019150614fd2565b60b8811015614ed657607e1981019150614fd2565b60c0811015614f5057600060b78203600186019550806020036101000a865104915060018101820193505080831015614f4a576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b50614fd2565b60f8811015614f655760be1981019150614fd2565b600060f78203600186019550806020036101000a865104915060018101820193505080831015614fd0576040805162461bcd60e51b81526020600482015260116024820152706164646974696f6e206f766572666c6f7760781b604482015290519081900360640190fd5b505b5092915050565b8051600090601514614fea57600080fd5b612fa482613546565b6000606061500c846402540be40063ffffffff6132bf16565b60408051600480825260a0820190925291955060609190816020015b606081526020019060019003908161502857905050905061504b8760ff16613366565b8160008151811061505857fe5b6020026020010181905250615075866001600160a01b0316613343565b8160018151811061508257fe5b602002602001018190525061509685613366565b816002815181106150a357fe5b60200260200101819052506150bd8463ffffffff16613366565b816003815181106150ca57fe5b602002602001018190525060606150e082613379565b94989497509395505050505050565b806150f9576131d4565b5b60208110615119578251825260209283019290910190601f19016150fa565b915181516020939093036101000a6000190180199091169216919091179052565b60008261514957506000612fa4565b8282028284828161515657fe5b04146132b85760405162461bcd60e51b815260040180806020018281038252602181526020018061529f6021913960400191505060405180910390fd5b60405180606001604052806003906020820280368337509192915050565b60405180604001604052806151c46151d1565b8152602001600081525090565b60405180604001604052806000815260200160008152509056fe7468652042534352656c61796572466565206d6f642074656e20646563696d616c73206d757374206265207a65726f7468652042534352656c61796572466565206d757374206265206c657373207468616e2072656c61796572466565746865206d696e44656c65676174696f6e206d7573742062652067726561746572207468616e2072656c61796572466565696e73756666696369656e742062616c616e636520616674657220726564656c6567617465536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f777468652072656c61796572466565206d6f642074656e20646563696d616c73206d757374206265207a65726f746865206d6573736167652073656e646572206d75737420626520676f7665726e616e636520636f6e74726163747468652072656c61796572466565206d757374206265206c657373207468616e206d696e44656c65676174696f6e7468652072656c61796572466565206d757374206265206d6f7265207468616e2042534352656c61796572466565696e73756666696369656e742062616c616e636520616674657220756e64656c6567617465746865206d6573736167652073656e646572206d7573742062652063726f737320636861696e20636f6e74726163747468652042534352656c61796572466565206d757374206e6f74206265207a65726fa2646970667358221220f93b7c737ada8f392b296e539e2479e336344a76181ff9ba33d0303334f6a7c064736f6c63430006040033", + }, + }, + } + gibbsUpgrade[chapelNet] = &Upgrade{ UpgradeName: "gibbs", Configs: []*UpgradeConfig{ diff --git a/params/config.go b/params/config.go index 15ea21ad8..0a0d69c06 100644 --- a/params/config.go +++ b/params/config.go @@ -296,11 +296,9 @@ var ( MirrorSyncBlock: big.NewInt(5184000), BrunoBlock: big.NewInt(13082000), EulerBlock: big.NewInt(18907621), - - //TODO - GibbsBlock: nil, - NanoBlock: big.NewInt(21962149), - MoranBlock: big.NewInt(22107423), + NanoBlock: big.NewInt(21962149), + MoranBlock: big.NewInt(22107423), + GibbsBlock: big.NewInt(23846001), Parlia: &ParliaConfig{ Period: 3, From d87d697d927c9dd0d24ee31e15b23e0f760469fa Mon Sep 17 00:00:00 2001 From: Larry <92799281+brilliant-lx@users.noreply.github.com> Date: Thu, 24 Nov 2022 15:22:37 +0800 Subject: [PATCH 52/61] worker: add double sign check for safety. (#1201) * worker: add double sign check for safety. And for corner cases, such as reorg after reorg... use slice to record all broadcast blocks's parents to avoid overwritten. --- miner/worker.go | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 05a93c934..200ffb88b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" + lru "github.com/hashicorp/golang-lru" ) const ( @@ -63,6 +64,10 @@ const ( // staleThreshold is the maximum depth of the acceptable stale block. staleThreshold = 11 + + // the current 4 mining loops could have asynchronous risk of mining block with + // save height, keep recently mined blocks to avoid double sign for safety, + recentMinedCacheLimit = 20 ) var ( @@ -226,13 +231,15 @@ type worker struct { isLocalBlock func(header *types.Header) bool // Function used to determine whether the specified block is mined by local miner. // Test hooks - newTaskHook func(*task) // Method to call upon receiving a new sealing task. - skipSealHook func(*task) bool // Method to decide whether skipping the sealing. - fullTaskHook func() // Method to call before pushing the full sealing task. - resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. + newTaskHook func(*task) // Method to call upon receiving a new sealing task. + skipSealHook func(*task) bool // Method to decide whether skipping the sealing. + fullTaskHook func() // Method to call before pushing the full sealing task. + resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. + recentMinedBlocks *lru.Cache } func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(header *types.Header) bool, init bool) *worker { + recentMinedBlocks, _ := lru.New(recentMinedCacheLimit) worker := &worker{ prefetcher: core.NewStatePrefetcher(chainConfig, eth.BlockChain(), engine), config: config, @@ -256,6 +263,7 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus exitCh: make(chan struct{}), startCh: make(chan struct{}, 1), resubmitIntervalCh: make(chan time.Duration), + recentMinedBlocks: recentMinedBlocks, } // Subscribe NewTxsEvent for tx pool worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh) @@ -661,6 +669,30 @@ func (w *worker) resultLoop() { logs = append(logs, receipt.Logs...) } + if prev, ok := w.recentMinedBlocks.Get(block.NumberU64()); ok { + doubleSign := false + prevParents, _ := prev.([]common.Hash) + for _, prevParent := range prevParents { + if prevParent == block.ParentHash() { + log.Error("Reject Double Sign!!", "block", block.NumberU64(), + "hash", block.Hash(), + "root", block.Root(), + "ParentHash", block.ParentHash()) + doubleSign = true + break + } + } + if doubleSign { + continue + } + prevParents = append(prevParents, block.ParentHash()) + w.recentMinedBlocks.Add(block.NumberU64(), prevParents) + } else { + // Add() will call removeOldest internally to remove the oldest element + // if the LRU Cache is full + w.recentMinedBlocks.Add(block.NumberU64(), []common.Hash{block.ParentHash()}) + } + // Broadcast the block and announce chain insertion event w.mux.Post(core.NewMinedBlockEvent{Block: block}) From 58644491ada8b7f791ecbc73d06bf00fcf3b759d Mon Sep 17 00:00:00 2001 From: setunapo Date: Fri, 25 Nov 2022 14:05:19 +0800 Subject: [PATCH 53/61] worker: reused triePrefetch when multi-fillTransactions to mine a block. avoid too much trie prefetch routines when several fillTransactions are called. --- core/state/statedb.go | 19 +++++++++++++++++++ miner/worker.go | 32 ++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index e7bf3c949..f02908e88 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -200,6 +200,25 @@ func (s *StateDB) EnableWriteOnSharedStorage() { s.writeOnSharedStorage = true } +// In mining mode, we will try multi-fillTransactions to get the most profitable one. +// StateDB will be created for each fillTransactions with same block height. +// Share a single triePrefetcher to avoid too much prefetch routines. +func (s *StateDB) TransferPrefetcher(prev *StateDB) { + if prev == nil { + return + } + var fetcher *triePrefetcher + + prev.prefetcherLock.Lock() + fetcher = prev.prefetcher + prev.prefetcher = nil + prev.prefetcherLock.Unlock() + + s.prefetcherLock.Lock() + s.prefetcher = fetcher + s.prefetcherLock.Unlock() +} + // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. diff --git a/miner/worker.go b/miner/worker.go index 200ffb88b..77ce47f73 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -718,14 +718,19 @@ func (w *worker) resultLoop() { } // makeEnv creates a new environment for the sealing block. -func (w *worker) makeEnv(parent *types.Block, header *types.Header, coinbase common.Address) (*environment, error) { +func (w *worker) makeEnv(parent *types.Block, header *types.Header, coinbase common.Address, + prevEnv *environment) (*environment, error) { // Retrieve the parent state to execute on top and start a prefetcher for // the miner to speed block sealing up a bit state, err := w.chain.StateAtWithSharedPool(parent.Root()) if err != nil { return nil, err } - state.StartPrefetcher("miner") + if prevEnv == nil { + state.StartPrefetcher("miner") + } else { + state.TransferPrefetcher(prevEnv.state) + } // Note the passed coinbase may be different with header.Coinbase. env := &environment{ @@ -941,6 +946,7 @@ type generateParams struct { random common.Hash // The randomness generated by beacon chain, empty before the merge noUncle bool // Flag whether the uncle block inclusion is allowed noExtra bool // Flag whether the extra field assignment is allowed + prevWork *environment } // prepareWork constructs the sealing task according to the given parameters, @@ -999,7 +1005,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { // Could potentially happen if starting to mine in an odd state. // Note genParams.coinbase can be different with header.Coinbase // since clique algorithm can modify the coinbase field in header. - env, err := w.makeEnv(parent, header, genParams.coinbase) + env, err := w.makeEnv(parent, header, genParams.coinbase, genParams.prevWork) if err != nil { log.Error("Failed to create sealing context", "err", err) return nil, err @@ -1105,27 +1111,29 @@ func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { // validator can try several times to get the most profitable block, // as long as the timestamp is not reached. workList := make([]*environment, 0, 10) - var bestWork *environment + var prevWork *environment // workList clean up defer func() { - for _, w := range workList { + for _, wk := range workList { // only keep the best work, discard others. - if w == bestWork { + if wk == w.current { continue } - w.discard() + wk.discard() } }() + LOOP: for { work, err := w.prepareWork(&generateParams{ timestamp: uint64(timestamp), coinbase: coinbase, + prevWork: prevWork, }) if err != nil { return } - + prevWork = work workList = append(workList, work) delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) @@ -1215,13 +1223,13 @@ LOOP: } } // get the most profitable work - bestWork = workList[0] + bestWork := workList[0] bestReward := new(big.Int) - for i, w := range workList { - balance := w.state.GetBalance(consensus.SystemAddress) + for i, wk := range workList { + balance := wk.state.GetBalance(consensus.SystemAddress) log.Debug("Get the most profitable work", "index", i, "balance", balance, "bestReward", bestReward) if balance.Cmp(bestReward) > 0 { - bestWork = w + bestWork = wk bestReward = balance } } From 807d52e5577bcf9bcb33abb5d39dcf25e00aed99 Mon Sep 17 00:00:00 2001 From: setunapo Date: Fri, 25 Nov 2022 17:46:22 +0800 Subject: [PATCH 54/61] worker: some Subscribe NewTxsEvent changes of miner worker 1.remove the unnecessary NewTxsEvent subscriber, which was used for PoW resubmit check. 2.unsubscribe ASAP before another fillTransactions, to avoid block others. --- miner/worker.go | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 77ce47f73..599032c21 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -188,8 +188,6 @@ type worker struct { // Subscriptions mux *event.TypeMux - txsCh chan core.NewTxsEvent - txsSub event.Subscription chainHeadCh chan core.ChainHeadEvent chainHeadSub event.Subscription chainSideCh chan core.ChainSideEvent @@ -225,7 +223,6 @@ type worker struct { // atomic status counters running int32 // The indicator whether the consensus engine is running or not. - newTxs int32 // New arrival transaction count since last sealing work submitting. // External functions isLocalBlock func(header *types.Header) bool // Function used to determine whether the specified block is mined by local miner. @@ -253,7 +250,6 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus remoteUncles: make(map[common.Hash]*types.Block), unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), sealingLogAtDepth), pendingTasks: make(map[common.Hash]*task), - txsCh: make(chan core.NewTxsEvent, txChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize), newWorkCh: make(chan *newWorkReq), @@ -265,8 +261,6 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus resubmitIntervalCh: make(chan time.Duration), recentMinedBlocks: recentMinedBlocks, } - // Subscribe NewTxsEvent for tx pool - worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh) // Subscribe events for blockchain worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh) worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh) @@ -397,7 +391,6 @@ func (w *worker) newWorkLoop(recommit time.Duration) { return } timer.Reset(recommit) - atomic.StoreInt32(&w.newTxs, 0) } // clearPending cleans the stale pending tasks. clearPending := func(number uint64) { @@ -442,10 +435,6 @@ func (w *worker) newWorkLoop(recommit time.Duration) { if w.isRunning() && ((w.chainConfig.Ethash != nil) || (w.chainConfig.Clique != nil && w.chainConfig.Clique.Period > 0) || (w.chainConfig.Parlia != nil && w.chainConfig.Parlia.Period > 0)) { // Short circuit if no new transaction arrives. - if atomic.LoadInt32(&w.newTxs) == 0 { - timer.Reset(recommit) - continue - } commit(commitInterruptResubmit) } @@ -473,7 +462,6 @@ func (w *worker) newWorkLoop(recommit time.Duration) { // submit it or return task according to given parameters for various proposes. func (w *worker) mainLoop() { defer w.wg.Done() - defer w.txsSub.Unsubscribe() defer w.chainHeadSub.Unsubscribe() defer w.chainSideSub.Unsubscribe() defer func() { @@ -539,24 +527,9 @@ func (w *worker) mainLoop() { } } - case ev := <-w.txsCh: - if w.isRunning() { - // Special case, if the consensus engine is 0 period clique(dev mode), - // 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.chainConfig.Parlia != nil && w.chainConfig.Parlia.Period == 0) { - w.commitWork(nil, time.Now().Unix()) - } - } - - atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) - // System stopped case <-w.exitCh: return - case <-w.txsSub.Err(): - return case <-w.chainHeadSub.Err(): return case <-w.chainSideSub.Err(): @@ -1221,6 +1194,9 @@ LOOP: } } } + // if sub's channel if full, it will block other NewTxsEvent subscribers, + // so unsubscribe ASAP and Unsubscribe() is re-enterable, safe to call several time. + sub.Unsubscribe() } // get the most profitable work bestWork := workList[0] From d77ebb8511e04859bb77bed95054ce59b024039f Mon Sep 17 00:00:00 2001 From: j75689 Date: Mon, 28 Nov 2022 22:09:27 +0800 Subject: [PATCH 55/61] metrics: add label type in metrics package --- metrics/exp/exp.go | 70 ++++++++++++++++++++++++++++++++ metrics/label.go | 48 ++++++++++++++++++++++ metrics/prometheus/collector.go | 10 +++++ metrics/prometheus/prometheus.go | 2 + metrics/registry.go | 2 +- 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 metrics/label.go diff --git a/metrics/exp/exp.go b/metrics/exp/exp.go index 3ebe8cc68..4d9304a5f 100644 --- a/metrics/exp/exp.go +++ b/metrics/exp/exp.go @@ -95,6 +95,20 @@ func (exp *exp) getFloat(name string) *expvar.Float { return v } +func (exp *exp) getMap(name string) *expvar.Map { + var v *expvar.Map + exp.expvarLock.Lock() + p := expvar.Get(name) + if p != nil { + v = p.(*expvar.Map) + } else { + v = new(expvar.Map) + expvar.Publish(name, v) + } + exp.expvarLock.Unlock() + return v +} + func (exp *exp) publishCounter(name string, metric metrics.Counter) { v := exp.getInt(name) v.Set(metric.Count()) @@ -162,6 +176,60 @@ func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer exp.getInt(name + ".99-percentile").Set(ps[3]) } +func (exp *exp) publishLabel(name string, metric metrics.Label) { + labels := metric.Value() + for k, v := range labels { + exp.getMap(name).Set(k, exp.interfaceToExpVal(v)) + } +} + +func (exp *exp) interfaceToExpVal(v interface{}) expvar.Var { + switch i := v.(type) { + case string: + newV := new(expvar.String) + newV.Set(i) + return newV + case int64: + newV := new(expvar.Int) + newV.Set(i) + return newV + case int32: + newV := new(expvar.Int) + newV.Set(int64(i)) + return newV + case int16: + newV := new(expvar.Int) + newV.Set(int64(i)) + return newV + case int8: + newV := new(expvar.Int) + newV.Set(int64(i)) + return newV + case int: + newV := new(expvar.Int) + newV.Set(int64(i)) + return newV + case float32: + newV := new(expvar.Float) + newV.Set(float64(i)) + return newV + case float64: + newV := new(expvar.Float) + newV.Set(i) + return newV + case map[string]interface{}: + newV := new(expvar.Map) + for k, v := range i { + newV.Set(k, exp.interfaceToExpVal(v)) + } + return newV + default: + newV := new(expvar.String) + newV.Set(fmt.Sprint(v)) + return newV + } +} + func (exp *exp) syncToExpvar() { exp.registry.Each(func(name string, i interface{}) { switch i := i.(type) { @@ -179,6 +247,8 @@ func (exp *exp) syncToExpvar() { exp.publishTimer(name, i) case metrics.ResettingTimer: exp.publishResettingTimer(name, i) + case metrics.Label: + exp.publishLabel(name, i) default: panic(fmt.Sprintf("unsupported type for '%s': %T", name, i)) } diff --git a/metrics/label.go b/metrics/label.go new file mode 100644 index 000000000..6c6b02ed7 --- /dev/null +++ b/metrics/label.go @@ -0,0 +1,48 @@ +package metrics + +import "encoding/json" + +// Label hold an map[string]interface{} value that can be set arbitrarily. +type Label interface { + Value() map[string]interface{} + String() string + Mark(map[string]interface{}) +} + +// NewRegisteredLabel constructs and registers a new StandardLabel. +func NewRegisteredLabel(name string, r Registry) Label { + c := NewStandardLabel() + if nil == r { + r = DefaultRegistry + } + r.Register(name, c) + return c +} + +// NewStandardLabel constructs a new StandardLabel. +func NewStandardLabel() *StandardLabel { + return &StandardLabel{} +} + +// StandardLabel is the standard implementation of a Label. +type StandardLabel struct { + value map[string]interface{} + jsonStr string +} + +// Value returns label values. +func (l *StandardLabel) Value() map[string]interface{} { + return l.value +} + +// Mark records the label. +func (l *StandardLabel) Mark(value map[string]interface{}) { + buf, _ := json.Marshal(value) + l.jsonStr = string(buf) + l.value = value +} + +// String returns label by JSON format. +func (l *StandardLabel) String() string { + return l.jsonStr +} diff --git a/metrics/prometheus/collector.go b/metrics/prometheus/collector.go index 3959cbf5e..25c7b4f4c 100644 --- a/metrics/prometheus/collector.go +++ b/metrics/prometheus/collector.go @@ -31,6 +31,7 @@ var ( typeSummaryTpl = "# TYPE %s summary\n" keyValueTpl = "%s %v\n\n" keyQuantileTagValueTpl = "%s {quantile=\"%s\"} %v\n" + keyLabelValueTpl = "%s%s %v\n\n" ) // collector is a collection of byte buffers that aggregate Prometheus reports @@ -98,6 +99,15 @@ func (c *collector) addResettingTimer(name string, m metrics.ResettingTimer) { c.buff.WriteRune('\n') } +func (c *collector) addLabel(name string, m metrics.Label) { + c.writeLabel(mutateKey(name), m.String()) +} + +func (c *collector) writeLabel(name string, value interface{}) { + c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name)) + c.buff.WriteString(fmt.Sprintf(keyLabelValueTpl, name, value, 1)) +} + func (c *collector) writeGaugeCounter(name string, value interface{}) { name = mutateKey(name) c.buff.WriteString(fmt.Sprintf(typeGaugeTpl, name)) diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index 9ad5ec7e9..2b94266cb 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -57,6 +57,8 @@ func Handler(reg metrics.Registry) http.Handler { c.addTimer(name, m.Snapshot()) case metrics.ResettingTimer: c.addResettingTimer(name, m.Snapshot()) + case metrics.Label: + c.addLabel(name, m) default: log.Warn("Unknown Prometheus metric type", "type", fmt.Sprintf("%T", i)) } diff --git a/metrics/registry.go b/metrics/registry.go index c5435adf2..8ab519fcf 100644 --- a/metrics/registry.go +++ b/metrics/registry.go @@ -196,7 +196,7 @@ func (r *StandardRegistry) register(name string, i interface{}) error { return DuplicateMetric(name) } switch i.(type) { - case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer: + case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer, Label: r.metrics[name] = i } return nil From 9023e42d0a1851e427f35331546444599b4915a0 Mon Sep 17 00:00:00 2001 From: j75689 Date: Mon, 28 Nov 2022 22:09:45 +0800 Subject: [PATCH 56/61] metrics: add build info into metrics server --- cmd/geth/main.go | 2 +- cmd/utils/flags.go | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 9ed921c24..a4455c3c0 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -324,7 +324,7 @@ func prepare(ctx *cli.Context) { } // Start metrics export if enabled - utils.SetupMetrics(ctx) + utils.SetupMetrics(ctx, utils.EnableBuildInfo(gitCommit, gitDate)) // Start system runtime metrics collection go metrics.CollectProcessMetrics(3 * time.Second) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index cb6741bac..33cc72bb2 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -26,6 +26,7 @@ import ( "math/big" "os" "path/filepath" + "runtime" godebug "runtime/debug" "strconv" "strings" @@ -1931,7 +1932,23 @@ func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, cfg node.C } } -func SetupMetrics(ctx *cli.Context) { +type SetupMetricsOption func() + +func EnableBuildInfo(gitCommit, gitDate string) SetupMetricsOption { + return func() { + // register build info into metrics + metrics.NewRegisteredLabel("build-info", nil).Mark(map[string]interface{}{ + "version": params.VersionWithMeta, + "git-commit": gitCommit, + "git-commit-date": gitDate, + "go-version": runtime.Version(), + "operating-system": runtime.GOOS, + "architecture": runtime.GOARCH, + }) + } +} + +func SetupMetrics(ctx *cli.Context, options ...SetupMetricsOption) { if metrics.Enabled { log.Info("Enabling metrics collection") @@ -1987,6 +2004,10 @@ func SetupMetrics(ctx *cli.Context) { log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address) exp.Setup(address) } + + for _, opt := range options { + opt() + } } } From d1c9262b123cbbc17438f12e6986617b740e4721 Mon Sep 17 00:00:00 2001 From: j75689 Date: Mon, 28 Nov 2022 22:20:54 +0800 Subject: [PATCH 57/61] ci: add git info to cross-compile --- Makefile | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index d2e5d66fd..b35a4a9e4 100644 --- a/Makefile +++ b/Makefile @@ -9,25 +9,30 @@ GOBIN = ./build/bin GO ?= latest GORUN = env GO111MODULE=on go run +GIT_COMMIT=$(shell git rev-parse HEAD) +GIT_COMMIT_DATE=$(shell git log -n1 --pretty='format:%cd' --date=format:'%Y%m%d') geth: $(GORUN) build/ci.go install ./cmd/geth @echo "Done building." @echo "Run \"$(GOBIN)/geth\" to launch geth." +ldflags = -X main.gitCommit=$(GIT_COMMIT) \ + -X main.gitDate=$(GIT_COMMIT_DATE) + geth-linux-arm: geth-linux-arm5 geth-linux-arm6 geth-linux-arm7 geth-linux-arm64 geth-linux-arm5: - env GO111MODULE=on GOARCH=arm GOARM=5 GOOS=linux go build -o build/bin/geth-linux-arm-5 ./cmd/geth + env GO111MODULE=on GOARCH=arm GOARM=5 GOOS=linux go build -ldflags="$(ldflags)" -o build/bin/geth-linux-arm-5 ./cmd/geth geth-linux-arm6: - env GO111MODULE=on GOARCH=arm GOARM=6 GOOS=linux go build -o build/bin/geth-linux-arm-6 ./cmd/geth + env GO111MODULE=on GOARCH=arm GOARM=6 GOOS=linux go build -ldflags="$(ldflags)" -o build/bin/geth-linux-arm-6 ./cmd/geth geth-linux-arm7: - env GO111MODULE=on GOARCH=arm GOARM=7 GOOS=linux go build -o build/bin/geth-linux-arm-7 ./cmd/geth + env GO111MODULE=on GOARCH=arm GOARM=7 GOOS=linux go build -ldflags="$(ldflags)" -o build/bin/geth-linux-arm-7 ./cmd/geth geth-linux-arm64: - env GO111MODULE=on GOARCH=arm64 GOOS=linux go build -o build/bin/geth-linux-arm64 ./cmd/geth + env GO111MODULE=on GOARCH=arm64 GOOS=linux go build -ldflags="$(ldflags)" -o build/bin/geth-linux-arm64 ./cmd/geth all: $(GORUN) build/ci.go install From fe5682c4e0f18e9d3e7117006504e28913f59f88 Mon Sep 17 00:00:00 2001 From: j75689 Date: Mon, 28 Nov 2022 22:38:59 +0800 Subject: [PATCH 58/61] ci: fix build cmd of arm binary --- .github/workflows/pre-release.yml | 14 +++++--------- .github/workflows/release.yml | 14 +++++--------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 0e7b5ea53..c9265dd5c 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -50,12 +50,8 @@ jobs: - name: Build Binary for ARM if: matrix.os == 'ubuntu-18.04' - env: - GOPATH: /home/runner/work/woodpecker/go run: | - mkdir -p $GOPATH/src/github.com/bnb-chain/bsc/ - cp -r ./* $GOPATH/src/github.com/bnb-chain/bsc/ - cd $GOPATH/src/github.com/bnb-chain/bsc/ && make geth-linux-arm + make geth-linux-arm # ============================== # Upload artifacts # ============================== @@ -86,28 +82,28 @@ jobs: if: matrix.os == 'ubuntu-18.04' with: name: arm5 - path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-5 + path: ./build/bin/geth-linux-arm-5 - name: Upload ARM-6 Build uses: actions/upload-artifact@v2 if: matrix.os == 'ubuntu-18.04' with: name: arm6 - path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-6 + path: ./build/bin/geth-linux-arm-6 - name: Upload ARM-7 Build uses: actions/upload-artifact@v2 if: matrix.os == 'ubuntu-18.04' with: name: arm7 - path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-7 + path: ./build/bin/geth-linux-arm-7 - name: Upload ARM-64 Build uses: actions/upload-artifact@v2 if: matrix.os == 'ubuntu-18.04' with: name: arm64 - path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm64 + path: ./build/bin/geth-linux-arm64 release: name: Release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 11c5f7893..778d8a56f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,12 +51,8 @@ jobs: - name: Build Binary for ARM if: matrix.os == 'ubuntu-18.04' - env: - GOPATH: /home/runner/work/woodpecker/go run: | - mkdir -p $GOPATH/src/github.com/bnb-chain/bsc/ - cp -r ./* $GOPATH/src/github.com/bnb-chain/bsc/ - cd $GOPATH/src/github.com/bnb-chain/bsc/ && make geth-linux-arm + make geth-linux-arm # ============================== # Upload artifacts # ============================== @@ -87,28 +83,28 @@ jobs: if: matrix.os == 'ubuntu-18.04' with: name: arm5 - path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-5 + path: ./build/bin/geth-linux-arm-5 - name: Upload ARM-6 Build uses: actions/upload-artifact@v2 if: matrix.os == 'ubuntu-18.04' with: name: arm6 - path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-6 + path: ./build/bin/geth-linux-arm-6 - name: Upload ARM-7 Build uses: actions/upload-artifact@v2 if: matrix.os == 'ubuntu-18.04' with: name: arm7 - path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm-7 + path: ./build/bin/geth-linux-arm-7 - name: Upload ARM-64 Build uses: actions/upload-artifact@v2 if: matrix.os == 'ubuntu-18.04' with: name: arm64 - path: /home/runner/work/woodpecker/go/src/github.com/bnb-chain/bsc/build/bin/geth-linux-arm64 + path: ./build/bin/geth-linux-arm64 release: name: Release From 02f7ad74c6829ba8040c9afc8cdfab07d9df14e5 Mon Sep 17 00:00:00 2001 From: zjubfd <296179868@qq.com> Date: Tue, 29 Nov 2022 13:39:08 +0800 Subject: [PATCH 59/61] release: prepare for release v1.1.18 --- CHANGELOG.md | 19 +++++++++++++++++++ params/version.go | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f52d48670..d54be272c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## v1.1.18 +IMPROVEMENT + +* [\#1209](https://github.com/bnb-chain/bsc/pull/1209) metrics: add build info into metrics server +* [\#1204](https://github.com/bnb-chain/bsc/pull/1204) worker: NewTxsEvent and triePrefetch reuse in mining task +* [\#1195](https://github.com/bnb-chain/bsc/pull/1195) hardfork: update Gibbs fork height and system contract code +* [\#1192](https://github.com/bnb-chain/bsc/pull/1192) all: sync with upstream v1.10.22 +* [\#1186](https://github.com/bnb-chain/bsc/pull/1186) worker: improvement of the current block generation logic to get more rewards +* [\#1184](https://github.com/bnb-chain/bsc/pull/1184) worker: remove pre-seal empty block +* [\#1182](https://github.com/bnb-chain/bsc/pull/1182) Parlia: Some updates of the miner worker +* [\#1181](https://github.com/bnb-chain/bsc/pull/1181) all: sync with upstream v1.10.21 +* [\#1177](https://github.com/bnb-chain/bsc/pull/1177) core/forkid: refactor nextForkHash function +* [\#1174](https://github.com/bnb-chain/bsc/pull/1174) worker: some code enhancement on work.go +* [\#1166](https://github.com/bnb-chain/bsc/pull/1166) miner: disable enforceTip when get txs from txpool + +BUGFIX +* [\#1201](https://github.com/bnb-chain/bsc/pull/1201) worker: add double sign check for safety +* [\#1185](https://github.com/bnb-chain/bsc/pull/1185) worker: fix a bug of the delay timer + ## v1.1.17 IMPROVEMENT diff --git a/params/version.go b/params/version.go index cb4ddea21..d5e9e1e38 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 1 // Minor version component of the current release - VersionPatch = 17 // Patch version component of the current release + VersionPatch = 18 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From b6b274eba2ec4dc5683b38c2e8e45b1c2ceb0f3f Mon Sep 17 00:00:00 2001 From: nathanhopp <96248703+nathanhopp@users.noreply.github.com> Date: Wed, 30 Nov 2022 19:13:50 -0700 Subject: [PATCH 60/61] metrics fix: edit mutate key to replace - with _ (#1217) --- metrics/prometheus/collector.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/metrics/prometheus/collector.go b/metrics/prometheus/collector.go index 25c7b4f4c..ea85abc1b 100644 --- a/metrics/prometheus/collector.go +++ b/metrics/prometheus/collector.go @@ -126,5 +126,7 @@ func (c *collector) writeSummaryPercentile(name, p string, value interface{}) { } func mutateKey(key string) string { - return strings.Replace(key, "/", "_", -1) + key = strings.Replace(key, "/", "_", -1) + key = strings.Replace(key, "-", "_", -1) + return key } From ecc12f6493665f5b2619f57e5d5f4d331159e529 Mon Sep 17 00:00:00 2001 From: j75689 Date: Thu, 1 Dec 2022 16:54:10 +0800 Subject: [PATCH 61/61] metrics: fix the label format of prometheus server --- metrics/label.go | 13 +------------ metrics/prometheus/collector.go | 6 +++++- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/metrics/label.go b/metrics/label.go index 6c6b02ed7..f59c149d0 100644 --- a/metrics/label.go +++ b/metrics/label.go @@ -1,11 +1,8 @@ package metrics -import "encoding/json" - // Label hold an map[string]interface{} value that can be set arbitrarily. type Label interface { Value() map[string]interface{} - String() string Mark(map[string]interface{}) } @@ -26,8 +23,7 @@ func NewStandardLabel() *StandardLabel { // StandardLabel is the standard implementation of a Label. type StandardLabel struct { - value map[string]interface{} - jsonStr string + value map[string]interface{} } // Value returns label values. @@ -37,12 +33,5 @@ func (l *StandardLabel) Value() map[string]interface{} { // Mark records the label. func (l *StandardLabel) Mark(value map[string]interface{}) { - buf, _ := json.Marshal(value) - l.jsonStr = string(buf) l.value = value } - -// String returns label by JSON format. -func (l *StandardLabel) String() string { - return l.jsonStr -} diff --git a/metrics/prometheus/collector.go b/metrics/prometheus/collector.go index ea85abc1b..1921a0c37 100644 --- a/metrics/prometheus/collector.go +++ b/metrics/prometheus/collector.go @@ -100,7 +100,11 @@ func (c *collector) addResettingTimer(name string, m metrics.ResettingTimer) { } func (c *collector) addLabel(name string, m metrics.Label) { - c.writeLabel(mutateKey(name), m.String()) + labels := make([]string, 0, len(m.Value())) + for k, v := range m.Value() { + labels = append(labels, fmt.Sprintf(`%s="%s"`, mutateKey(k), fmt.Sprint(v))) + } + c.writeLabel(mutateKey(name), "{"+strings.Join(labels, ", ")+"}") } func (c *collector) writeLabel(name string, value interface{}) {