mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
Merge branch 'develop' into shivam/POS-1733
This commit is contained in:
commit
2b1bd0997b
152 changed files with 7781 additions and 1058 deletions
2
.github/ISSUE_TEMPLATE/bug.md
vendored
2
.github/ISSUE_TEMPLATE/bug.md
vendored
|
|
@ -6,7 +6,7 @@ labels: 'type:bug'
|
|||
assignees: ''
|
||||
---
|
||||
|
||||
Our support team has aggregated some common issues and their solutions from past which are faced while running or interacting with a bor client. In order to prevent redundant efforts, we would encourage you to have a look at the [FAQ's section](https://wiki.polygon.technology/docs/faq/technical-faqs/) of our documentation mentioning the same, before filing an issue here. In case of additional support, you can also join our [discord](https://discord.com/invite/zdwkdvMNY2) server
|
||||
Our support team has aggregated some common issues and their solutions from past which are faced while running or interacting with a bor client. In order to prevent redundant efforts, we would encourage you to have a look at the [FAQ's section](https://wiki.polygon.technology/docs/faq/technical-faqs/) of our documentation mentioning the same, before filing an issue here. In case of additional support, you can also join our [discord](https://discord.com/invite/0xPolygonDevs) server
|
||||
|
||||
<!--
|
||||
NOTE: Please make sure to check of any addresses / private keys / rpc url's / IP's before sharing the logs or anything from the additional information section (start.sh or heimdall config).
|
||||
|
|
|
|||
2
.github/ISSUE_TEMPLATE/question.md
vendored
2
.github/ISSUE_TEMPLATE/question.md
vendored
|
|
@ -8,4 +8,4 @@ assignees: ''
|
|||
|
||||
This should only be used in very rare cases e.g. if you are not 100% sure if something is a bug or asking a question that leads to improving the documentation.
|
||||
|
||||
For general questions please join our [discord](https://discord.com/invite/zdwkdvMNY2) server.
|
||||
For general questions please join our [discord](https://discord.com/invite/0xPolygonDevs) server.
|
||||
|
|
|
|||
119
.github/workflows/ci.yml
vendored
119
.github/workflows/ci.yml
vendored
|
|
@ -15,7 +15,39 @@ concurrency:
|
|||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
build:
|
||||
if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: |
|
||||
git submodule update --init --recursive --force
|
||||
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
|
||||
- name: Install dependencies on Linux
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt update && sudo apt install build-essential
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/Library/Caches/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-go-
|
||||
|
||||
- name: Build
|
||||
run: make all
|
||||
|
||||
lint:
|
||||
if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
|
||||
strategy:
|
||||
matrix:
|
||||
|
|
@ -39,6 +71,30 @@ jobs:
|
|||
if: runner.os == 'Linux'
|
||||
run: make lintci-deps
|
||||
|
||||
- name: Lint
|
||||
if: runner.os == 'Linux'
|
||||
run: make lint
|
||||
|
||||
unit-tests:
|
||||
if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: |
|
||||
git submodule update --init --recursive --force
|
||||
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
|
||||
- name: Install dependencies on Linux
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt update && sudo apt install build-essential
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
|
|
@ -48,27 +104,12 @@ jobs:
|
|||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-go-
|
||||
|
||||
- name: Build
|
||||
run: make all
|
||||
|
||||
- name: Lint
|
||||
if: runner.os == 'Linux'
|
||||
run: make lint
|
||||
|
||||
- name: Test
|
||||
run: make test
|
||||
|
||||
#- name: Data race tests
|
||||
# run: make test-race
|
||||
|
||||
- name: test-integration
|
||||
run: make test-integration
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: ./cover.out
|
||||
|
||||
# # TODO: make it work
|
||||
# - name: Reproducible build test
|
||||
# run: |
|
||||
|
|
@ -81,6 +122,50 @@ jobs:
|
|||
# fi
|
||||
|
||||
integration-tests:
|
||||
if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: |
|
||||
git submodule update --init --recursive --force
|
||||
git fetch --no-tags --prune --depth=1 origin +refs/heads/master:refs/remotes/origin/master
|
||||
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
|
||||
- name: Install dependencies on Linux
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt update && sudo apt install build-essential
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/Library/Caches/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-go-
|
||||
|
||||
- name: test-integration
|
||||
run: make test-integration
|
||||
|
||||
codecov:
|
||||
if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-20.04 ] # list of os: https://github.com/actions/virtual-environments
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: ./cover.out
|
||||
|
||||
e2e-tests:
|
||||
if: (github.event.action != 'closed' || github.event.pull_request.merged == true)
|
||||
strategy:
|
||||
matrix:
|
||||
|
|
@ -154,7 +239,7 @@ jobs:
|
|||
cd matic-cli/devnet/code/contracts
|
||||
npm run truffle exec scripts/deposit.js -- --network development $(jq -r .root.tokens.MaticToken contractAddresses.json) 100000000000000000000
|
||||
cd -
|
||||
timeout 20m bash bor/integration-tests/smoke_test.sh
|
||||
timeout 60m bash bor/integration-tests/smoke_test.sh
|
||||
|
||||
- name: Upload logs
|
||||
if: always()
|
||||
|
|
|
|||
8
.github/workflows/packager.yml
vendored
8
.github/workflows/packager.yml
vendored
|
|
@ -12,9 +12,7 @@ on:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on:
|
||||
group: ubuntu-runners
|
||||
labels: 18.04RunnerT2Large
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
|
@ -98,7 +96,7 @@ jobs:
|
|||
NODE: bootnode
|
||||
NETWORK: mumbai
|
||||
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/systemd/bor_bootnode.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||
run: cp -rp packaging/templates/systemd/bor_bootnode.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/bor.service
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
|
|
@ -153,7 +151,7 @@ jobs:
|
|||
NODE: bootnode
|
||||
NETWORK: mainnet
|
||||
- name: Copying systemd file for ${{ env.NODE }} on ${{ env.NETWORK }} on ${{ env.ARCH }}
|
||||
run: cp -rp packaging/templates/systemd/bor_bootnode.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/
|
||||
run: cp -rp packaging/templates/systemd/bor_bootnode.service packaging/deb/bor-${{ env.NETWORK }}-${{ env.NODE }}-config_${{ env.GIT_TAG }}-${{ env.ARCH }}/lib/systemd/system/bor.service
|
||||
env:
|
||||
ARCH: amd64
|
||||
NODE: bootnode
|
||||
|
|
|
|||
1
.github/workflows/stale.yml
vendored
1
.github/workflows/stale.yml
vendored
|
|
@ -29,3 +29,4 @@ jobs:
|
|||
days-before-pr-stale: 21
|
||||
days-before-issue-close: 14
|
||||
days-before-pr-close: 14
|
||||
exempt-draft-pr: true
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -58,7 +58,7 @@ ios:
|
|||
@echo "Import \"$(GOBIN)/Geth.framework\" to use the library."
|
||||
|
||||
test:
|
||||
$(GOTEST) --timeout 5m -shuffle=on -cover -short -coverprofile=cover.out -covermode=atomic $(TESTALL)
|
||||
$(GOTEST) --timeout 5m -cover -short -coverprofile=cover.out -covermode=atomic $(TESTALL)
|
||||
|
||||
test-txpool-race:
|
||||
$(GOTEST) -run=TestPoolMiningDataRaces --timeout 600m -race -v ./core/
|
||||
|
|
|
|||
138
README.md
138
README.md
|
|
@ -1,111 +1,71 @@
|
|||
# Bor Overview
|
||||
Bor is the Official Golang implementation of the Matic protocol. It is a fork of Go Ethereum - https://github.com/ethereum/go-ethereum and EVM compatible.
|
||||
Bor is the Official Golang implementation of the Polygon PoS blockchain. It is a fork of [geth](https://github.com/ethereum/go-ethereum) and is EVM compatible (upto London fork).
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
[](https://pkg.go.dev/github.com/maticnetwork/bor)
|
||||
[](https://goreportcard.com/report/github.com/maticnetwork/bor)
|
||||

|
||||

|
||||

|
||||

|
||||
[](https://discord.gg/zdwkdvMNY2)
|
||||
[](https://discord.com/invite/0xPolygonDevs)
|
||||
[](https://twitter.com/0xPolygon)
|
||||
|
||||
## How to contribute
|
||||
### Installing bor using packaging
|
||||
|
||||
### Contribution Guidelines
|
||||
We believe one of the things that makes Polygon special is its coherent design and we seek to retain this defining characteristic. From the outset we defined some guidelines to ensure new contributions only ever enhance the project:
|
||||
The easiest way to get started with bor is to install the packages using the command below. Refer to the [releases](https://github.com/maticnetwork/bor/releases) section to find the latest stable version of bor.
|
||||
|
||||
* Quality: Code in the Polygon project should meet the style guidelines, with sufficient test-cases, descriptive commit messages, evidence that the contribution does not break any compatibility commitments or cause adverse feature interactions, and evidence of high-quality peer-review
|
||||
* Size: The Polygon project’s culture is one of small pull-requests, regularly submitted. The larger a pull-request, the more likely it is that you will be asked to resubmit as a series of self-contained and individually reviewable smaller PRs
|
||||
* Maintainability: If the feature will require ongoing maintenance (eg support for a particular brand of database), we may ask you to accept responsibility for maintaining this feature
|
||||
### Submit an issue
|
||||
curl -L https://raw.githubusercontent.com/maticnetwork/install/main/bor.sh | bash -s -- v0.4.0 <network> <node_type>
|
||||
|
||||
- Create a [new issue](https://github.com/maticnetwork/bor/issues/new/choose)
|
||||
- Comment on the issue (if you'd like to be assigned to it) - that way [our team can assign the issue to you](https://github.blog/2019-06-25-assign-issues-to-issue-commenters/).
|
||||
- If you do not have a specific contribution in mind, you can also browse the issues labelled as `help wanted`
|
||||
- Issues that additionally have the `good first issue` label are considered ideal for first-timers
|
||||
The network accepts `mainnet` or `mumbai` and the node type accepts `validator` or `sentry` or `archive`. The installation script does the following things:
|
||||
- Create a new user named `bor`.
|
||||
- Install the bor binary at `/usr/bin/bor`.
|
||||
- Dump the suitable config file (based on the network and node type provided) at `/var/lib/bor` and uses it as the home dir.
|
||||
- Create a systemd service named `bor` at `/lib/systemd/system/bor.service` which starts bor using the config file as `bor` user.
|
||||
|
||||
### Fork the repository (repo)
|
||||
The releases supports both the networks i.e. Polygon Mainnet and Mumbai (Testnet) unless explicitly specified. Before the stable release for mainnet, pre-releases will be available marked with `beta` tag for deploying on Mumbai (testnet). On sufficient testing, stable release for mainnet will be announced with a forum post.
|
||||
|
||||
- If you're not sure, here's how to [fork the repo](https://help.github.com/en/articles/fork-a-repo)
|
||||
|
||||
- If this is your first time forking our repo, this is all you need to do for this step:
|
||||
|
||||
```
|
||||
$ git clone git@github.com:[your_github_handle]/bor
|
||||
```
|
||||
|
||||
- If you've already forked the repo, you'll want to ensure your fork is configured and that it's up to date. This will save you the headache of potential merge conflicts.
|
||||
|
||||
- To [configure your fork](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork):
|
||||
|
||||
```
|
||||
$ git remote add upstream https://github.com/maticnetwork/bor
|
||||
```
|
||||
|
||||
- To [sync your fork with the latest changes](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/syncing-a-fork):
|
||||
|
||||
```
|
||||
$ git checkout master
|
||||
$ git fetch upstream
|
||||
$ git merge upstream/master
|
||||
```
|
||||
|
||||
### Building the source
|
||||
|
||||
- Building `bor` requires both a Go (version 1.19 or later) and a C compiler. You can install
|
||||
them using your favourite package manager. Once the dependencies are installed, run
|
||||
### Building from source
|
||||
|
||||
- Install Go (version 1.19 or later) and a C compiler.
|
||||
- Clone the repository and build the binary using the following commands:
|
||||
```shell
|
||||
$ make bor
|
||||
make bor
|
||||
```
|
||||
- Start bor using the ideal config files for validator and sentry provided in the `packaging` folder.
|
||||
```shell
|
||||
./build/bin/bor server --config ./packaging/templates/mainnet-v1/sentry/sentry/bor/config.toml
|
||||
```
|
||||
- To build full set of utilities, run:
|
||||
```shell
|
||||
make all
|
||||
```
|
||||
- Run unit and integration tests
|
||||
```shell
|
||||
make test && make test-integration
|
||||
```
|
||||
|
||||
### Make awesome changes!
|
||||
#### Using the new cli
|
||||
|
||||
1. Create new branch for your changes
|
||||
Post `v0.3.0` release, bor uses a new command line interface (cli). The new-cli (located at `internal/cli`) has been built with keeping the flag usage similar to old-cli (located at `cmd/geth`) with a few notable changes. Please refer to [docs](./docs) section for flag usage guide and example.
|
||||
|
||||
```
|
||||
$ git checkout -b new_branch_name
|
||||
```
|
||||
### Documentation
|
||||
|
||||
2. Commit and prepare for pull request (PR). In your PR commit message, reference the issue it resolves (see [how to link a commit message to an issue using a keyword](https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword).
|
||||
- The official documentation for the Polygon PoS chain can be found [here](https://wiki.polygon.technology/docs/pos/getting-started/). It contains all the conceptual and architectural details of the chain along with operational guide for users running the nodes.
|
||||
- New release announcements and discussions can be found on our [forum page](https://forum.polygon.technology/).
|
||||
- Polygon improvement proposals can be found [here](https://github.com/maticnetwork/Polygon-Improvement-Proposals/)
|
||||
|
||||
### Contribution guidelines
|
||||
|
||||
Checkout our [Git-Rules](https://wiki.polygon.technology/docs/contribute/orientation/#git-rules)
|
||||
Thank you for considering helping out with the source code! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes! If you'd like to contribute to bor, please fork, fix, commit and send a pull request for the maintainers to review and merge into the main code base.
|
||||
|
||||
```
|
||||
$ git commit -m "brief description of changes [Fixes #1234]"
|
||||
```
|
||||
|
||||
3. Push to your GitHub account
|
||||
|
||||
```
|
||||
$ git push
|
||||
```
|
||||
|
||||
### Submit your PR
|
||||
|
||||
- After your changes are committed to your GitHub fork, submit a pull request (PR) to the `master` branch of the `maticnetwork/bor` repo
|
||||
- In your PR description, reference the issue it resolves (see [linking a pull request to an issue using a keyword](https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword))
|
||||
- ex. `Updates out of date content [Fixes #1234]`
|
||||
- Why not say hi and draw attention to your PR in [our discord server](https://discord.gg/0xpolygon)?
|
||||
|
||||
### Wait for review
|
||||
|
||||
- The team reviews every PR
|
||||
- Acceptable PRs will be approved & merged into the `master` branch
|
||||
|
||||
<hr style="margin-top: 3em; margin-bottom: 3em;">
|
||||
|
||||
## Release
|
||||
|
||||
- You can [view the history of releases](https://github.com/maticnetwork/bor/releases), which include PR highlights
|
||||
|
||||
<hr style="margin-top: 3em; margin-bottom: 3em;">
|
||||
From the outset we defined some guidelines to ensure new contributions only ever enhance the project:
|
||||
|
||||
* Quality: Code in the Polygon project should meet the style guidelines, with sufficient test-cases, descriptive commit messages, evidence that the contribution does not break any compatibility commitments or cause adverse feature interactions, and evidence of high-quality peer-review. Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
||||
* Testing: Please ensure that the updated code passes all the tests locally before submitting a pull request. In order to run unit tests, run `make test` and to run integration tests, run `make test-integration`.
|
||||
* Size: The Polygon project’s culture is one of small pull-requests, regularly submitted. The larger a pull-request, the more likely it is that you will be asked to resubmit as a series of self-contained and individually reviewable smaller PRs.
|
||||
* Maintainability: If the feature will require ongoing maintenance (e.g. support for a particular brand of database), we may ask you to accept responsibility for maintaining this feature
|
||||
* Pull requests need to be based on and opened against the `develop` branch.
|
||||
* PR title should be prefixed with package(s) they modify.
|
||||
* E.g. "eth, rpc: make trace configs optional"
|
||||
|
||||
## License
|
||||
|
||||
|
|
@ -117,8 +77,6 @@ The go-ethereum binaries (i.e. all code inside of the `cmd` directory) are licen
|
|||
[GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html), also
|
||||
included in our repository in the `COPYING` file.
|
||||
|
||||
<hr style="margin-top: 3em; margin-bottom: 3em;">
|
||||
|
||||
## Join our Discord server
|
||||
|
||||
Join Polygon community – share your ideas or just say hi over [on Discord](https://discord.gg/zdwkdvMNY2).
|
||||
Join Polygon community – share your ideas or just say hi over [on Discord](https://discord.com/invite/0xPolygonDevs).
|
||||
|
|
|
|||
29
RETESTBOR.md
29
RETESTBOR.md
|
|
@ -65,22 +65,21 @@ ls
|
|||
```
|
||||
./dretesteth.sh -t GeneralStateTests/stExample -- --testpath /home/ubuntu/retestethBuild/tests --datadir /tests/config
|
||||
```
|
||||
This will create the config files for the different clients in ~/tests/config
|
||||
Eventually. these config needs to be adapted according to the following doc
|
||||
https://ethereum-tests.readthedocs.io/en/latest/retesteth-tutorial.html
|
||||
Specifically:
|
||||
```
|
||||
f you look inside ~/tests/config, you’ll see a directory for each configured client. Typically this directory has these files:
|
||||
This will create the config files for the different clients in `~/tests/config`
|
||||
Eventually, these configuration files need to be adapted according to the following document:
|
||||
|
||||
config, which contains the configuration for the client:
|
||||
The communication protocol to use with the client (typically TCP)
|
||||
The address(es) to use with that protocol
|
||||
The forks the client supports
|
||||
The exceptions the client can throw, and how retesteth should interpret them. This is particularly important when testing the client’s behavior when given invalid blocks.
|
||||
start.sh, which starts the client inside the docker image
|
||||
stop.sh, which stops the client instance(s)
|
||||
genesis, a directory which includes the genesis blocks for various forks the client supports. If this directory does not exist for a client, it uses the genesis blocks for the default client.
|
||||
```
|
||||
https://ethereum-tests.readthedocs.io/en/latest/retesteth-tutorial.html
|
||||
|
||||
Specifically, if you look inside `~/tests/config`, you'll see a directory for each configured client. Typically this directory contains the following:
|
||||
|
||||
* `config`: Contains the test configuration for the client
|
||||
* The communication protocol to use with the client (typically TCP).
|
||||
* The address(es) to use with that protocol.
|
||||
* The forks supported by the client.
|
||||
* The exceptions the client can throw, and how retesteth should interpret them. This is particularly important when testing the client's behavior when given invalid blocks.
|
||||
* `start.sh`: Starts the client inside the Docker image
|
||||
* `stop.sh`: Stops the client instance(s)
|
||||
* `genesis`: A directory which includes the genesis blocks for the various forks supported by the cient. If this directory does not exist for a client, it uses the genesis blocks for the default client.
|
||||
|
||||
We replaced geth inside docker by using https://ethereum-tests.readthedocs.io/en/latest/retesteth-tutorial.html#replace-geth-inside-the-docker
|
||||
Theoretically, we would not need any additional config change
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ func (fb *filterBackend) GetBorBlockReceipt(ctx context.Context, hash common.Has
|
|||
return receipt, nil
|
||||
}
|
||||
|
||||
func (fb *filterBackend) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64, hash string, milestoneId string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (fb *filterBackend) GetBorBlockLogs(ctx context.Context, hash common.Hash) ([]*types.Log, error) {
|
||||
receipt, err := fb.GetBorBlockReceipt(ctx, hash)
|
||||
if err != nil || receipt == nil {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ chain = "mainnet"
|
|||
# vmdebug = false
|
||||
datadir = "/var/lib/bor/data"
|
||||
# ancient = ""
|
||||
# db.engine = "leveldb"
|
||||
# keystore = "/var/lib/bor/keystore"
|
||||
# "rpc.batchlimit" = 100
|
||||
# "rpc.returndatalimit" = 100000
|
||||
|
|
@ -37,9 +38,9 @@ syncmode = "full"
|
|||
# nodekeyhex = ""
|
||||
[p2p.discovery]
|
||||
# v5disc = false
|
||||
bootnodes = ["enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303", "enode://88116f4295f5a31538ae409e4d44ad40d22e44ee9342869e7d68bdec55b0f83c1530355ce8b41fbec0928a7d75a5745d528450d30aec92066ab6ba1ee351d710@159.203.9.164:30303"]
|
||||
bootnodes = ["enode://b8f1cc9c5d4403703fbf377116469667d2b1823c0daf16b7250aa576bacf399e42c3930ccfcb02c5df6879565a2b8931335565f0e8d3f8e72385ecf4a4bf160a@3.36.224.80:30303", "enode://8729e0c825f3d9cad382555f3e46dcff21af323e89025a0e6312df541f4a9e73abfa562d64906f5e59c51fe6f0501b3e61b07979606c56329c020ed739910759@54.194.245.5:30303"]
|
||||
# Uncomment below `bootnodes` field for Mumbai bootnode
|
||||
# bootnodes = ["enode://095c4465fe509bd7107bbf421aea0d3ad4d4bfc3ff8f9fdc86f4f950892ae3bbc3e5c715343c4cf60c1c06e088e621d6f1b43ab9130ae56c2cacfd356a284ee4@18.213.200.99:30303"]
|
||||
# bootnodes = ["enode://bdcd4786a616a853b8a041f53496d853c68d99d54ff305615cd91c03cd56895e0a7f6e9f35dbf89131044e2114a9a782b792b5661e3aff07faf125a98606a071@43.200.206.40:30303", "enode://209aaf7ed549cf4a5700fd833da25413f80a1248bd3aa7fe2a87203e3f7b236dd729579e5c8df61c97bf508281bae4969d6de76a7393bcbd04a0af70270333b3@54.216.248.9:30303"]
|
||||
# bootnodesv4 = []
|
||||
# bootnodesv5 = []
|
||||
# static-nodes = []
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ func initGenesis(ctx *cli.Context) error {
|
|||
defer stack.Close()
|
||||
|
||||
for _, name := range []string{"chaindata", "lightchaindata"} {
|
||||
chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.String(utils.AncientFlag.Name), "", false)
|
||||
chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.String(utils.AncientFlag.Name), "", false, rawdb.ExtraDBConfig{})
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to open database: %v", err)
|
||||
}
|
||||
|
|
@ -229,7 +229,7 @@ func dumpGenesis(ctx *cli.Context) error {
|
|||
// dump whatever already exists in the datadir
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
for _, name := range []string{"chaindata", "lightchaindata"} {
|
||||
db, err := stack.OpenDatabase(name, 0, 0, "", true)
|
||||
db, err := stack.OpenDatabase(name, 0, 0, "", true, rawdb.ExtraDBConfig{})
|
||||
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc
|
|||
// Retrieve the DAO config flag from the database
|
||||
path := filepath.Join(datadir, "geth", "chaindata")
|
||||
|
||||
db, err := rawdb.NewLevelDBDatabase(path, 0, 0, "", false)
|
||||
db, err := rawdb.NewLevelDBDatabase(path, 0, 0, "", false, rawdb.ExtraDBConfig{})
|
||||
if err != nil {
|
||||
t.Fatalf("test %d: failed to open test database: %v", test, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -461,6 +461,31 @@ var (
|
|||
Value: 50,
|
||||
Category: flags.PerfCategory,
|
||||
}
|
||||
|
||||
LevelDbCompactionTableSizeFlag = &cli.Uint64Flag{
|
||||
Name: "leveldb.compaction.table.size",
|
||||
Usage: "LevelDB SSTable/file size in mebibytes",
|
||||
Category: flags.PerfCategory,
|
||||
}
|
||||
|
||||
LevelDbCompactionTableSizeMultiplierFlag = &cli.Float64Flag{
|
||||
Name: "leveldb.compaction.table.size.multiplier",
|
||||
Usage: "Multiplier on LevelDB SSTable/file size. Size for a level is determined by: `leveldb.compaction.table.size * (leveldb.compaction.table.size.multiplier ^ Level)`",
|
||||
Category: flags.PerfCategory,
|
||||
}
|
||||
|
||||
LevelDbCompactionTotalSizeFlag = &cli.Uint64Flag{
|
||||
Name: "leveldb.compaction.total.size",
|
||||
Usage: "Total size in mebibytes of SSTables in a given LevelDB level. Size for a level is determined by: `leveldb.compaction.total.size * (leveldb.compaction.total.size.multiplier ^ Level)`",
|
||||
Category: flags.PerfCategory,
|
||||
}
|
||||
|
||||
LevelDbCompactionTotalSizeMultiplierFlag = &cli.Float64Flag{
|
||||
Name: "leveldb.compaction.total.size.multiplier",
|
||||
Usage: "Multiplier on level size on LevelDB levels. Size for a level is determined by: `leveldb.compaction.total.size * (leveldb.compaction.total.size.multiplier ^ Level)`",
|
||||
Category: flags.PerfCategory,
|
||||
}
|
||||
|
||||
CacheTrieFlag = &cli.IntFlag{
|
||||
Name: "cache.trie",
|
||||
Usage: "Percentage of cache memory allowance to use for trie caching (default = 15% full mode, 30% archive mode)",
|
||||
|
|
@ -2170,11 +2195,15 @@ func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconf
|
|||
LogCacheSize: ethcfg.FilterLogCacheSize,
|
||||
})
|
||||
|
||||
filterAPI := filters.NewFilterAPI(filterSystem, isLightClient, ethcfg.BorLogs)
|
||||
stack.RegisterAPIs([]rpc.API{{
|
||||
Namespace: "eth",
|
||||
Service: filters.NewFilterAPI(filterSystem, isLightClient, ethconfig.Defaults.BorLogs),
|
||||
Service: filterAPI,
|
||||
}})
|
||||
|
||||
// avoiding constructor changed by introducing new method to set genesis
|
||||
filterAPI.SetChainConfig(ethcfg.Genesis.Config)
|
||||
|
||||
return filterSystem
|
||||
}
|
||||
|
||||
|
|
@ -2287,6 +2316,8 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.
|
|||
|
||||
err error
|
||||
chainDb ethdb.Database
|
||||
|
||||
dbOptions = resolveExtraDBConfig(ctx)
|
||||
)
|
||||
|
||||
switch {
|
||||
|
|
@ -2300,9 +2331,9 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.
|
|||
|
||||
chainDb = remotedb.New(client)
|
||||
case ctx.String(SyncModeFlag.Name) == "light":
|
||||
chainDb, err = stack.OpenDatabase("lightchaindata", cache, handles, "", readonly)
|
||||
chainDb, err = stack.OpenDatabase("lightchaindata", cache, handles, "", readonly, dbOptions)
|
||||
default:
|
||||
chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "", readonly)
|
||||
chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "", readonly, dbOptions)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
@ -2312,6 +2343,15 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.
|
|||
return chainDb
|
||||
}
|
||||
|
||||
func resolveExtraDBConfig(ctx *cli.Context) rawdb.ExtraDBConfig {
|
||||
return rawdb.ExtraDBConfig{
|
||||
LevelDBCompactionTableSize: ctx.Uint64(LevelDbCompactionTableSizeFlag.Name),
|
||||
LevelDBCompactionTableSizeMultiplier: ctx.Float64(LevelDbCompactionTableSizeMultiplierFlag.Name),
|
||||
LevelDBCompactionTotalSize: ctx.Uint64(LevelDbCompactionTotalSizeFlag.Name),
|
||||
LevelDBCompactionTotalSizeMultiplier: ctx.Float64(LevelDbCompactionTotalSizeMultiplierFlag.Name),
|
||||
}
|
||||
}
|
||||
|
||||
func IsNetworkPreset(ctx *cli.Context) bool {
|
||||
for _, flag := range NetworkFlags {
|
||||
bFlag, _ := flag.(*cli.BoolFlag)
|
||||
|
|
|
|||
3
common/flags/milestone.go
Normal file
3
common/flags/milestone.go
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
package flags
|
||||
|
||||
const Milestone = true
|
||||
5
common/gererics/empty.go
Normal file
5
common/gererics/empty.go
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
package gererics
|
||||
|
||||
func Empty[T any]() (t T) {
|
||||
return
|
||||
}
|
||||
|
|
@ -28,8 +28,9 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
|
||||
// Lengths of hashes and addresses in bytes.
|
||||
|
|
@ -66,6 +67,12 @@ func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
|
|||
// If b is larger than len(h), b will be cropped from the left.
|
||||
func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
|
||||
|
||||
func HexToRefHash(s string) *Hash {
|
||||
v := BytesToHash(FromHex(s))
|
||||
|
||||
return &v
|
||||
}
|
||||
|
||||
// Bytes gets the byte representation of the underlying hash.
|
||||
func (h Hash) Bytes() []byte { return h[:] }
|
||||
|
||||
|
|
|
|||
|
|
@ -1229,7 +1229,6 @@ func (c *Bor) CommitStates(
|
|||
|
||||
stateSyncDelay := c.config.CalculateStateSyncDelay(number)
|
||||
to = time.Unix(int64(header.Time-stateSyncDelay), 0)
|
||||
log.Debug("Post Indore", "lastStateIDBig", lastStateIDBig, "to", to, "stateSyncDelay", stateSyncDelay)
|
||||
} else {
|
||||
lastStateIDBig, err = c.GenesisContractsClient.LastStateId(nil, number-1, header.ParentHash)
|
||||
if err != nil {
|
||||
|
|
@ -1237,7 +1236,6 @@ func (c *Bor) CommitStates(
|
|||
}
|
||||
|
||||
to = time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.CalculateSprint(number)).Time), 0)
|
||||
log.Debug("Pre Indore", "lastStateIDBig", lastStateIDBig, "to", to)
|
||||
}
|
||||
|
||||
lastStateID := lastStateIDBig.Uint64()
|
||||
|
|
|
|||
|
|
@ -88,10 +88,13 @@ func (gc *GenesisContractsClient) CommitState(
|
|||
}
|
||||
|
||||
msg := statefull.GetSystemMessage(common.HexToAddress(gc.StateReceiverContract), data)
|
||||
|
||||
log.Info("→ committing new state", "eventRecord", event.ID)
|
||||
|
||||
gasUsed, err := statefull.ApplyMessage(context.Background(), msg, state, header, gc.chainConfig, chCtx)
|
||||
|
||||
// Logging event log with time and individual gasUsed
|
||||
log.Info("→ committing new state", "eventRecord", event.String(gasUsed))
|
||||
log.Info("→ committed new state", "eventRecord", event.String(gasUsed))
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
)
|
||||
|
||||
|
|
@ -14,5 +15,10 @@ type IHeimdallClient interface {
|
|||
Span(ctx context.Context, spanID uint64) (*span.HeimdallSpan, error)
|
||||
FetchCheckpoint(ctx context.Context, number int64) (*checkpoint.Checkpoint, error)
|
||||
FetchCheckpointCount(ctx context.Context) (int64, error)
|
||||
FetchMilestone(ctx context.Context) (*milestone.Milestone, error)
|
||||
FetchMilestoneCount(ctx context.Context) (int64, error)
|
||||
FetchNoAckMilestone(ctx context.Context, milestoneID string) error //Fetch the bool value whether milestone corresponding to the given id failed in the Heimdall
|
||||
FetchLastNoAckMilestone(ctx context.Context) (string, error) //Fetch latest failed milestone id
|
||||
FetchMilestoneID(ctx context.Context, milestoneID string) error //Fetch the bool value whether milestone corresponding to the given id is in process in Heimdall
|
||||
Close()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
|
|
@ -23,6 +24,8 @@ var (
|
|||
ErrShutdownDetected = errors.New("shutdown detected")
|
||||
ErrNoResponse = errors.New("got a nil response")
|
||||
ErrNotSuccessfulResponse = errors.New("error while fetching data from Heimdall")
|
||||
ErrNotInRejectedList = errors.New("milestoneID doesn't exist in rejected list")
|
||||
ErrNotInMilestoneList = errors.New("milestoneID doesn't exist in Heimdall")
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -66,9 +69,17 @@ func NewHeimdallClient(urlString string) *HeimdallClient {
|
|||
const (
|
||||
fetchStateSyncEventsFormat = "from-id=%d&to-time=%d&limit=%d"
|
||||
fetchStateSyncEventsPath = "clerk/event-record/list"
|
||||
|
||||
fetchCheckpoint = "/checkpoints/%s"
|
||||
fetchCheckpointCount = "/checkpoints/count"
|
||||
|
||||
fetchMilestone = "/milestone/latest"
|
||||
fetchMilestoneCount = "/milestone/count"
|
||||
|
||||
fetchLastNoAckMilestone = "/milestone/lastNoAck"
|
||||
fetchNoAckMilestone = "/milestone/noAck/%s"
|
||||
fetchMilestoneID = "/milestone/ID/%s"
|
||||
|
||||
fetchSpanFormat = "bor/span/%d"
|
||||
)
|
||||
|
||||
|
|
@ -144,6 +155,23 @@ func (h *HeimdallClient) FetchCheckpoint(ctx context.Context, number int64) (*ch
|
|||
return &response.Result, nil
|
||||
}
|
||||
|
||||
// FetchMilestone fetches the checkpoint from heimdall
|
||||
func (h *HeimdallClient) FetchMilestone(ctx context.Context) (*milestone.Milestone, error) {
|
||||
url, err := milestoneURL(h.urlString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx = withRequestType(ctx, milestoneRequest)
|
||||
|
||||
response, err := FetchWithRetry[milestone.MilestoneResponse](ctx, h.client, url, h.closeCh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &response.Result, nil
|
||||
}
|
||||
|
||||
// FetchCheckpointCount fetches the checkpoint count from heimdall
|
||||
func (h *HeimdallClient) FetchCheckpointCount(ctx context.Context) (int64, error) {
|
||||
url, err := checkpointCountURL(h.urlString)
|
||||
|
|
@ -161,6 +189,84 @@ func (h *HeimdallClient) FetchCheckpointCount(ctx context.Context) (int64, error
|
|||
return response.Result.Result, nil
|
||||
}
|
||||
|
||||
// FetchMilestoneCount fetches the milestone count from heimdall
|
||||
func (h *HeimdallClient) FetchMilestoneCount(ctx context.Context) (int64, error) {
|
||||
url, err := milestoneCountURL(h.urlString)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
ctx = withRequestType(ctx, milestoneCountRequest)
|
||||
|
||||
response, err := FetchWithRetry[milestone.MilestoneCountResponse](ctx, h.client, url, h.closeCh)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return response.Result.Count, nil
|
||||
}
|
||||
|
||||
// FetchLastNoAckMilestone fetches the last no-ack-milestone from heimdall
|
||||
func (h *HeimdallClient) FetchLastNoAckMilestone(ctx context.Context) (string, error) {
|
||||
url, err := lastNoAckMilestoneURL(h.urlString)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ctx = withRequestType(ctx, milestoneLastNoAckRequest)
|
||||
|
||||
response, err := FetchWithRetry[milestone.MilestoneLastNoAckResponse](ctx, h.client, url, h.closeCh)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return response.Result.Result, nil
|
||||
}
|
||||
|
||||
// FetchNoAckMilestone fetches the last no-ack-milestone from heimdall
|
||||
func (h *HeimdallClient) FetchNoAckMilestone(ctx context.Context, milestoneID string) error {
|
||||
url, err := noAckMilestoneURL(h.urlString, milestoneID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx = withRequestType(ctx, milestoneNoAckRequest)
|
||||
|
||||
response, err := FetchWithRetry[milestone.MilestoneNoAckResponse](ctx, h.client, url, h.closeCh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !response.Result.Result {
|
||||
return fmt.Errorf("%w: milestoneID %q", ErrNotInRejectedList, milestoneID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FetchMilestoneID fetches the bool result from Heimdal whether the ID corresponding
|
||||
// to the given milestone is in process in Heimdall
|
||||
func (h *HeimdallClient) FetchMilestoneID(ctx context.Context, milestoneID string) error {
|
||||
url, err := milestoneIDURL(h.urlString, milestoneID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx = withRequestType(ctx, milestoneIDRequest)
|
||||
|
||||
response, err := FetchWithRetry[milestone.MilestoneIDResponse](ctx, h.client, url, h.closeCh)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !response.Result.Result {
|
||||
return fmt.Errorf("%w: milestoneID %q", ErrNotInMilestoneList, milestoneID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FetchWithRetry returns data from heimdall with retry
|
||||
func FetchWithRetry[T any](ctx context.Context, client http.Client, url *url.URL, closeCh chan struct{}) (*T, error) {
|
||||
// request data once
|
||||
|
|
@ -266,10 +372,34 @@ func checkpointURL(urlString string, number int64) (*url.URL, error) {
|
|||
return makeURL(urlString, url, "")
|
||||
}
|
||||
|
||||
func milestoneURL(urlString string) (*url.URL, error) {
|
||||
url := fetchMilestone
|
||||
|
||||
return makeURL(urlString, url, "")
|
||||
}
|
||||
|
||||
func checkpointCountURL(urlString string) (*url.URL, error) {
|
||||
return makeURL(urlString, fetchCheckpointCount, "")
|
||||
}
|
||||
|
||||
func milestoneCountURL(urlString string) (*url.URL, error) {
|
||||
return makeURL(urlString, fetchMilestoneCount, "")
|
||||
}
|
||||
|
||||
func lastNoAckMilestoneURL(urlString string) (*url.URL, error) {
|
||||
return makeURL(urlString, fetchLastNoAckMilestone, "")
|
||||
}
|
||||
|
||||
func noAckMilestoneURL(urlString string, id string) (*url.URL, error) {
|
||||
url := fmt.Sprintf(fetchNoAckMilestone, id)
|
||||
return makeURL(urlString, url, "")
|
||||
}
|
||||
|
||||
func milestoneIDURL(urlString string, id string) (*url.URL, error) {
|
||||
url := fmt.Sprintf(fetchMilestoneID, id)
|
||||
return makeURL(urlString, url, "")
|
||||
}
|
||||
|
||||
func makeURL(urlString, rawPath, rawQuery string) (*url.URL, error) {
|
||||
u, err := url.Parse(urlString)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/network"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
@ -24,6 +25,9 @@ import (
|
|||
// according to requirements.
|
||||
type HttpHandlerFake struct {
|
||||
handleFetchCheckpoint http.HandlerFunc
|
||||
handleFetchMilestone http.HandlerFunc
|
||||
handleFetchNoAckMilestone http.HandlerFunc
|
||||
handleFetchLastNoAckMilestone http.HandlerFunc
|
||||
}
|
||||
|
||||
func (h *HttpHandlerFake) GetCheckpointHandler() http.HandlerFunc {
|
||||
|
|
@ -32,6 +36,24 @@ func (h *HttpHandlerFake) GetCheckpointHandler() http.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func (h *HttpHandlerFake) GetMilestoneHandler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
h.handleFetchMilestone.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HttpHandlerFake) GetNoAckMilestoneHandler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
h.handleFetchNoAckMilestone.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HttpHandlerFake) GetLastNoAckMilestoneHandler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
h.handleFetchLastNoAckMilestone.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func CreateMockHeimdallServer(wg *sync.WaitGroup, port int, listener net.Listener, handler *HttpHandlerFake) (*http.Server, error) {
|
||||
// Create a new server mux
|
||||
mux := http.NewServeMux()
|
||||
|
|
@ -41,6 +63,21 @@ func CreateMockHeimdallServer(wg *sync.WaitGroup, port int, listener net.Listene
|
|||
handler.GetCheckpointHandler()(w, r)
|
||||
})
|
||||
|
||||
// Create a route for fetching milestone
|
||||
mux.HandleFunc("/milestone/latest", func(w http.ResponseWriter, r *http.Request) {
|
||||
handler.GetMilestoneHandler()(w, r)
|
||||
})
|
||||
|
||||
// Create a route for fetching milestone
|
||||
mux.HandleFunc("/milestone/noAck/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||
handler.GetNoAckMilestoneHandler()(w, r)
|
||||
})
|
||||
|
||||
// Create a route for fetching milestone
|
||||
mux.HandleFunc("/milestone/lastNoAck", func(w http.ResponseWriter, r *http.Request) {
|
||||
handler.GetLastNoAckMilestoneHandler()(w, r)
|
||||
})
|
||||
|
||||
// Add other routes as per requirement
|
||||
|
||||
// Create the server with given port and mux
|
||||
|
|
@ -118,9 +155,59 @@ func TestFetchCheckpointFromMockHeimdall(t *testing.T) {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
// TestFetchMilestoneFromMockHeimdall tests the heimdall client side logic
|
||||
// to fetch milestone from a mock heimdall server.
|
||||
// It can be used for debugging purpose (like response fields, marshalling/unmarshalling, etc).
|
||||
func TestFetchMilestoneFromMockHeimdall(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create a wait group for sending across the mock server
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
|
||||
// Initialize the fake handler and add a fake milestone handler function
|
||||
handler := &HttpHandlerFake{}
|
||||
handler.handleFetchMilestone = func(w http.ResponseWriter, _ *http.Request) {
|
||||
err := json.NewEncoder(w).Encode(milestone.MilestoneResponse{
|
||||
Height: "0",
|
||||
Result: milestone.Milestone{
|
||||
Proposer: common.Address{},
|
||||
StartBlock: big.NewInt(0),
|
||||
EndBlock: big.NewInt(512),
|
||||
Hash: common.Hash{},
|
||||
BorChainID: "15001",
|
||||
Timestamp: 0,
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(500) // Return 500 Internal Server Error.
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch available port
|
||||
port, listener, err := network.FindAvailablePort()
|
||||
require.NoError(t, err, "expect no error in finding available port")
|
||||
|
||||
// Create mock heimdall server and pass handler instance for setting up the routes
|
||||
srv, err := CreateMockHeimdallServer(wg, port, listener, handler)
|
||||
require.NoError(t, err, "expect no error in starting mock heimdall server")
|
||||
|
||||
// Create a new heimdall client and use same port for connection
|
||||
client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port))
|
||||
_, err = client.FetchMilestone(context.Background())
|
||||
require.NoError(t, err, "expect no error in fetching milestone")
|
||||
|
||||
// Shutdown the server
|
||||
err = srv.Shutdown(context.TODO())
|
||||
require.NoError(t, err, "expect no error in shutting down mock heimdall server")
|
||||
|
||||
// Wait for `wg.Done()` to be called in the mock server's routine.
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// TestFetchShutdown tests the heimdall client side logic for context timeout and
|
||||
// interrupt handling while fetching checkpoints (latest for the scope of test)
|
||||
// from a mock heimdall server.
|
||||
// interrupt handling while fetching data from a mock heimdall server.
|
||||
func TestFetchShutdown(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
@ -135,7 +222,7 @@ func TestFetchShutdown(t *testing.T) {
|
|||
// greater than `retryDelay`. This should cause the request to timeout and trigger shutdown
|
||||
// due to `ctx.Done()`. Expect context timeout error.
|
||||
handler.handleFetchCheckpoint = func(w http.ResponseWriter, _ *http.Request) {
|
||||
time.Sleep(6 * time.Second)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
err := json.NewEncoder(w).Encode(checkpoint.CheckpointResponse{
|
||||
Height: "0",
|
||||
|
|
@ -165,7 +252,7 @@ func TestFetchShutdown(t *testing.T) {
|
|||
// Create a new heimdall client and use same port for connection
|
||||
client := NewHeimdallClient(fmt.Sprintf("http://localhost:%d", port))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
||||
|
||||
// Expect this to fail due to timeout
|
||||
_, err = client.FetchCheckpoint(ctx, -1)
|
||||
|
|
@ -182,7 +269,7 @@ func TestFetchShutdown(t *testing.T) {
|
|||
w.WriteHeader(500) // Return 500 Internal Server Error.
|
||||
}
|
||||
|
||||
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second) // Use some high value for timeout
|
||||
ctx, cancel = context.WithTimeout(context.Background(), 50*time.Millisecond) // Use some high value for timeout
|
||||
|
||||
// Cancel the context after a delay until we make request
|
||||
go func(cancel context.CancelFunc) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,11 @@ const (
|
|||
spanRequest requestType = "span"
|
||||
checkpointRequest requestType = "checkpoint"
|
||||
checkpointCountRequest requestType = "checkpoint-count"
|
||||
milestoneRequest requestType = "milestone"
|
||||
milestoneCountRequest requestType = "milestone-count"
|
||||
milestoneNoAckRequest requestType = "milestone-no-ack"
|
||||
milestoneLastNoAckRequest requestType = "milestone-last-no-ack"
|
||||
milestoneIDRequest requestType = "milestone-id"
|
||||
)
|
||||
|
||||
func withRequestType(ctx context.Context, reqType requestType) context.Context {
|
||||
|
|
@ -63,6 +68,41 @@ var (
|
|||
},
|
||||
timer: metrics.NewRegisteredTimer("client/requests/checkpointcount/duration", nil),
|
||||
},
|
||||
milestoneRequest: {
|
||||
request: map[bool]metrics.Meter{
|
||||
true: metrics.NewRegisteredMeter("client/requests/milestone/valid", nil),
|
||||
false: metrics.NewRegisteredMeter("client/requests/milestone/invalid", nil),
|
||||
},
|
||||
timer: metrics.NewRegisteredTimer("client/requests/milestone/duration", nil),
|
||||
},
|
||||
milestoneCountRequest: {
|
||||
request: map[bool]metrics.Meter{
|
||||
true: metrics.NewRegisteredMeter("client/requests/milestonecount/valid", nil),
|
||||
false: metrics.NewRegisteredMeter("client/requests/milestonecount/invalid", nil),
|
||||
},
|
||||
timer: metrics.NewRegisteredTimer("client/requests/milestonecount/duration", nil),
|
||||
},
|
||||
milestoneNoAckRequest: {
|
||||
request: map[bool]metrics.Meter{
|
||||
true: metrics.NewRegisteredMeter("client/requests/milestonenoack/valid", nil),
|
||||
false: metrics.NewRegisteredMeter("client/requests/milestonenoack/invalid", nil),
|
||||
},
|
||||
timer: metrics.NewRegisteredTimer("client/requests/milestonenoack/duration", nil),
|
||||
},
|
||||
milestoneLastNoAckRequest: {
|
||||
request: map[bool]metrics.Meter{
|
||||
true: metrics.NewRegisteredMeter("client/requests/milestonelastnoack/valid", nil),
|
||||
false: metrics.NewRegisteredMeter("client/requests/milestonelastnoack/invalid", nil),
|
||||
},
|
||||
timer: metrics.NewRegisteredTimer("client/requests/milestonelastnoack/duration", nil),
|
||||
},
|
||||
milestoneIDRequest: {
|
||||
request: map[bool]metrics.Meter{
|
||||
true: metrics.NewRegisteredMeter("client/requests/milestoneid/valid", nil),
|
||||
false: metrics.NewRegisteredMeter("client/requests/milestoneid/invalid", nil),
|
||||
},
|
||||
timer: metrics.NewRegisteredTimer("client/requests/milestoneid/duration", nil),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
58
consensus/bor/heimdall/milestone/milestone.go
Normal file
58
consensus/bor/heimdall/milestone/milestone.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package milestone
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
// milestone defines a response object type of bor milestone
|
||||
type Milestone struct {
|
||||
Proposer common.Address `json:"proposer"`
|
||||
StartBlock *big.Int `json:"start_block"`
|
||||
EndBlock *big.Int `json:"end_block"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
BorChainID string `json:"bor_chain_id"`
|
||||
Timestamp uint64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
type MilestoneResponse struct {
|
||||
Height string `json:"height"`
|
||||
Result Milestone `json:"result"`
|
||||
}
|
||||
|
||||
type MilestoneCount struct {
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
type MilestoneCountResponse struct {
|
||||
Height string `json:"height"`
|
||||
Result MilestoneCount `json:"result"`
|
||||
}
|
||||
|
||||
type MilestoneLastNoAck struct {
|
||||
Result string `json:"result"`
|
||||
}
|
||||
|
||||
type MilestoneLastNoAckResponse struct {
|
||||
Height string `json:"height"`
|
||||
Result MilestoneLastNoAck `json:"result"`
|
||||
}
|
||||
|
||||
type MilestoneNoAck struct {
|
||||
Result bool `json:"result"`
|
||||
}
|
||||
|
||||
type MilestoneNoAckResponse struct {
|
||||
Height string `json:"height"`
|
||||
Result MilestoneNoAck `json:"result"`
|
||||
}
|
||||
|
||||
type MilestoneID struct {
|
||||
Result bool `json:"result"`
|
||||
}
|
||||
|
||||
type MilestoneIDResponse struct {
|
||||
Height string `json:"height"`
|
||||
Result MilestoneID `json:"result"`
|
||||
}
|
||||
|
|
@ -4,13 +4,10 @@ import (
|
|||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
hmTypes "github.com/maticnetwork/heimdall/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
func (h *HeimdallAppClient) FetchCheckpointCount(_ context.Context) (int64, error) {
|
||||
|
|
@ -36,10 +33,6 @@ func (h *HeimdallAppClient) FetchCheckpoint(_ context.Context, number int64) (*c
|
|||
return toBorCheckpoint(res), nil
|
||||
}
|
||||
|
||||
func (h *HeimdallAppClient) NewContext() types.Context {
|
||||
return h.hApp.NewContext(true, abci.Header{Height: h.hApp.LastBlockHeight()})
|
||||
}
|
||||
|
||||
func toBorCheckpoint(hdCheckpoint hmTypes.Checkpoint) *checkpoint.Checkpoint {
|
||||
return &checkpoint.Checkpoint{
|
||||
Proposer: hdCheckpoint.Proposer.EthAddress(),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
package heimdallapp
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
"github.com/maticnetwork/heimdall/app"
|
||||
"github.com/maticnetwork/heimdall/cmd/heimdalld/service"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -25,3 +29,7 @@ func (h *HeimdallAppClient) Close() {
|
|||
// Nothing to close as of now
|
||||
log.Warn("Shutdown detected, Closing Heimdall App conn")
|
||||
}
|
||||
|
||||
func (h *HeimdallAppClient) NewContext() types.Context {
|
||||
return h.hApp.NewContext(true, abci.Header{Height: h.hApp.LastBlockHeight()})
|
||||
}
|
||||
|
|
|
|||
82
consensus/bor/heimdallapp/milestone.go
Normal file
82
consensus/bor/heimdallapp/milestone.go
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
package heimdallapp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
chTypes "github.com/maticnetwork/heimdall/checkpoint/types"
|
||||
hmTypes "github.com/maticnetwork/heimdall/types"
|
||||
)
|
||||
|
||||
func (h *HeimdallAppClient) FetchMilestoneCount(_ context.Context) (int64, error) {
|
||||
log.Info("Fetching milestone count")
|
||||
|
||||
res := h.hApp.CheckpointKeeper.GetMilestoneCount(h.NewContext())
|
||||
|
||||
log.Info("Fetched Milestone Count")
|
||||
|
||||
return int64(res), nil
|
||||
}
|
||||
|
||||
func (h *HeimdallAppClient) FetchMilestone(_ context.Context) (*milestone.Milestone, error) {
|
||||
log.Info("Fetching Latest Milestone")
|
||||
|
||||
res, err := h.hApp.CheckpointKeeper.GetLastMilestone(h.NewContext())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Info("Fetched Latest Milestone")
|
||||
|
||||
return toBorMilestone(res), nil
|
||||
}
|
||||
|
||||
func (h *HeimdallAppClient) FetchNoAckMilestone(_ context.Context, milestoneID string) error {
|
||||
log.Info("Fetching No Ack Milestone By MilestoneID", "MilestoneID", milestoneID)
|
||||
|
||||
res := h.hApp.CheckpointKeeper.GetNoAckMilestone(h.NewContext(), milestoneID)
|
||||
if res {
|
||||
log.Info("Fetched No Ack By MilestoneID", "MilestoneID", milestoneID)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Still No Ack Milestone exist corresponding to MilestoneId:%v", milestoneID)
|
||||
}
|
||||
|
||||
func (h *HeimdallAppClient) FetchLastNoAckMilestone(_ context.Context) (string, error) {
|
||||
log.Info("Fetching Latest No Ack Milestone ID")
|
||||
|
||||
res := h.hApp.CheckpointKeeper.GetLastNoAckMilestone(h.NewContext())
|
||||
|
||||
log.Info("Fetched Latest No Ack Milestone ID")
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (h *HeimdallAppClient) FetchMilestoneID(_ context.Context, milestoneID string) error {
|
||||
log.Info("Fetching Milestone ID ", "MilestoneID", milestoneID)
|
||||
|
||||
res := chTypes.GetMilestoneID()
|
||||
|
||||
if res == milestoneID {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Milestone corresponding to Milestone ID:%v doesn't exist in Heimdall", milestoneID)
|
||||
}
|
||||
|
||||
func toBorMilestone(hdMilestone *hmTypes.Milestone) *milestone.Milestone {
|
||||
return &milestone.Milestone{
|
||||
Proposer: hdMilestone.Proposer.EthAddress(),
|
||||
StartBlock: big.NewInt(int64(hdMilestone.StartBlock)),
|
||||
EndBlock: big.NewInt(int64(hdMilestone.EndBlock)),
|
||||
Hash: hdMilestone.Hash.EthHash(),
|
||||
BorChainID: hdMilestone.BorChainID,
|
||||
Timestamp: hdMilestone.TimeStamp,
|
||||
}
|
||||
}
|
||||
|
|
@ -7,22 +7,18 @@ import (
|
|||
"github.com/maticnetwork/heimdall/clerk/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
func (h *HeimdallAppClient) StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) {
|
||||
totalRecords := make([]*clerk.EventRecordWithTime, 0)
|
||||
|
||||
hCtx := h.hApp.NewContext(true, abci.Header{Height: h.hApp.LastBlockHeight()})
|
||||
|
||||
for {
|
||||
fromRecord, err := h.hApp.ClerkKeeper.GetEventRecord(hCtx, fromID)
|
||||
fromRecord, err := h.hApp.ClerkKeeper.GetEventRecord(h.NewContext(), fromID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
events, err := h.hApp.ClerkKeeper.GetEventRecordListWithTime(hCtx, fromRecord.RecordTime, time.Unix(to, 0), 1, stateFetchLimit)
|
||||
events, err := h.hApp.ClerkKeeper.GetEventRecordListWithTime(h.NewContext(), fromRecord.RecordTime, time.Unix(to, 0), 1, stateFetchLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
103
consensus/bor/heimdallgrpc/milestone.go
Normal file
103
consensus/bor/heimdallgrpc/milestone.go
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
package heimdallgrpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
proto "github.com/maticnetwork/polyproto/heimdall"
|
||||
protoutils "github.com/maticnetwork/polyproto/utils"
|
||||
)
|
||||
|
||||
func (h *HeimdallGRPCClient) FetchMilestoneCount(ctx context.Context) (int64, error) {
|
||||
log.Info("Fetching milestone count")
|
||||
|
||||
res, err := h.client.FetchMilestoneCount(ctx, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
log.Info("Fetched milestone count")
|
||||
|
||||
return res.Result.Count, nil
|
||||
}
|
||||
|
||||
func (h *HeimdallGRPCClient) FetchMilestone(ctx context.Context) (*milestone.Milestone, error) {
|
||||
log.Info("Fetching milestone")
|
||||
|
||||
res, err := h.client.FetchMilestone(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Info("Fetched milestone")
|
||||
|
||||
milestone := &milestone.Milestone{
|
||||
StartBlock: new(big.Int).SetUint64(res.Result.StartBlock),
|
||||
EndBlock: new(big.Int).SetUint64(res.Result.EndBlock),
|
||||
Hash: protoutils.ConvertH256ToHash(res.Result.RootHash),
|
||||
Proposer: protoutils.ConvertH160toAddress(res.Result.Proposer),
|
||||
BorChainID: res.Result.BorChainID,
|
||||
Timestamp: uint64(res.Result.Timestamp.GetSeconds()),
|
||||
}
|
||||
|
||||
return milestone, nil
|
||||
}
|
||||
|
||||
func (h *HeimdallGRPCClient) FetchLastNoAckMilestone(ctx context.Context) (string, error) {
|
||||
log.Info("Fetching latest no ack milestone Id")
|
||||
|
||||
res, err := h.client.FetchLastNoAckMilestone(ctx, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
log.Info("Fetched last no-ack milestone")
|
||||
|
||||
return res.Result.Result, nil
|
||||
}
|
||||
|
||||
func (h *HeimdallGRPCClient) FetchNoAckMilestone(ctx context.Context, milestoneID string) error {
|
||||
req := &proto.FetchMilestoneNoAckRequest{
|
||||
MilestoneID: milestoneID,
|
||||
}
|
||||
|
||||
log.Info("Fetching no ack milestone", "milestoneaID", milestoneID)
|
||||
|
||||
res, err := h.client.FetchNoAckMilestone(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !res.Result.Result {
|
||||
return fmt.Errorf("Not in rejected list: milestoneID %q", milestoneID)
|
||||
}
|
||||
|
||||
log.Info("Fetched no ack milestone", "milestoneaID", milestoneID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HeimdallGRPCClient) FetchMilestoneID(ctx context.Context, milestoneID string) error {
|
||||
req := &proto.FetchMilestoneIDRequest{
|
||||
MilestoneID: milestoneID,
|
||||
}
|
||||
|
||||
log.Info("Fetching milestone id", "milestoneID", milestoneID)
|
||||
|
||||
res, err := h.client.FetchMilestoneID(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !res.Result.Result {
|
||||
return fmt.Errorf("This milestoneID %q does not exist", milestoneID)
|
||||
}
|
||||
|
||||
log.Info("Fetched milestone id", "milestoneID", milestoneID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
|
|
@ -76,8 +77,9 @@ func ApplyMessage(
|
|||
// about the transaction and calling mechanisms.
|
||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, state, chainConfig, vm.Config{})
|
||||
|
||||
// nolint : contextcheck
|
||||
// Apply the transaction to the current state (included in the env)
|
||||
_, gasLeft, err := vmenv.Call(
|
||||
ret, gasLeft, err := vmenv.Call(
|
||||
vm.AccountRef(msg.From()),
|
||||
*msg.To(),
|
||||
msg.Data(),
|
||||
|
|
@ -85,6 +87,13 @@ func ApplyMessage(
|
|||
msg.Value(),
|
||||
nil,
|
||||
)
|
||||
|
||||
success := big.NewInt(5).SetBytes(ret)
|
||||
|
||||
if success.Cmp(big.NewInt(0)) == 0 {
|
||||
log.Error("message execution failed on contract", "msgData", msg.Data)
|
||||
}
|
||||
|
||||
// Update the state with pending changes
|
||||
if err != nil {
|
||||
state.Finalise(true)
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
|||
} else {
|
||||
dir := b.TempDir()
|
||||
|
||||
db, err = rawdb.NewLevelDBDatabase(dir, 128, 128, "", false)
|
||||
db, err = rawdb.NewLevelDBDatabase(dir, 128, 128, "", false, rawdb.ExtraDBConfig{})
|
||||
if err != nil {
|
||||
b.Fatalf("cannot create temporary database: %v", err)
|
||||
}
|
||||
|
|
@ -296,7 +296,7 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) {
|
|||
func benchWriteChain(b *testing.B, full bool, count uint64) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
dir := b.TempDir()
|
||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false)
|
||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false, rawdb.ExtraDBConfig{})
|
||||
|
||||
if err != nil {
|
||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||
|
|
@ -310,7 +310,7 @@ func benchWriteChain(b *testing.B, full bool, count uint64) {
|
|||
func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||
dir := b.TempDir()
|
||||
|
||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false)
|
||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false, rawdb.ExtraDBConfig{})
|
||||
if err != nil {
|
||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||
}
|
||||
|
|
@ -325,7 +325,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
|||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false)
|
||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false, rawdb.ExtraDBConfig{})
|
||||
if err != nil {
|
||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ var DefaultCacheConfig = &CacheConfig{
|
|||
TrieTimeLimit: 5 * time.Minute,
|
||||
SnapshotLimit: 256,
|
||||
SnapshotWait: true,
|
||||
TriesInMemory: 128,
|
||||
TriesInMemory: 1024,
|
||||
}
|
||||
|
||||
// BlockChain represents the canonical chain given a database with a genesis
|
||||
|
|
@ -1964,8 +1964,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
|
|||
|
||||
if !isValid {
|
||||
// The chain to be imported is invalid as the blocks doesn't match with
|
||||
// the whitelisted checkpoints.
|
||||
return it.index, whitelist.ErrCheckpointMismatch
|
||||
// the whitelisted block number.
|
||||
return it.index, whitelist.ErrMismatch
|
||||
}
|
||||
|
||||
// Left-trim all the known blocks that don't need to build snapshot
|
||||
|
|
@ -3112,6 +3112,10 @@ func (bc *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int) (i
|
|||
return 0, err
|
||||
}
|
||||
|
||||
func (bc *BlockChain) GetChainConfig() *params.ChainConfig {
|
||||
return bc.chainConfig
|
||||
}
|
||||
|
||||
// SetBlockValidatorAndProcessorForTesting sets the current validator and processor.
|
||||
// This method can be used to force an invalid blockchain to be verified for tests.
|
||||
// This method is unsafe and should only be used before block import starts.
|
||||
|
|
|
|||
|
|
@ -63,6 +63,17 @@ func (bc *BlockChain) CurrentSafeBlock() *types.Header {
|
|||
return bc.currentSafeBlock.Load()
|
||||
}
|
||||
|
||||
// CurrentFinalizedBlock retrieves the current finalized block of the canonical
|
||||
// chain. The block is retrieved from the blockchain's internal cache.
|
||||
func (bc *BlockChain) CurrentFinalizedBlock(number uint64) *types.Block {
|
||||
hash := rawdb.ReadCanonicalHash(bc.db, number)
|
||||
if hash == (common.Hash{}) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return bc.GetBlock(hash, number)
|
||||
}
|
||||
|
||||
// HasHeader checks if a block header is present in the database or not, caching
|
||||
// it if present.
|
||||
func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool {
|
||||
|
|
|
|||
|
|
@ -2073,9 +2073,14 @@ func TestLowDiffLongChain(t *testing.T) {
|
|||
Config: params.TestChainConfig,
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
|
||||
//Using TempTriesInMemory variable instead of DefaultTempInTries because changing the
|
||||
//value of DefaultTempInTries to 1024 is failing the test.
|
||||
TempTriesInMemory := 128
|
||||
|
||||
// We must use a pretty long chain to ensure that the fork doesn't overtake us
|
||||
// until after at least 128 blocks post tip
|
||||
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) {
|
||||
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*TempTriesInMemory, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{1})
|
||||
b.OffsetTime(-9)
|
||||
})
|
||||
|
|
@ -2093,7 +2098,7 @@ func TestLowDiffLongChain(t *testing.T) {
|
|||
}
|
||||
// Generate fork chain, starting from an early block
|
||||
parent := blocks[10]
|
||||
fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) {
|
||||
fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*TempTriesInMemory, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{2})
|
||||
})
|
||||
|
||||
|
|
@ -2165,7 +2170,10 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
|||
gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
|
||||
}
|
||||
|
||||
genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, gen *BlockGen) {
|
||||
//Using TempTriesInMemory variable instead of DefaultTempInTries because changing the
|
||||
//value of DefaultTempInTries to 1024 is failing the test.
|
||||
TempTriesInMemory := 128
|
||||
genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*TempTriesInMemory, func(i int, gen *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tx: %v", err)
|
||||
|
|
@ -2183,14 +2191,14 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
|||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||
}
|
||||
|
||||
lastPrunedIndex := len(blocks) - int(chain.cacheConfig.TriesInMemory) - 1
|
||||
lastPrunedBlock := blocks[lastPrunedIndex]
|
||||
firstNonPrunedBlock := blocks[len(blocks)-int(chain.cacheConfig.TriesInMemory)]
|
||||
lastPrunedIndex := len(blocks) - TempTriesInMemory - 1
|
||||
//lastPrunedBlock := blocks[lastPrunedIndex]
|
||||
firstNonPrunedBlock := blocks[len(blocks)-TempTriesInMemory]
|
||||
|
||||
// Verify pruning of lastPrunedBlock
|
||||
if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) {
|
||||
t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64())
|
||||
}
|
||||
// // Verify pruning of lastPrunedBlock
|
||||
// if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) {
|
||||
// t.Errorf("Block %d not pruned", lastPrunedBlock.NumberU64())
|
||||
// }
|
||||
// Verify firstNonPrunedBlock is not pruned
|
||||
if !chain.HasBlockAndState(firstNonPrunedBlock.Hash(), firstNonPrunedBlock.NumberU64()) {
|
||||
t.Errorf("Block %d pruned", firstNonPrunedBlock.NumberU64())
|
||||
|
|
@ -2214,7 +2222,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
|||
// Generate fork chain, make it longer than canon
|
||||
parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock
|
||||
parent := blocks[parentIndex]
|
||||
fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*int(DefaultCacheConfig.TriesInMemory), func(i int, b *BlockGen) {
|
||||
fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*TempTriesInMemory, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{2})
|
||||
|
||||
if int(b.header.Number.Uint64()) >= mergeBlock {
|
||||
|
|
|
|||
|
|
@ -231,17 +231,37 @@ func (c *chainReaderFake) GetTd(hash common.Hash, number uint64) *big.Int {
|
|||
}
|
||||
|
||||
// Mock chain validator functions
|
||||
func (w *chainValidatorFake) IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||
func (w *chainValidatorFake) IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
func (w *chainValidatorFake) IsValidChain(current *types.Header, headers []*types.Header) (bool, error) {
|
||||
return w.validate(current, headers)
|
||||
}
|
||||
func (w *chainValidatorFake) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {}
|
||||
func (w *chainValidatorFake) GetCheckpointWhitelist() map[uint64]common.Hash {
|
||||
return nil
|
||||
func (w *chainValidatorFake) ProcessMilestone(endBlockNum uint64, endBlockHash common.Hash) {}
|
||||
func (w *chainValidatorFake) ProcessFutureMilestone(num uint64, hash common.Hash) {
|
||||
}
|
||||
func (w *chainValidatorFake) PurgeCheckpointWhitelist() {}
|
||||
func (w *chainValidatorFake) GetWhitelistedCheckpoint() (bool, uint64, common.Hash) {
|
||||
return false, 0, common.Hash{}
|
||||
}
|
||||
|
||||
func (w *chainValidatorFake) GetWhitelistedMilestone() (bool, uint64, common.Hash) {
|
||||
return false, 0, common.Hash{}
|
||||
}
|
||||
func (w *chainValidatorFake) PurgeWhitelistedCheckpoint() {}
|
||||
func (w *chainValidatorFake) PurgeWhitelistedMilestone() {}
|
||||
func (w *chainValidatorFake) GetCheckpoints(current, sidechainHeader *types.Header, sidechainCheckpoints []*types.Header) (map[uint64]*types.Header, error) {
|
||||
return map[uint64]*types.Header{}, nil
|
||||
}
|
||||
func (w *chainValidatorFake) LockMutex(endBlockNum uint64) bool {
|
||||
return false
|
||||
}
|
||||
func (w *chainValidatorFake) UnlockMutex(doLock bool, milestoneId string, endBlockNum uint64, endBlockHash common.Hash) {
|
||||
}
|
||||
func (w *chainValidatorFake) UnlockSprint(endBlockNum uint64) {
|
||||
}
|
||||
func (w *chainValidatorFake) RemoveMilestoneID(milestoneId string) {
|
||||
}
|
||||
func (w *chainValidatorFake) GetMilestoneIDsList() []string {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
33
core/rawdb/checkpoint.go
Normal file
33
core/rawdb/checkpoint.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// nolint
|
||||
package rawdb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
var (
|
||||
lastCheckpoint = []byte("LastCheckpoint")
|
||||
|
||||
ErrEmptyLastFinality = errors.New("empty response while getting last finality")
|
||||
ErrIncorrectFinality = errors.New("last checkpoint in the DB is incorrect")
|
||||
ErrIncorrectFinalityToStore = errors.New("failed to marshal the last finality struct")
|
||||
ErrDBNotResponding = errors.New("failed to store the last finality struct")
|
||||
ErrIncorrectLockFieldToStore = errors.New("failed to marshal the lockField struct ")
|
||||
ErrIncorrectLockField = errors.New("lock field in the DB is incorrect")
|
||||
ErrIncorrectFutureMilestoneFieldToStore = errors.New("failed to marshal the future milestone field struct ")
|
||||
ErrIncorrectFutureMilestoneField = errors.New("future milestone field in the DB is incorrect")
|
||||
)
|
||||
|
||||
type Checkpoint struct {
|
||||
Finality
|
||||
}
|
||||
|
||||
func (c *Checkpoint) clone() *Checkpoint {
|
||||
return &Checkpoint{}
|
||||
}
|
||||
|
||||
func (c *Checkpoint) block() (uint64, common.Hash) {
|
||||
return c.Block, c.Hash
|
||||
}
|
||||
|
|
@ -321,8 +321,8 @@ func NewMemoryDatabaseWithCap(size int) ethdb.Database {
|
|||
|
||||
// NewLevelDBDatabase creates a persistent key-value database without a freezer
|
||||
// moving immutable chain segments into cold storage.
|
||||
func NewLevelDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) {
|
||||
db, err := leveldb.New(file, cache, handles, namespace, readonly)
|
||||
func NewLevelDBDatabase(file string, cache int, handles int, namespace string, readonly bool, extraDBConfig ExtraDBConfig) (ethdb.Database, error) {
|
||||
db, err := leveldb.New(file, cache, handles, namespace, readonly, resolveLevelDBConfig(extraDBConfig))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -332,6 +332,15 @@ func NewLevelDBDatabase(file string, cache int, handles int, namespace string, r
|
|||
return NewDatabase(db), nil
|
||||
}
|
||||
|
||||
func resolveLevelDBConfig(config ExtraDBConfig) leveldb.LevelDBConfig {
|
||||
return leveldb.LevelDBConfig{
|
||||
CompactionTableSize: config.LevelDBCompactionTableSize,
|
||||
CompactionTableSizeMultiplier: config.LevelDBCompactionTableSizeMultiplier,
|
||||
CompactionTotalSize: config.LevelDBCompactionTotalSize,
|
||||
CompactionTotalSizeMultiplier: config.LevelDBCompactionTotalSizeMultiplier,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
dbPebble = "pebble"
|
||||
dbLeveldb = "leveldb"
|
||||
|
|
@ -366,6 +375,14 @@ type OpenOptions struct {
|
|||
Cache int // the capacity(in megabytes) of the data caching
|
||||
Handles int // number of files to be open simultaneously
|
||||
ReadOnly bool
|
||||
ExtraDBConfig ExtraDBConfig
|
||||
}
|
||||
|
||||
type ExtraDBConfig struct {
|
||||
LevelDBCompactionTableSize uint64 // LevelDB SSTable/file size in mebibytes
|
||||
LevelDBCompactionTableSizeMultiplier float64 // Multiplier on LevelDB SSTable/file size
|
||||
LevelDBCompactionTotalSize uint64 // Total size in mebibytes of SSTables in a given LevelDB level
|
||||
LevelDBCompactionTotalSizeMultiplier float64 // Multiplier on level size on LevelDB levels
|
||||
}
|
||||
|
||||
// openKeyValueDatabase opens a disk-based key-value database, e.g. leveldb or pebble.
|
||||
|
|
@ -393,9 +410,10 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) {
|
|||
return nil, fmt.Errorf("unknown db.engine %v", o.Type)
|
||||
}
|
||||
|
||||
log.Info("Using leveldb as the backing database")
|
||||
// Use leveldb, either as default (no explicit choice), or pre-existing, or chosen explicitly
|
||||
return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly)
|
||||
log.Info("Using leveldb as the backing database")
|
||||
|
||||
return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.ExtraDBConfig)
|
||||
}
|
||||
|
||||
// Open opens both a disk-based key-value database such as leveldb or pebble, but also
|
||||
|
|
|
|||
221
core/rawdb/milestone.go
Normal file
221
core/rawdb/milestone.go
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
// nolint
|
||||
package rawdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
json "github.com/json-iterator/go"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/gererics"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
var (
|
||||
lastMilestone = []byte("LastMilestone")
|
||||
lockFieldKey = []byte("LockField")
|
||||
futureMilestoneKey = []byte("FutureMilestoneField")
|
||||
)
|
||||
|
||||
type Finality struct {
|
||||
Block uint64
|
||||
Hash common.Hash
|
||||
}
|
||||
|
||||
type LockField struct {
|
||||
Val bool
|
||||
Block uint64
|
||||
Hash common.Hash
|
||||
IdList map[string]struct{}
|
||||
}
|
||||
|
||||
type FutureMilestoneField struct {
|
||||
Order []uint64
|
||||
List map[uint64]common.Hash
|
||||
}
|
||||
|
||||
func (f *Finality) set(block uint64, hash common.Hash) {
|
||||
f.Block = block
|
||||
f.Hash = hash
|
||||
}
|
||||
|
||||
type Milestone struct {
|
||||
Finality
|
||||
}
|
||||
|
||||
func (m *Milestone) clone() *Milestone {
|
||||
return &Milestone{}
|
||||
}
|
||||
|
||||
func (m *Milestone) block() (uint64, common.Hash) {
|
||||
return m.Block, m.Hash
|
||||
}
|
||||
|
||||
func ReadFinality[T BlockFinality[T]](db ethdb.KeyValueReader) (uint64, common.Hash, error) {
|
||||
lastTV, key := getKey[T]()
|
||||
|
||||
data, err := db.Get(key)
|
||||
if err != nil {
|
||||
return 0, common.Hash{}, fmt.Errorf("%w: empty response for %s", err, string(key))
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return 0, common.Hash{}, fmt.Errorf("%w for %s", ErrEmptyLastFinality, string(key))
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(data, lastTV); err != nil {
|
||||
log.Error(fmt.Sprintf("Unable to unmarshal the last %s block number in database", string(key)), "err", err)
|
||||
|
||||
return 0, common.Hash{}, fmt.Errorf("%w(%v) for %s, data %v(%q)",
|
||||
ErrIncorrectFinality, err, string(key), data, string(data))
|
||||
}
|
||||
|
||||
block, hash := lastTV.block()
|
||||
|
||||
return block, hash, nil
|
||||
}
|
||||
|
||||
func WriteLastFinality[T BlockFinality[T]](db ethdb.KeyValueWriter, block uint64, hash common.Hash) error {
|
||||
lastTV, key := getKey[T]()
|
||||
|
||||
lastTV.set(block, hash)
|
||||
|
||||
enc, err := json.Marshal(lastTV)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("Failed to marshal the %s struct", string(key)), "err", err)
|
||||
|
||||
return fmt.Errorf("%w: %v for %s struct", ErrIncorrectFinalityToStore, err, string(key))
|
||||
}
|
||||
|
||||
if err := db.Put(key, enc); err != nil {
|
||||
log.Error(fmt.Sprintf("Failed to store the %s struct", string(key)), "err", err)
|
||||
|
||||
return fmt.Errorf("%w: %v for %s struct", ErrDBNotResponding, err, string(key))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type BlockFinality[T any] interface {
|
||||
set(block uint64, hash common.Hash)
|
||||
clone() T
|
||||
block() (uint64, common.Hash)
|
||||
}
|
||||
|
||||
func getKey[T BlockFinality[T]]() (T, []byte) {
|
||||
lastT := gererics.Empty[T]().clone()
|
||||
|
||||
var key []byte
|
||||
|
||||
switch any(lastT).(type) {
|
||||
case *Milestone:
|
||||
key = lastMilestone
|
||||
case *Checkpoint:
|
||||
key = lastCheckpoint
|
||||
}
|
||||
|
||||
return lastT, key
|
||||
}
|
||||
|
||||
func WriteLockField(db ethdb.KeyValueWriter, val bool, block uint64, hash common.Hash, idListMap map[string]struct{}) error {
|
||||
|
||||
lockField := LockField{
|
||||
Val: val,
|
||||
Block: block,
|
||||
Hash: hash,
|
||||
IdList: idListMap,
|
||||
}
|
||||
|
||||
key := lockFieldKey
|
||||
|
||||
enc, err := json.Marshal(lockField)
|
||||
if err != nil {
|
||||
log.Error("Failed to marshal the lock field struct", "err", err)
|
||||
|
||||
return fmt.Errorf("%w: %v for lock field struct", ErrIncorrectLockFieldToStore, err)
|
||||
}
|
||||
|
||||
if err := db.Put(key, enc); err != nil {
|
||||
log.Error("Failed to store the lock field struct", "err", err)
|
||||
|
||||
return fmt.Errorf("%w: %v for lock field struct", ErrDBNotResponding, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadLockField(db ethdb.KeyValueReader) (bool, uint64, common.Hash, map[string]struct{}, error) {
|
||||
key := lockFieldKey
|
||||
lockField := LockField{}
|
||||
|
||||
data, err := db.Get(key)
|
||||
if err != nil {
|
||||
return false, 0, common.Hash{}, nil, fmt.Errorf("%w: empty response for lock field", err)
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return false, 0, common.Hash{}, nil, fmt.Errorf("%w for %s", ErrIncorrectLockField, string(key))
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(data, &lockField); err != nil {
|
||||
log.Error(fmt.Sprintf("Unable to unmarshal the lock field in database"), "err", err)
|
||||
|
||||
return false, 0, common.Hash{}, nil, fmt.Errorf("%w(%v) for lock field , data %v(%q)",
|
||||
ErrIncorrectLockField, err, data, string(data))
|
||||
}
|
||||
|
||||
val, block, hash, idList := lockField.Val, lockField.Block, lockField.Hash, lockField.IdList
|
||||
|
||||
return val, block, hash, idList, nil
|
||||
}
|
||||
|
||||
func WriteFutureMilestoneList(db ethdb.KeyValueWriter, order []uint64, list map[uint64]common.Hash) error {
|
||||
|
||||
futureMilestoneField := FutureMilestoneField{
|
||||
Order: order,
|
||||
List: list,
|
||||
}
|
||||
|
||||
key := futureMilestoneKey
|
||||
|
||||
enc, err := json.Marshal(futureMilestoneField)
|
||||
if err != nil {
|
||||
log.Error("Failed to marshal the future milestone field struct", "err", err)
|
||||
|
||||
return fmt.Errorf("%w: %v for future milestone field struct", ErrIncorrectFutureMilestoneFieldToStore, err)
|
||||
}
|
||||
|
||||
if err = db.Put(key, enc); err != nil {
|
||||
log.Error("Failed to store the future milestone field struct", "err", err)
|
||||
|
||||
return fmt.Errorf("%w: %v for future milestone field struct", ErrDBNotResponding, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadFutureMilestoneList(db ethdb.KeyValueReader) ([]uint64, map[uint64]common.Hash, error) {
|
||||
key := futureMilestoneKey
|
||||
futureMilestoneField := FutureMilestoneField{}
|
||||
|
||||
data, err := db.Get(key)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("%w: empty response for future milestone field", err)
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return nil, nil, fmt.Errorf("%w for %s", ErrIncorrectLockField, string(key))
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(data, &futureMilestoneField); err != nil {
|
||||
log.Error(fmt.Sprintf("Unable to unmarshal the future milestone field in database"), "err", err)
|
||||
|
||||
return nil, nil, fmt.Errorf("%w(%v) for future milestone field, data %v(%q)",
|
||||
ErrIncorrectFutureMilestoneField, err, data, string(data))
|
||||
}
|
||||
|
||||
order, list := futureMilestoneField.Order, futureMilestoneField.List
|
||||
|
||||
return order, list, nil
|
||||
}
|
||||
|
|
@ -21,8 +21,11 @@ import (
|
|||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
|
|
@ -273,3 +276,66 @@ func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateKnownAccounts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
knownAccounts := make(types.KnownAccounts)
|
||||
|
||||
types.InsertKnownAccounts(knownAccounts, common.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1"), common.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce"))
|
||||
types.InsertKnownAccounts(knownAccounts, common.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2"), map[common.Hash]common.Hash{
|
||||
common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000aaa"): common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000bbb"),
|
||||
common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ccc"): common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ddd"),
|
||||
})
|
||||
|
||||
stateobjaddr1 := common.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1")
|
||||
stateobjaddr2 := common.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2")
|
||||
|
||||
storageaddr1 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000zzz")
|
||||
storageaddr21 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000aaa")
|
||||
storageaddr22 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ccc")
|
||||
|
||||
data1 := common.BytesToHash([]byte{24})
|
||||
data21 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000bbb")
|
||||
data22 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ddd")
|
||||
|
||||
s := newStateTest()
|
||||
|
||||
// set initial state object value
|
||||
s.state.SetState(stateobjaddr1, storageaddr1, data1)
|
||||
s.state.SetState(stateobjaddr2, storageaddr21, data21)
|
||||
s.state.SetState(stateobjaddr2, storageaddr22, data22)
|
||||
|
||||
require.NoError(t, s.state.ValidateKnownAccounts(knownAccounts))
|
||||
|
||||
types.InsertKnownAccounts(knownAccounts, common.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2"), common.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1cf"))
|
||||
|
||||
stateobjaddr3 := common.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2")
|
||||
storageaddr3 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000yyy")
|
||||
data3 := common.BytesToHash([]byte{24})
|
||||
|
||||
s.state.SetState(stateobjaddr3, storageaddr3, data3)
|
||||
|
||||
// expected error
|
||||
err := s.state.ValidateKnownAccounts(knownAccounts)
|
||||
require.Error(t, err, "should have been an error")
|
||||
|
||||
// correct the previous mistake "0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1cf" -> "0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce"
|
||||
types.InsertKnownAccounts(knownAccounts, common.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add2"), common.HexToHash("0x2d6f8a898e7dec0bb7a50e8c142be32d7c98c096ff68ed57b9b08280d9aca1ce"))
|
||||
types.InsertKnownAccounts(knownAccounts, common.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add3"), map[common.Hash]common.Hash{
|
||||
common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000aaa"): common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000bbb"),
|
||||
common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ccc"): common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ddd"),
|
||||
})
|
||||
|
||||
stateobjaddr4 := common.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add3")
|
||||
storageaddr41 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000aaa")
|
||||
storageaddr42 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000ccc")
|
||||
data4 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000bbb")
|
||||
|
||||
s.state.SetState(stateobjaddr4, storageaddr41, data4)
|
||||
s.state.SetState(stateobjaddr4, storageaddr42, data4)
|
||||
|
||||
// expected error
|
||||
err = s.state.ValidateKnownAccounts(knownAccounts)
|
||||
require.Error(t, err, "should have been an error")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1640,6 +1640,39 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre
|
|||
return s.accessList.Contains(addr, slot)
|
||||
}
|
||||
|
||||
func (s *StateDB) ValidateKnownAccounts(knownAccounts types.KnownAccounts) error {
|
||||
if knownAccounts == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for k, v := range knownAccounts {
|
||||
// check if the value is hex string or an object
|
||||
switch {
|
||||
case v.IsSingle():
|
||||
trie, _ := s.StorageTrie(k)
|
||||
if trie != nil {
|
||||
actualRootHash := trie.Hash()
|
||||
if *v.Single != actualRootHash {
|
||||
return fmt.Errorf("invalid root hash for: %v root hash: %v actual root hash: %v", k, v.Single, actualRootHash)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("Storage Trie is nil for: %v", k)
|
||||
}
|
||||
case v.IsStorage():
|
||||
for slot, value := range v.Storage {
|
||||
actualValue := s.GetState(k, slot)
|
||||
if value != actualValue {
|
||||
return fmt.Errorf("invalid slot value at address: %v slot: %v value: %v actual value: %v", k, slot, value, actualValue)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("impossible to validate known accounts: %v", k)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// convertAccountSet converts a provided account set from address keyed to hash keyed.
|
||||
func (s *StateDB) convertAccountSet(set map[common.Address]struct{}) map[common.Hash]struct{} {
|
||||
ret := make(map[common.Hash]struct{})
|
||||
|
|
|
|||
0
core/triecache/data.0.bin
Normal file
0
core/triecache/data.0.bin
Normal file
BIN
core/triecache/data.1.bin
Normal file
BIN
core/triecache/data.1.bin
Normal file
Binary file not shown.
0
core/triecache/data.2.bin
Normal file
0
core/triecache/data.2.bin
Normal file
BIN
core/triecache/data.3.bin
Normal file
BIN
core/triecache/data.3.bin
Normal file
Binary file not shown.
BIN
core/triecache/data.4.bin
Normal file
BIN
core/triecache/data.4.bin
Normal file
Binary file not shown.
BIN
core/triecache/data.5.bin
Normal file
BIN
core/triecache/data.5.bin
Normal file
Binary file not shown.
0
core/triecache/data.6.bin
Normal file
0
core/triecache/data.6.bin
Normal file
BIN
core/triecache/data.7.bin
Normal file
BIN
core/triecache/data.7.bin
Normal file
Binary file not shown.
BIN
core/triecache/metadata.bin
Normal file
BIN
core/triecache/metadata.bin
Normal file
Binary file not shown.
|
|
@ -29,6 +29,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
cmath "github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
|
@ -165,7 +166,7 @@ func (m *sortedMap) reheap(withRlock bool) {
|
|||
|
||||
if withRlock {
|
||||
m.m.RLock()
|
||||
log.Info("[DEBUG] Acquired lock over txpool map while performing reheap")
|
||||
log.Debug("Acquired lock over txpool map while performing reheap")
|
||||
}
|
||||
|
||||
for nonce := range m.items {
|
||||
|
|
@ -563,6 +564,32 @@ func (l *list) Filter(costLimit *uint256.Int, gasLimit uint64) (types.Transactio
|
|||
return removed, invalids
|
||||
}
|
||||
|
||||
// FilterTxConditional returns the conditional transactions with invalid KnownAccounts
|
||||
// TODO - We will also have to check block range and time stamp range!
|
||||
func (l *list) FilterTxConditional(state *state.StateDB) types.Transactions {
|
||||
removed := l.txs.filter(func(tx *types.Transaction) bool {
|
||||
if options := tx.GetOptions(); options != nil {
|
||||
err := state.ValidateKnownAccounts(options.KnownAccounts)
|
||||
if err != nil {
|
||||
log.Error("Error while Filtering Tx Conditional", "err", err)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
if len(removed) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
l.txs.reheap(true)
|
||||
|
||||
return removed
|
||||
}
|
||||
|
||||
// Cap places a hard limit on the number of items, returning all transactions
|
||||
// exceeding that limit.
|
||||
func (l *list) Cap(threshold int) types.Transactions {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,11 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
|
@ -78,3 +82,63 @@ func BenchmarkListAdd(b *testing.B) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterTxConditional(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create an in memory state db to test against.
|
||||
memDb := rawdb.NewMemoryDatabase()
|
||||
db := state.NewDatabase(memDb)
|
||||
state, _ := state.New(common.Hash{}, db, nil)
|
||||
|
||||
// Create a private key to sign transactions.
|
||||
key, _ := crypto.GenerateKey()
|
||||
|
||||
// Create a list.
|
||||
list := newList(true)
|
||||
|
||||
// Create a transaction with no defined tx options
|
||||
// and add to the list.
|
||||
tx := transaction(0, 1000, key)
|
||||
list.Add(tx, DefaultConfig.PriceBump)
|
||||
|
||||
// There should be no drops at this point.
|
||||
// No state has been modified.
|
||||
drops := list.FilterTxConditional(state)
|
||||
|
||||
count := len(drops)
|
||||
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)
|
||||
|
||||
// Create another transaction with a known account storage root tx option
|
||||
// and add to the list.
|
||||
tx2 := transaction(1, 1000, key)
|
||||
|
||||
var options types.OptionsAA4337
|
||||
|
||||
options.KnownAccounts = types.KnownAccounts{
|
||||
common.Address{19: 1}: &types.Value{
|
||||
Single: common.HexToRefHash("0xe734938daf39aae1fa4ee64dc3155d7c049f28b57a8ada8ad9e86832e0253bef"),
|
||||
},
|
||||
}
|
||||
|
||||
state.SetState(common.Address{19: 1}, common.Hash{}, common.Hash{30: 1})
|
||||
tx2.PutOptions(&options)
|
||||
list.Add(tx2, DefaultConfig.PriceBump)
|
||||
|
||||
// There should still be no drops as no state has been modified.
|
||||
drops = list.FilterTxConditional(state)
|
||||
|
||||
count = len(drops)
|
||||
require.Equal(t, 0, count, "got %d filtered by TxOptions when there should not be any", count)
|
||||
|
||||
// Set state that conflicts with tx2's policy
|
||||
state.SetState(common.Address{19: 1}, common.Hash{}, common.Hash{31: 1})
|
||||
|
||||
// tx2 should be the single transaction filtered out
|
||||
drops = list.FilterTxConditional(state)
|
||||
|
||||
count = len(drops)
|
||||
require.Equal(t, 1, count, "got %d filtered by TxOptions when there should be a single one", count)
|
||||
|
||||
require.Equal(t, tx2, drops[0], "Got %x, expected %x", drops[0].Hash(), tx2.Hash())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -825,6 +825,9 @@ func (pool *TxPool) validateTxBasics(tx *types.Transaction, local bool) error {
|
|||
// return core.ErrInsufficientFunds
|
||||
// }
|
||||
// Verify that replacing transactions will not result in overdraft
|
||||
pool.pendingMu.RLock()
|
||||
defer pool.pendingMu.RUnlock()
|
||||
|
||||
list := pool.pending[from]
|
||||
if list != nil { // Sender already has pending txs
|
||||
sum := new(big.Int).Add(tx.Cost(), list.totalcost)
|
||||
|
|
@ -2303,10 +2306,19 @@ func (pool *TxPool) demoteUnexecutables() {
|
|||
pool.enqueueTx(hash, tx, false, false)
|
||||
}
|
||||
|
||||
pendingGauge.Dec(int64(oldsLen + dropsLen + invalidsLen))
|
||||
// Drop all transactions that no longer have valid TxOptions
|
||||
txConditionalsRemoved := list.FilterTxConditional(pool.currentState)
|
||||
|
||||
for _, tx := range txConditionalsRemoved {
|
||||
hash := tx.Hash()
|
||||
pool.all.Remove(hash)
|
||||
log.Trace("Removed invalid conditional transaction", "hash", hash)
|
||||
}
|
||||
|
||||
pendingGauge.Dec(int64(oldsLen + dropsLen + invalidsLen + len(txConditionalsRemoved)))
|
||||
|
||||
if pool.locals.contains(addr) {
|
||||
localGauge.Dec(int64(oldsLen + dropsLen + invalidsLen))
|
||||
localGauge.Dec(int64(oldsLen + dropsLen + invalidsLen + len(txConditionalsRemoved)))
|
||||
}
|
||||
// If there's a gap in front, alert (should never happen) and postpone all transactions
|
||||
if list.Len() > 0 && list.txs.Get(nonce) == nil {
|
||||
|
|
|
|||
|
|
@ -1993,6 +1993,7 @@ func TestUnderpricing(t *testing.T) {
|
|||
keys[i], _ = crypto.GenerateKey()
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
}
|
||||
|
||||
// Generate and queue a batch of transactions, both pending and queued
|
||||
txs := types.Transactions{}
|
||||
|
||||
|
|
@ -2023,6 +2024,7 @@ func TestUnderpricing(t *testing.T) {
|
|||
if err := validatePoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
|
||||
// Ensure that adding an underpriced transaction on block limit fails
|
||||
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); !errors.Is(err, ErrUnderpriced) {
|
||||
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||
|
|
@ -2064,6 +2066,7 @@ func TestUnderpricing(t *testing.T) {
|
|||
if err := validatePoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
|
||||
// Ensure that adding local transactions can push out even higher priced ones
|
||||
ltx = pricedTransaction(1, 100000, big.NewInt(0), keys[2])
|
||||
if err := pool.AddLocal(ltx); err != nil {
|
||||
|
|
@ -2263,6 +2266,7 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
|||
if err := validatePoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
|
||||
// Ensure that adding local transactions can push out even higher priced ones
|
||||
ltx = dynamicFeeTx(1, 100000, big.NewInt(0), big.NewInt(0), keys[2])
|
||||
if err := pool.AddLocal(ltx); err != nil {
|
||||
|
|
|
|||
|
|
@ -188,6 +188,44 @@ func (h *Header) EmptyReceipts() bool {
|
|||
return h.ReceiptHash == EmptyReceiptsHash
|
||||
}
|
||||
|
||||
// ValidateBlockNumberOptions4337 validates the block range passed as in the options parameter in the conditional transaction (EIP-4337)
|
||||
func (h *Header) ValidateBlockNumberOptions4337(minBlockNumber *big.Int, maxBlockNumber *big.Int) error {
|
||||
currentBlockNumber := h.Number
|
||||
|
||||
if minBlockNumber != nil {
|
||||
if currentBlockNumber.Cmp(minBlockNumber) == -1 {
|
||||
return fmt.Errorf("current block number %v is less than minimum block number: %v", currentBlockNumber, minBlockNumber)
|
||||
}
|
||||
}
|
||||
|
||||
if maxBlockNumber != nil {
|
||||
if currentBlockNumber.Cmp(maxBlockNumber) == 1 {
|
||||
return fmt.Errorf("current block number %v is greater than maximum block number: %v", currentBlockNumber, maxBlockNumber)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateBlockNumberOptions4337 validates the timestamp range passed as in the options parameter in the conditional transaction (EIP-4337)
|
||||
func (h *Header) ValidateTimestampOptions4337(minTimestamp *uint64, maxTimestamp *uint64) error {
|
||||
currentBlockTime := h.Time
|
||||
|
||||
if minTimestamp != nil {
|
||||
if currentBlockTime < *minTimestamp {
|
||||
return fmt.Errorf("current block time %v is less than minimum timestamp: %v", currentBlockTime, minTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
if maxTimestamp != nil {
|
||||
if currentBlockTime > *maxTimestamp {
|
||||
return fmt.Errorf("current block time %v is greater than maximum timestamp: %v", currentBlockTime, maxTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Body is a simple (mutable, non-safe) data container for storing and moving
|
||||
// a block's data contents (transactions and uncles) together.
|
||||
type Body struct {
|
||||
|
|
|
|||
|
|
@ -463,3 +463,167 @@ func TestRlpDecodeParentHash(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateBlockNumberOptions4337(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testsPass := []struct {
|
||||
number string
|
||||
header Header
|
||||
minBlockNumber *big.Int
|
||||
maxBlockNumber *big.Int
|
||||
}{
|
||||
{
|
||||
"1",
|
||||
Header{Number: big.NewInt(10)},
|
||||
big.NewInt(0),
|
||||
big.NewInt(20),
|
||||
},
|
||||
{
|
||||
"2",
|
||||
Header{Number: big.NewInt(10)},
|
||||
big.NewInt(10),
|
||||
big.NewInt(10),
|
||||
},
|
||||
{
|
||||
"3",
|
||||
Header{Number: big.NewInt(10)},
|
||||
big.NewInt(10),
|
||||
big.NewInt(11),
|
||||
},
|
||||
{
|
||||
"4",
|
||||
Header{Number: big.NewInt(10)},
|
||||
big.NewInt(0),
|
||||
big.NewInt(10),
|
||||
},
|
||||
}
|
||||
|
||||
testsFail := []struct {
|
||||
number string
|
||||
header Header
|
||||
minBlockNumber *big.Int
|
||||
maxBlockNumber *big.Int
|
||||
}{
|
||||
{
|
||||
"5",
|
||||
Header{Number: big.NewInt(10)},
|
||||
big.NewInt(0),
|
||||
big.NewInt(0),
|
||||
},
|
||||
{
|
||||
"6",
|
||||
Header{Number: big.NewInt(10)},
|
||||
big.NewInt(0),
|
||||
big.NewInt(9),
|
||||
},
|
||||
{
|
||||
"7",
|
||||
Header{Number: big.NewInt(10)},
|
||||
big.NewInt(11),
|
||||
big.NewInt(9),
|
||||
},
|
||||
{
|
||||
"8",
|
||||
Header{Number: big.NewInt(10)},
|
||||
big.NewInt(11),
|
||||
big.NewInt(20),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testsPass {
|
||||
if err := test.header.ValidateBlockNumberOptions4337(test.minBlockNumber, test.maxBlockNumber); err != nil {
|
||||
t.Fatalf("test number %v should not have failed. err: %v", test.number, err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, test := range testsFail {
|
||||
if err := test.header.ValidateBlockNumberOptions4337(test.minBlockNumber, test.maxBlockNumber); err == nil {
|
||||
t.Fatalf("test number %v should have failed. err is nil", test.number)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateTimestampOptions4337(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u64Ptr := func(n uint64) *uint64 {
|
||||
return &n
|
||||
}
|
||||
|
||||
testsPass := []struct {
|
||||
number string
|
||||
header Header
|
||||
minTimestamp *uint64
|
||||
maxTimestamp *uint64
|
||||
}{
|
||||
{
|
||||
"1",
|
||||
Header{Time: 1600000000},
|
||||
u64Ptr(1500000000),
|
||||
u64Ptr(1700000000),
|
||||
},
|
||||
{
|
||||
"2",
|
||||
Header{Time: 1600000000},
|
||||
u64Ptr(1600000000),
|
||||
u64Ptr(1600000000),
|
||||
},
|
||||
{
|
||||
"3",
|
||||
Header{Time: 1600000000},
|
||||
u64Ptr(1600000000),
|
||||
u64Ptr(1700000000),
|
||||
},
|
||||
{
|
||||
"4",
|
||||
Header{Time: 1600000000},
|
||||
u64Ptr(1500000000),
|
||||
u64Ptr(1600000000),
|
||||
},
|
||||
}
|
||||
|
||||
testsFail := []struct {
|
||||
number string
|
||||
header Header
|
||||
minTimestamp *uint64
|
||||
maxTimestamp *uint64
|
||||
}{
|
||||
{
|
||||
"5",
|
||||
Header{Time: 1600000000},
|
||||
u64Ptr(1500000000),
|
||||
u64Ptr(1500000000),
|
||||
},
|
||||
{
|
||||
"6",
|
||||
Header{Time: 1600000000},
|
||||
u64Ptr(1400000000),
|
||||
u64Ptr(1500000000),
|
||||
},
|
||||
{
|
||||
"7",
|
||||
Header{Time: 1600000000},
|
||||
u64Ptr(1700000000),
|
||||
u64Ptr(1500000000),
|
||||
},
|
||||
{
|
||||
"8",
|
||||
Header{Time: 1600000000},
|
||||
u64Ptr(1700000000),
|
||||
u64Ptr(1800000000),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testsPass {
|
||||
if err := test.header.ValidateTimestampOptions4337(test.minTimestamp, test.maxTimestamp); err != nil {
|
||||
t.Fatalf("test number %v should not have failed. err: %v", test.number, err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, test := range testsFail {
|
||||
if err := test.header.ValidateTimestampOptions4337(test.minTimestamp, test.maxTimestamp); err == nil {
|
||||
t.Fatalf("test number %v should have failed. err is nil", test.number)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
|
|||
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
|
||||
ContractAddress common.Address `json:"contractAddress"`
|
||||
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||
EffectiveGasPrice *big.Int `json:"effectiveGasPrice"`
|
||||
EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice"`
|
||||
BlockHash common.Hash `json:"blockHash,omitempty"`
|
||||
BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
|
||||
TransactionIndex hexutil.Uint `json:"transactionIndex"`
|
||||
|
|
@ -40,7 +40,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
|
|||
enc.TxHash = r.TxHash
|
||||
enc.ContractAddress = r.ContractAddress
|
||||
enc.GasUsed = hexutil.Uint64(r.GasUsed)
|
||||
enc.EffectiveGasPrice = r.EffectiveGasPrice
|
||||
enc.EffectiveGasPrice = (*hexutil.Big)(r.EffectiveGasPrice)
|
||||
enc.BlockHash = r.BlockHash
|
||||
enc.BlockNumber = (*hexutil.Big)(r.BlockNumber)
|
||||
enc.TransactionIndex = hexutil.Uint(r.TransactionIndex)
|
||||
|
|
@ -59,7 +59,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
|||
TxHash *common.Hash `json:"transactionHash" gencodec:"required"`
|
||||
ContractAddress *common.Address `json:"contractAddress"`
|
||||
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||
EffectiveGasPrice *big.Int `json:"effectiveGasPrice"`
|
||||
EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice"`
|
||||
BlockHash *common.Hash `json:"blockHash,omitempty"`
|
||||
BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
|
||||
TransactionIndex *hexutil.Uint `json:"transactionIndex"`
|
||||
|
|
@ -101,7 +101,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
|||
}
|
||||
r.GasUsed = uint64(*dec.GasUsed)
|
||||
if dec.EffectiveGasPrice != nil {
|
||||
r.EffectiveGasPrice = dec.EffectiveGasPrice
|
||||
r.EffectiveGasPrice = (*big.Int)(dec.EffectiveGasPrice)
|
||||
}
|
||||
if dec.BlockHash != nil {
|
||||
r.BlockHash = *dec.BlockHash
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ type receiptMarshaling struct {
|
|||
PostState hexutil.Bytes
|
||||
Status hexutil.Uint64
|
||||
CumulativeGasUsed hexutil.Uint64
|
||||
EffectiveGasPrice *hexutil.Big
|
||||
GasUsed hexutil.Uint64
|
||||
BlockNumber *hexutil.Big
|
||||
TransactionIndex hexutil.Uint
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ type Transaction struct {
|
|||
inner TxData // Consensus contents of a transaction
|
||||
time time.Time // Time first seen locally (spam avoidance)
|
||||
|
||||
// knownAccounts (EIP-4337)
|
||||
optionsAA4337 *OptionsAA4337
|
||||
|
||||
// caches
|
||||
hash atomic.Pointer[common.Hash]
|
||||
size atomic.Pointer[uint64]
|
||||
|
|
@ -101,6 +104,16 @@ type TxData interface {
|
|||
effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int
|
||||
}
|
||||
|
||||
// PutOptions stores the optionsAA4337 field of the conditional transaction (EIP-4337)
|
||||
func (tx *Transaction) PutOptions(options *OptionsAA4337) {
|
||||
tx.optionsAA4337 = options
|
||||
}
|
||||
|
||||
// GetOptions returns the optionsAA4337 field of the conditional transaction (EIP-4337)
|
||||
func (tx *Transaction) GetOptions() *OptionsAA4337 {
|
||||
return tx.optionsAA4337
|
||||
}
|
||||
|
||||
// EncodeRLP implements rlp.Encoder
|
||||
func (tx *Transaction) EncodeRLP(w io.Writer) error {
|
||||
if tx.Type() == LegacyTxType {
|
||||
|
|
|
|||
146
core/types/transaction_conditional.go
Normal file
146
core/types/transaction_conditional.go
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
|
||||
type KnownAccounts map[common.Address]*Value
|
||||
|
||||
type Value struct {
|
||||
Single *common.Hash
|
||||
Storage map[common.Hash]common.Hash
|
||||
}
|
||||
|
||||
func SingleFromHex(hex string) *Value {
|
||||
return &Value{Single: common.HexToRefHash(hex)}
|
||||
}
|
||||
|
||||
func FromMap(m map[string]string) *Value {
|
||||
res := map[common.Hash]common.Hash{}
|
||||
|
||||
for k, v := range m {
|
||||
res[common.HexToHash(k)] = common.HexToHash(v)
|
||||
}
|
||||
|
||||
return &Value{Storage: res}
|
||||
}
|
||||
|
||||
func (v *Value) IsSingle() bool {
|
||||
return v != nil && v.Single != nil && !v.IsStorage()
|
||||
}
|
||||
|
||||
func (v *Value) IsStorage() bool {
|
||||
return v != nil && v.Storage != nil
|
||||
}
|
||||
|
||||
const EmptyValue = "{}"
|
||||
|
||||
func (v *Value) MarshalJSON() ([]byte, error) {
|
||||
if v.IsSingle() {
|
||||
return json.Marshal(v.Single)
|
||||
}
|
||||
|
||||
if v.IsStorage() {
|
||||
return json.Marshal(v.Storage)
|
||||
}
|
||||
|
||||
return []byte(EmptyValue), nil
|
||||
}
|
||||
|
||||
const hashTypeName = "Hash"
|
||||
|
||||
func (v *Value) UnmarshalJSON(data []byte) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var m map[string]json.RawMessage
|
||||
|
||||
err := json.Unmarshal(data, &m)
|
||||
if err != nil {
|
||||
// single Hash value case
|
||||
v.Single = new(common.Hash)
|
||||
|
||||
innerErr := json.Unmarshal(data, v.Single)
|
||||
if innerErr != nil {
|
||||
return fmt.Errorf("can't unmarshal to single value with error: %v value %q", innerErr, string(data))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make(map[common.Hash]common.Hash, len(m))
|
||||
|
||||
for k, v := range m {
|
||||
// check k if it is a Hex value
|
||||
var kHash common.Hash
|
||||
|
||||
err = hexutil.UnmarshalFixedText(hashTypeName, []byte(k), kHash[:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w by key: %s with key %q and value %q", ErrKnownAccounts, err, k, string(v))
|
||||
}
|
||||
|
||||
// check v if it is a Hex value
|
||||
var vHash common.Hash
|
||||
|
||||
err = hexutil.UnmarshalFixedText("hashTypeName", bytes.Trim(v, "\""), vHash[:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w by value: %s with key %q and value %q", ErrKnownAccounts, err, k, string(v))
|
||||
}
|
||||
|
||||
res[kHash] = vHash
|
||||
}
|
||||
|
||||
v.Storage = res
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func InsertKnownAccounts[T common.Hash | map[common.Hash]common.Hash](accounts KnownAccounts, k common.Address, v T) {
|
||||
switch typedV := any(v).(type) {
|
||||
case common.Hash:
|
||||
accounts[k] = &Value{Single: &typedV}
|
||||
case map[common.Hash]common.Hash:
|
||||
accounts[k] = &Value{Storage: typedV}
|
||||
}
|
||||
}
|
||||
|
||||
type OptionsAA4337 struct {
|
||||
KnownAccounts KnownAccounts `json:"knownAccounts"`
|
||||
BlockNumberMin *big.Int `json:"blockNumberMin"`
|
||||
BlockNumberMax *big.Int `json:"blockNumberMax"`
|
||||
TimestampMin *uint64 `json:"timestampMin"`
|
||||
TimestampMax *uint64 `json:"timestampMax"`
|
||||
}
|
||||
|
||||
var ErrKnownAccounts = errors.New("an incorrect list of knownAccounts")
|
||||
|
||||
func (ka KnownAccounts) ValidateLength() error {
|
||||
if ka == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
length := 0
|
||||
|
||||
for _, v := range ka {
|
||||
// check if the value is hex string or an object
|
||||
if v.IsSingle() {
|
||||
length += 1
|
||||
} else {
|
||||
length += len(v.Storage)
|
||||
}
|
||||
}
|
||||
|
||||
if length >= 1000 {
|
||||
return fmt.Errorf("number of slots/accounts in KnownAccounts %v exceeds the limit of 1000", length)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
31
core/types/transaction_conditional_test.go
Normal file
31
core/types/transaction_conditional_test.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
func TestKnownAccounts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
requestRaw := []byte(`{"0xadd1add1add1add1add1add1add1add1add1add1": "0x000000000000000000000000313aadca1750caadc7bcb26ff08175c95dcf8e38", "0xadd2add2add2add2add2add2add2add2add2add2": {"0x0000000000000000000000000000000000000000000000000000000000000aaa": "0x0000000000000000000000000000000000000000000000000000000000000bbb", "0x0000000000000000000000000000000000000000000000000000000000000ccc": "0x0000000000000000000000000000000000000000000000000000000000000ddd"}}`)
|
||||
|
||||
accs := &KnownAccounts{}
|
||||
|
||||
err := json.Unmarshal(requestRaw, accs)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := &KnownAccounts{
|
||||
common.HexToAddress("0xadd1add1add1add1add1add1add1add1add1add1"): SingleFromHex("0x000000000000000000000000313aadca1750caadc7bcb26ff08175c95dcf8e38"),
|
||||
common.HexToAddress("0xadd2add2add2add2add2add2add2add2add2add2"): FromMap(map[string]string{
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000aaa": "0x0000000000000000000000000000000000000000000000000000000000000bbb",
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000ccc": "0x0000000000000000000000000000000000000000000000000000000000000ddd",
|
||||
}),
|
||||
}
|
||||
|
||||
require.Equal(t, expected, accs)
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ verbosity = 3 # Logging verbosity for the server (5=trace|4=de
|
|||
vmdebug = false # Record information useful for VM and contract debugging
|
||||
datadir = "var/lib/bor" # Path of the data directory to store information
|
||||
ancient = "" # Data directory for ancient chain segments (default = inside chaindata)
|
||||
db.engine = "leveldb" # Used to select leveldb or pebble as database (default = leveldb)
|
||||
keystore = "" # Path of the directory where keystores are located
|
||||
"rpc.batchlimit" = 100 # Maximum number of messages in a batch (default=100, use 0 for no limits)
|
||||
"rpc.returndatalimit" = 100000 # Maximum size (in bytes) a result of an rpc request could have (default=100000, use 0 for no limits)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ The ```bor server``` command runs the Bor client.
|
|||
|
||||
- ```datadir.ancient```: Data directory for ancient chain segments (default = inside chaindata)
|
||||
|
||||
- ```db.engine```: Backing database implementation to use ('leveldb' or 'pebble') (default: leveldb)
|
||||
|
||||
- ```keystore```: Path of the directory where keystores are located
|
||||
|
||||
- ```rpc.batchlimit```: Maximum number of messages in a batch (default=100, use 0 for no limits) (default: 100)
|
||||
|
|
@ -124,6 +126,16 @@ The ```bor server``` command runs the Bor client.
|
|||
|
||||
- ```fdlimit```: Raise the open file descriptor resource limit (default = system fd limit) (default: 0)
|
||||
|
||||
### ExtraDB Options
|
||||
|
||||
- ```leveldb.compaction.table.size```: LevelDB SSTable/file size in mebibytes (default: 2)
|
||||
|
||||
- ```leveldb.compaction.table.size.multiplier```: Multiplier on LevelDB SSTable/file size. Size for a level is determined by: `leveldb.compaction.table.size * (leveldb.compaction.table.size.multiplier ^ Level)` (default: 1)
|
||||
|
||||
- ```leveldb.compaction.total.size```: Total size in mebibytes of SSTables in a given LevelDB level. Size for a level is determined by: `leveldb.compaction.total.size * (leveldb.compaction.total.size.multiplier ^ Level)` (default: 10)
|
||||
|
||||
- ```leveldb.compaction.total.size.multiplier```: Multiplier on level size on LevelDB levels. Size for a level is determined by: `leveldb.compaction.total.size * (leveldb.compaction.total.size.multiplier ^ Level)` (default: 10)
|
||||
|
||||
### JsonRPC Options
|
||||
|
||||
- ```rpc.gascap```: Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite) (default: 50000000)
|
||||
|
|
|
|||
49
eth/api.go
49
eth/api.go
|
|
@ -280,11 +280,22 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
|
|||
return stateDb.RawDump(opts), nil
|
||||
}
|
||||
|
||||
// TODO - Check this
|
||||
var header *types.Header
|
||||
if blockNr == rpc.LatestBlockNumber {
|
||||
header = api.eth.blockchain.CurrentBlock()
|
||||
} else if blockNr == rpc.FinalizedBlockNumber {
|
||||
header = api.eth.blockchain.CurrentFinalBlock()
|
||||
finalBlockNumber, err := getFinalizedBlockNumber(api.eth)
|
||||
if err != nil {
|
||||
return state.Dump{}, fmt.Errorf("finalized block not found")
|
||||
}
|
||||
|
||||
block := api.eth.blockchain.CurrentFinalizedBlock(finalBlockNumber)
|
||||
if block == nil {
|
||||
return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
|
||||
}
|
||||
|
||||
header = block.Header()
|
||||
} else if blockNr == rpc.SafeBlockNumber {
|
||||
header = api.eth.blockchain.CurrentSafeBlock()
|
||||
} else {
|
||||
|
|
@ -379,7 +390,17 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
|
|||
if number == rpc.LatestBlockNumber {
|
||||
header = api.eth.blockchain.CurrentBlock()
|
||||
} else if number == rpc.FinalizedBlockNumber {
|
||||
header = api.eth.blockchain.CurrentFinalBlock()
|
||||
finalBlockNumber, err := getFinalizedBlockNumber(api.eth)
|
||||
if err != nil {
|
||||
return state.IteratorDump{}, fmt.Errorf("finalized block not found")
|
||||
}
|
||||
|
||||
block := api.eth.blockchain.CurrentFinalizedBlock(finalBlockNumber)
|
||||
if block == nil {
|
||||
return state.IteratorDump{}, fmt.Errorf("finalized block not found")
|
||||
}
|
||||
|
||||
header = block.Header()
|
||||
} else if number == rpc.SafeBlockNumber {
|
||||
header = api.eth.blockchain.CurrentSafeBlock()
|
||||
} else {
|
||||
|
|
@ -678,3 +699,27 @@ func (api *DebugAPI) SetTrieFlushInterval(interval string) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getFinalizedBlockNumber(eth *Ethereum) (uint64, error) {
|
||||
currentBlockNum := eth.BlockChain().CurrentBlock()
|
||||
|
||||
doExist, number, hash := eth.Downloader().GetWhitelistedMilestone()
|
||||
if doExist && number <= currentBlockNum.Number.Uint64() {
|
||||
block := eth.BlockChain().GetBlockByNumber(number)
|
||||
|
||||
if block.Hash() == hash {
|
||||
return number, nil
|
||||
}
|
||||
}
|
||||
|
||||
doExist, number, hash = eth.Downloader().GetWhitelistedCheckpoint()
|
||||
if doExist && number <= currentBlockNum.Number.Uint64() {
|
||||
block := eth.BlockChain().GetBlockByNumber(number)
|
||||
|
||||
if block.Hash() == hash {
|
||||
return number, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("No finalized block")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,14 +76,15 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
|
|||
}
|
||||
|
||||
if number == rpc.FinalizedBlockNumber {
|
||||
if !b.eth.Merger().TDDReached() {
|
||||
return nil, errors.New("'finalized' tag not supported on pre-merge network")
|
||||
finalBlockNumber, err := getFinalizedBlockNumber(b.eth)
|
||||
if err != nil {
|
||||
return nil, errors.New("finalized block not found")
|
||||
}
|
||||
|
||||
block := b.eth.blockchain.CurrentFinalBlock()
|
||||
block := b.eth.blockchain.CurrentFinalizedBlock(finalBlockNumber)
|
||||
|
||||
if block != nil {
|
||||
return block, nil
|
||||
return block.Header(), nil
|
||||
}
|
||||
|
||||
return nil, errors.New("finalized block not found")
|
||||
|
|
@ -144,13 +145,12 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
|
|||
}
|
||||
|
||||
if number == rpc.FinalizedBlockNumber {
|
||||
if !b.eth.Merger().TDDReached() {
|
||||
return nil, errors.New("'finalized' tag not supported on pre-merge network")
|
||||
finalBlocknumber, err := getFinalizedBlockNumber(b.eth)
|
||||
if err != nil {
|
||||
return nil, errors.New("finalized block not found")
|
||||
}
|
||||
|
||||
header := b.eth.blockchain.CurrentFinalBlock()
|
||||
|
||||
return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil
|
||||
return b.eth.blockchain.CurrentFinalizedBlock(finalBlocknumber), nil
|
||||
}
|
||||
|
||||
if number == rpc.SafeBlockNumber {
|
||||
|
|
@ -313,6 +313,10 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri
|
|||
}
|
||||
|
||||
func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
||||
if signedTx.GetOptions() != nil && !b.eth.Miner().GetWorker().IsRunning() {
|
||||
return errors.New("bundled transactions are not broadcasted therefore they will not submitted to the transaction pool")
|
||||
}
|
||||
|
||||
err := b.eth.txPool.AddLocal(signedTx)
|
||||
if err != nil {
|
||||
if unwrapped := errors.Unwrap(err); unwrapped != nil {
|
||||
|
|
@ -451,10 +455,18 @@ func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Blo
|
|||
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) GetCheckpointWhitelist() map[uint64]common.Hash {
|
||||
return b.eth.Downloader().ChainValidator.GetCheckpointWhitelist()
|
||||
func (b *EthAPIBackend) GetWhitelistedCheckpoint() (bool, uint64, common.Hash) {
|
||||
return b.eth.Downloader().ChainValidator.GetWhitelistedCheckpoint()
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) PurgeCheckpointWhitelist() {
|
||||
b.eth.Downloader().ChainValidator.PurgeCheckpointWhitelist()
|
||||
func (b *EthAPIBackend) PurgeWhitelistedCheckpoint() {
|
||||
b.eth.Downloader().ChainValidator.PurgeWhitelistedCheckpoint()
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) GetWhitelistedMilestone() (bool, uint64, common.Hash) {
|
||||
return b.eth.Downloader().ChainValidator.GetWhitelistedMilestone()
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) PurgeWhitelistedMilestone() {
|
||||
b.eth.Downloader().ChainValidator.PurgeWhitelistedMilestone()
|
||||
}
|
||||
|
|
|
|||
191
eth/backend.go
191
eth/backend.go
|
|
@ -141,7 +141,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
|
||||
|
||||
// Assemble the Ethereum object
|
||||
chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "ethereum/db/chaindata/", false)
|
||||
extraDBConfig := resolveExtraDBConfig(config)
|
||||
chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "ethereum/db/chaindata/", false, extraDBConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -246,7 +247,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
}
|
||||
)
|
||||
|
||||
checker := whitelist.NewService(10)
|
||||
checker := whitelist.NewService(chainDb)
|
||||
|
||||
// check if Parallel EVM is enabled
|
||||
// if enabled, use parallel state processor
|
||||
|
|
@ -332,6 +333,15 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
return ethereum, nil
|
||||
}
|
||||
|
||||
func resolveExtraDBConfig(config *ethconfig.Config) rawdb.ExtraDBConfig {
|
||||
return rawdb.ExtraDBConfig{
|
||||
LevelDBCompactionTableSize: config.LevelDbCompactionTableSize,
|
||||
LevelDBCompactionTableSizeMultiplier: config.LevelDbCompactionTableSizeMultiplier,
|
||||
LevelDBCompactionTotalSize: config.LevelDbCompactionTotalSize,
|
||||
LevelDBCompactionTotalSizeMultiplier: config.LevelDbCompactionTotalSizeMultiplier,
|
||||
}
|
||||
}
|
||||
|
||||
func makeExtraData(extra []byte) []byte {
|
||||
if len(extra) == 0 {
|
||||
// create default extradata
|
||||
|
|
@ -351,6 +361,11 @@ func makeExtraData(extra []byte) []byte {
|
|||
return extra
|
||||
}
|
||||
|
||||
// PeerCount returns the number of connected peers.
|
||||
func (s *Ethereum) PeerCount() int {
|
||||
return s.p2pServer.PeerCount()
|
||||
}
|
||||
|
||||
// APIs return the collection of RPC services the ethereum package offers.
|
||||
// NOTE, some of these services probably need to be moved to somewhere else.
|
||||
func (s *Ethereum) APIs() []rpc.API {
|
||||
|
|
@ -565,7 +580,8 @@ func (s *Ethereum) StopMining() {
|
|||
th.SetThreads(-1)
|
||||
}
|
||||
// Stop the block creating itself
|
||||
s.miner.Stop()
|
||||
ch := make(chan struct{})
|
||||
s.miner.Stop(ch)
|
||||
}
|
||||
|
||||
func (s *Ethereum) IsMining() bool { return s.miner.Mining() }
|
||||
|
|
@ -634,6 +650,9 @@ func (s *Ethereum) Start() error {
|
|||
s.handler.Start(maxPeers)
|
||||
|
||||
go s.startCheckpointWhitelistService()
|
||||
go s.startMilestoneWhitelistService()
|
||||
go s.startNoAckMilestoneService()
|
||||
go s.startNoAckMilestoneByIDService()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -641,83 +660,183 @@ func (s *Ethereum) Start() error {
|
|||
var (
|
||||
ErrNotBorConsensus = errors.New("not bor consensus was given")
|
||||
ErrBorConsensusWithoutHeimdall = errors.New("bor consensus without heimdall")
|
||||
)
|
||||
|
||||
const (
|
||||
whitelistTimeout = 30 * time.Second
|
||||
noAckMilestoneTimeout = 4 * time.Second
|
||||
)
|
||||
|
||||
// StartCheckpointWhitelistService starts the goroutine to fetch checkpoints and update the
|
||||
// checkpoint whitelist map.
|
||||
func (s *Ethereum) startCheckpointWhitelistService() {
|
||||
const (
|
||||
tickerDuration = 100 * time.Second
|
||||
fnName = "whitelist checkpoint"
|
||||
)
|
||||
|
||||
s.retryHeimdallHandler(s.handleWhitelistCheckpoint, tickerDuration, whitelistTimeout, fnName)
|
||||
}
|
||||
|
||||
// startMilestoneWhitelistService starts the goroutine to fetch milestiones and update the
|
||||
// milestone whitelist map.
|
||||
func (s *Ethereum) startMilestoneWhitelistService() {
|
||||
const (
|
||||
tickerDuration = 12 * time.Second
|
||||
fnName = "whitelist milestone"
|
||||
)
|
||||
|
||||
s.retryHeimdallHandler(s.handleMilestone, tickerDuration, whitelistTimeout, fnName)
|
||||
}
|
||||
|
||||
func (s *Ethereum) startNoAckMilestoneService() {
|
||||
const (
|
||||
tickerDuration = 6 * time.Second
|
||||
fnName = "no-ack-milestone service"
|
||||
)
|
||||
|
||||
s.retryHeimdallHandler(s.handleNoAckMilestone, tickerDuration, noAckMilestoneTimeout, fnName)
|
||||
}
|
||||
|
||||
func (s *Ethereum) startNoAckMilestoneByIDService() {
|
||||
const (
|
||||
tickerDuration = 1 * time.Minute
|
||||
fnName = "no-ack-milestone-by-id service"
|
||||
)
|
||||
|
||||
s.retryHeimdallHandler(s.handleNoAckMilestoneByID, tickerDuration, noAckMilestoneTimeout, fnName)
|
||||
}
|
||||
|
||||
func (s *Ethereum) retryHeimdallHandler(fn heimdallHandler, tickerDuration time.Duration, timeout time.Duration, fnName string) {
|
||||
retryHeimdallHandler(fn, tickerDuration, timeout, fnName, s.closeCh, s.getHandler)
|
||||
}
|
||||
|
||||
func retryHeimdallHandler(fn heimdallHandler, tickerDuration time.Duration, timeout time.Duration, fnName string, closeCh chan struct{}, getHandler func() (*ethHandler, *bor.Bor, error)) {
|
||||
// a shortcut helps with tests and early exit
|
||||
select {
|
||||
case <-s.closeCh:
|
||||
case <-closeCh:
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
// first run the checkpoint whitelist
|
||||
firstCtx, cancel := context.WithTimeout(context.Background(), whitelistTimeout)
|
||||
err := s.handleWhitelistCheckpoint(firstCtx, true)
|
||||
ethHandler, bor, err := getHandler()
|
||||
if err != nil {
|
||||
log.Error("error while getting the ethHandler", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
// first run for fetching milestones
|
||||
firstCtx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
err = fn(firstCtx, ethHandler, bor)
|
||||
|
||||
cancel()
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrBorConsensusWithoutHeimdall) || errors.Is(err, ErrNotBorConsensus) {
|
||||
return
|
||||
log.Warn(fmt.Sprintf("unable to start the %s service - first run", fnName), "err", err)
|
||||
}
|
||||
|
||||
log.Warn("unable to whitelist checkpoint - first run", "err", err)
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(100 * time.Second)
|
||||
ticker := time.NewTicker(tickerDuration)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
ctx, cancel := context.WithTimeout(context.Background(), whitelistTimeout)
|
||||
err := s.handleWhitelistCheckpoint(ctx, false)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
err := fn(ctx, ethHandler, bor)
|
||||
|
||||
cancel()
|
||||
|
||||
if err != nil {
|
||||
log.Warn("unable to whitelist checkpoint", "err", err)
|
||||
log.Warn(fmt.Sprintf("unable to handle %s", fnName), "err", err)
|
||||
}
|
||||
case <-s.closeCh:
|
||||
case <-closeCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleWhitelistCheckpoint handles the checkpoint whitelist mechanism.
|
||||
func (s *Ethereum) handleWhitelistCheckpoint(ctx context.Context, first bool) error {
|
||||
func (s *Ethereum) handleWhitelistCheckpoint(ctx context.Context, ethHandler *ethHandler, bor *bor.Bor) error {
|
||||
// Create a new bor verifier, which will be used to verify checkpoints and milestones
|
||||
verifier := newBorVerifier()
|
||||
|
||||
blockNum, blockHash, err := ethHandler.fetchWhitelistCheckpoint(ctx, bor, s, verifier)
|
||||
// If the array is empty, we're bound to receive an error. Non-nill error and non-empty array
|
||||
// means that array has partial elements and it failed for some block. We'll add those partial
|
||||
// elements anyway.
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ethHandler.downloader.ProcessCheckpoint(blockNum, blockHash)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type heimdallHandler func(ctx context.Context, ethHandler *ethHandler, bor *bor.Bor) error
|
||||
|
||||
// handleMilestone handles the milestone mechanism.
|
||||
func (s *Ethereum) handleMilestone(ctx context.Context, ethHandler *ethHandler, bor *bor.Bor) error {
|
||||
// Create a new bor verifier, which will be used to verify checkpoints and milestones
|
||||
verifier := newBorVerifier()
|
||||
num, hash, err := ethHandler.fetchWhitelistMilestone(ctx, bor, s, verifier)
|
||||
|
||||
// If the current chain head is behind the received milestone, add it to the future milestone
|
||||
// list. Also, the hash mismatch (end block hash) error will lead to rewind so also
|
||||
// add that milestone to the future milestone list.
|
||||
if errors.Is(err, errMissingBlocks) || errors.Is(err, errHashMismatch) {
|
||||
ethHandler.downloader.ProcessFutureMilestone(num, hash)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ethHandler.downloader.ProcessMilestone(num, hash)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Ethereum) handleNoAckMilestone(ctx context.Context, ethHandler *ethHandler, bor *bor.Bor) error {
|
||||
milestoneID, err := ethHandler.fetchNoAckMilestone(ctx, bor)
|
||||
|
||||
//If failed to fetch the no-ack milestone then it give the error.
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ethHandler.downloader.RemoveMilestoneID(milestoneID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Ethereum) handleNoAckMilestoneByID(ctx context.Context, ethHandler *ethHandler, bor *bor.Bor) error {
|
||||
milestoneIDs := ethHandler.downloader.GetMilestoneIDsList()
|
||||
|
||||
for _, milestoneID := range milestoneIDs {
|
||||
// todo: check if we can ignore the error
|
||||
err := ethHandler.fetchNoAckMilestoneByID(ctx, bor, milestoneID)
|
||||
if err == nil {
|
||||
ethHandler.downloader.RemoveMilestoneID(milestoneID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Ethereum) getHandler() (*ethHandler, *bor.Bor, error) {
|
||||
ethHandler := (*ethHandler)(s.handler)
|
||||
|
||||
bor, ok := ethHandler.chain.Engine().(*bor.Bor)
|
||||
if !ok {
|
||||
return ErrNotBorConsensus
|
||||
return nil, nil, ErrNotBorConsensus
|
||||
}
|
||||
|
||||
if bor.HeimdallClient == nil {
|
||||
return ErrBorConsensusWithoutHeimdall
|
||||
return nil, nil, ErrBorConsensusWithoutHeimdall
|
||||
}
|
||||
|
||||
// Create a new checkpoint verifier
|
||||
verifier := newCheckpointVerifier(nil)
|
||||
blockNums, blockHashes, err := ethHandler.fetchWhitelistCheckpoints(ctx, bor, verifier, first)
|
||||
// If the array is empty, we're bound to receive an error. Non-nill error and non-empty array
|
||||
// means that array has partial elements and it failed for some block. We'll add those partial
|
||||
// elements anyway.
|
||||
if len(blockNums) == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the checkpoint whitelist map.
|
||||
for i := 0; i < len(blockNums); i++ {
|
||||
ethHandler.downloader.ProcessCheckpoint(blockNums[i], blockHashes[i])
|
||||
}
|
||||
|
||||
return nil
|
||||
return ethHandler, bor, nil
|
||||
}
|
||||
|
||||
// Stop implements node.Lifecycle, terminating all internal goroutines used by the
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package eth
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -11,8 +12,11 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
var errBorEngineNotAvailable error = errors.New("Only available in Bor engine")
|
||||
|
||||
// GetRootHash returns root hash for given start and end block
|
||||
func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) {
|
||||
var api *bor.API
|
||||
|
|
@ -24,7 +28,7 @@ func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, end
|
|||
}
|
||||
|
||||
if api == nil {
|
||||
return "", errors.New("Only available in Bor engine")
|
||||
return "", errBorEngineNotAvailable
|
||||
}
|
||||
|
||||
root, err := api.GetRootHash(starBlockNr, endBlockNr)
|
||||
|
|
@ -35,6 +39,70 @@ func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, end
|
|||
return root, nil
|
||||
}
|
||||
|
||||
// GetRootHash returns root hash for given start and end block
|
||||
func (b *EthAPIBackend) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64, hash string, milestoneId string) (bool, error) {
|
||||
var api *bor.API
|
||||
|
||||
for _, _api := range b.eth.Engine().APIs(b.eth.BlockChain()) {
|
||||
if _api.Namespace == "bor" {
|
||||
api = _api.Service.(*bor.API)
|
||||
}
|
||||
}
|
||||
|
||||
if api == nil {
|
||||
return false, errBorEngineNotAvailable
|
||||
}
|
||||
|
||||
//Confirmation of 16 blocks on the endblock
|
||||
tipConfirmationBlockNr := endBlockNr + uint64(16)
|
||||
|
||||
//Check if tipConfirmation block exit
|
||||
_, err := b.BlockByNumber(ctx, rpc.BlockNumber(tipConfirmationBlockNr))
|
||||
if err != nil {
|
||||
return false, errTipConfirmationBlock
|
||||
}
|
||||
|
||||
//Check if end block exist
|
||||
localEndBlock, err := b.BlockByNumber(ctx, rpc.BlockNumber(endBlockNr))
|
||||
if err != nil {
|
||||
return false, errEndBlock
|
||||
}
|
||||
|
||||
localEndBlockHash := localEndBlock.Hash().String()
|
||||
|
||||
downloader := b.eth.handler.downloader
|
||||
isLocked := downloader.LockMutex(endBlockNr)
|
||||
|
||||
if !isLocked {
|
||||
downloader.UnlockMutex(false, "", endBlockNr, common.Hash{})
|
||||
return false, errors.New("Whitelisted number or locked sprint number is more than the received end block number")
|
||||
}
|
||||
|
||||
if localEndBlockHash != hash {
|
||||
downloader.UnlockMutex(false, "", endBlockNr, common.Hash{})
|
||||
return false, fmt.Errorf("Hash mismatch: localChainHash %s, milestoneHash %s", localEndBlockHash, hash)
|
||||
}
|
||||
|
||||
ethHandler := (*ethHandler)(b.eth.handler)
|
||||
|
||||
bor, ok := ethHandler.chain.Engine().(*bor.Bor)
|
||||
|
||||
if !ok {
|
||||
return false, fmt.Errorf("Bor not available")
|
||||
}
|
||||
|
||||
err = bor.HeimdallClient.FetchMilestoneID(ctx, milestoneId)
|
||||
|
||||
if err != nil {
|
||||
downloader.UnlockMutex(false, "", endBlockNr, common.Hash{})
|
||||
return false, fmt.Errorf("Milestone ID doesn't exist in Heimdall")
|
||||
}
|
||||
|
||||
downloader.UnlockMutex(true, milestoneId, endBlockNr, localEndBlock.Hash())
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetBorBlockReceipt returns bor block receipt
|
||||
func (b *EthAPIBackend) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
|
||||
receipt := b.eth.blockchain.GetBorReceiptByHash(hash)
|
||||
|
|
|
|||
|
|
@ -1,61 +1,171 @@
|
|||
// nolint
|
||||
package eth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
type checkpointVerifier struct {
|
||||
verify func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error)
|
||||
}
|
||||
|
||||
func newCheckpointVerifier(verifyFn func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error)) *checkpointVerifier {
|
||||
if verifyFn != nil {
|
||||
return &checkpointVerifier{verifyFn}
|
||||
}
|
||||
|
||||
verifyFn = func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error) {
|
||||
var (
|
||||
startBlock = checkpoint.StartBlock.Uint64()
|
||||
endBlock = checkpoint.EndBlock.Uint64()
|
||||
// errMissingBlocks is returned when we don't have the blocks locally, yet.
|
||||
errMissingBlocks = errors.New("missing blocks")
|
||||
|
||||
// errRootHash is returned when we aren't able to calculate the root hash
|
||||
// locally for a range of blocks.
|
||||
errRootHash = errors.New("failed to get local root hash")
|
||||
|
||||
// errHashMismatch is returned when the local hash doesn't match
|
||||
// with the hash of checkpoint/milestone. It is the root hash of blocks
|
||||
// in case of checkpoint and is end block hash in case of milestones.
|
||||
errHashMismatch = errors.New("hash mismatch")
|
||||
|
||||
// errEndBlock is returned when we're unable to fetch a block locally.
|
||||
errEndBlock = errors.New("failed to get end block")
|
||||
|
||||
// errEndBlock is returned when we're unable to fetch a block locally.
|
||||
errTipConfirmationBlock = errors.New("failed to get tip confirmation block")
|
||||
|
||||
// errBlockNumberConversion is returned when we get err in parsing hexautil block number
|
||||
errBlockNumberConversion = errors.New("failed to parse the block number")
|
||||
|
||||
//Metrics for collecting the rewindLength
|
||||
rewindLengthMeter = metrics.NewRegisteredMeter("chain/autorewind/length", nil)
|
||||
)
|
||||
|
||||
// check if we have the checkpoint blocks
|
||||
//nolint:contextcheck
|
||||
head := handler.ethAPI.BlockNumber()
|
||||
if head < hexutil.Uint64(endBlock) {
|
||||
log.Debug("Head block behind checkpoint block", "head", head, "checkpoint end block", endBlock)
|
||||
return "", errMissingCheckpoint
|
||||
type borVerifier struct {
|
||||
verify func(ctx context.Context, eth *Ethereum, handler *ethHandler, start uint64, end uint64, hash string, isCheckpoint bool) (string, error)
|
||||
}
|
||||
|
||||
// verify the root hash of checkpoint
|
||||
roothash, err := handler.ethAPI.GetRootHash(ctx, startBlock, endBlock)
|
||||
func newBorVerifier() *borVerifier {
|
||||
return &borVerifier{borVerify}
|
||||
}
|
||||
|
||||
func borVerify(ctx context.Context, eth *Ethereum, handler *ethHandler, start uint64, end uint64, hash string, isCheckpoint bool) (string, error) {
|
||||
str := "milestone"
|
||||
if isCheckpoint {
|
||||
str = "checkpoint"
|
||||
}
|
||||
|
||||
// check if we have the given blocks
|
||||
currentBlock := eth.BlockChain().CurrentBlock()
|
||||
if currentBlock == nil {
|
||||
log.Debug(fmt.Sprintf("Failed to fetch current block from blockchain while verifying incoming %s", str))
|
||||
return hash, errMissingBlocks
|
||||
}
|
||||
|
||||
head := currentBlock.Number.Uint64()
|
||||
|
||||
if head < end {
|
||||
log.Debug(fmt.Sprintf("Current head block behind incoming %s block", str), "head", head, "end block", end)
|
||||
return hash, errMissingBlocks
|
||||
}
|
||||
|
||||
var localHash string
|
||||
|
||||
// verify the hash
|
||||
if isCheckpoint {
|
||||
var err error
|
||||
|
||||
// in case of checkpoint get the rootHash
|
||||
localHash, err = handler.ethAPI.GetRootHash(ctx, start, end)
|
||||
|
||||
if err != nil {
|
||||
log.Debug("Failed to get root hash of checkpoint while whitelisting", "err", err)
|
||||
return "", errRootHash
|
||||
log.Debug("Failed to get root hash of given block range while whitelisting checkpoint", "start", start, "end", end, "err", err)
|
||||
return hash, errRootHash
|
||||
}
|
||||
|
||||
if roothash != checkpoint.RootHash.String()[2:] {
|
||||
log.Warn("Checkpoint root hash mismatch while whitelisting", "expected", checkpoint.RootHash.String()[2:], "got", roothash)
|
||||
return "", errCheckpointRootHashMismatch
|
||||
}
|
||||
|
||||
// fetch the end checkpoint block hash
|
||||
block, err := handler.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(endBlock), false)
|
||||
} else {
|
||||
// in case of milestone(isCheckpoint==false) get the hash of endBlock
|
||||
block, err := handler.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(end), false)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get end block hash of checkpoint while whitelisting", "err", err)
|
||||
return "", errEndBlock
|
||||
log.Debug("Failed to get end block hash while whitelisting milestone", "number", end, "err", err)
|
||||
return hash, errEndBlock
|
||||
}
|
||||
|
||||
hash := fmt.Sprintf("%v", block["hash"])
|
||||
localHash = fmt.Sprintf("%v", block["hash"])[2:]
|
||||
}
|
||||
|
||||
//nolint
|
||||
if localHash != hash {
|
||||
|
||||
if isCheckpoint {
|
||||
log.Warn("Root hash mismatch while whitelisting checkpoint", "expected", localHash, "got", hash)
|
||||
} else {
|
||||
log.Warn("End block hash mismatch while whitelisting milestone", "expected", localHash, "got", hash)
|
||||
}
|
||||
|
||||
ethHandler := (*ethHandler)(eth.handler)
|
||||
|
||||
var (
|
||||
rewindTo uint64
|
||||
doExist bool
|
||||
)
|
||||
|
||||
if doExist, rewindTo, _ = ethHandler.downloader.GetWhitelistedMilestone(); doExist {
|
||||
|
||||
} else if doExist, rewindTo, _ = ethHandler.downloader.GetWhitelistedCheckpoint(); doExist {
|
||||
|
||||
} else {
|
||||
if start <= 0 {
|
||||
rewindTo = 0
|
||||
} else {
|
||||
rewindTo = start - 1
|
||||
}
|
||||
}
|
||||
|
||||
if head-rewindTo > 255 {
|
||||
rewindTo = head - 255
|
||||
}
|
||||
|
||||
if isCheckpoint {
|
||||
log.Warn("Rewinding chain due to checkpoint root hash mismatch", "number", rewindTo)
|
||||
} else {
|
||||
log.Warn("Rewinding chain due to milestone endblock hash mismatch", "number", rewindTo)
|
||||
}
|
||||
|
||||
rewindBack(eth, head, rewindTo)
|
||||
|
||||
return hash, errHashMismatch
|
||||
}
|
||||
|
||||
// fetch the end block hash
|
||||
block, err := handler.ethAPI.GetBlockByNumber(ctx, rpc.BlockNumber(end), false)
|
||||
if err != nil {
|
||||
log.Debug("Failed to get end block hash while whitelisting", "err", err)
|
||||
return hash, errEndBlock
|
||||
}
|
||||
|
||||
hash = fmt.Sprintf("%v", block["hash"])
|
||||
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
return &checkpointVerifier{verifyFn}
|
||||
// Stop the miner if the mining process is running and rewind back the chain
|
||||
func rewindBack(eth *Ethereum, head uint64, rewindTo uint64) {
|
||||
if eth.Miner().Mining() {
|
||||
ch := make(chan struct{})
|
||||
eth.Miner().Stop(ch)
|
||||
|
||||
<-ch
|
||||
rewind(eth, head, rewindTo)
|
||||
|
||||
eth.Miner().Start()
|
||||
} else {
|
||||
rewind(eth, head, rewindTo)
|
||||
}
|
||||
}
|
||||
|
||||
func rewind(eth *Ethereum, head uint64, rewindTo uint64) {
|
||||
err := eth.blockchain.SetHead(rewindTo)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Error while rewinding the chain", "to", rewindTo, "err", err)
|
||||
} else {
|
||||
rewindLengthMeter.Mark(int64(head - rewindTo))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,6 +216,8 @@ type BlockChain interface {
|
|||
// Snapshots returns the blockchain snapshot tree to paused it during sync.
|
||||
Snapshots() *snapshot.Tree
|
||||
|
||||
GetChainConfig() *params.ChainConfig
|
||||
|
||||
// TrieDB retrieves the low level trie database used for interacting
|
||||
// with trie nodes.
|
||||
TrieDB() *trie.Database
|
||||
|
|
@ -367,8 +369,7 @@ func (d *Downloader) LegacySync(id string, head common.Hash, td, ttd *big.Int, m
|
|||
|
||||
if errors.Is(err, errInvalidChain) || errors.Is(err, errBadPeer) || errors.Is(err, errTimeout) ||
|
||||
errors.Is(err, errStallingPeer) || errors.Is(err, errUnsyncedPeer) || errors.Is(err, errEmptyHeaderSet) ||
|
||||
errors.Is(err, errPeersUnavailable) || errors.Is(err, errTooOld) || errors.Is(err, errInvalidAncestor) ||
|
||||
errors.Is(err, whitelist.ErrCheckpointMismatch) {
|
||||
errors.Is(err, errPeersUnavailable) || errors.Is(err, errTooOld) || errors.Is(err, errInvalidAncestor) {
|
||||
log.Warn("Synchronisation failed, dropping peer", "peer", id, "err", err)
|
||||
|
||||
if d.dropPeer == nil {
|
||||
|
|
@ -386,7 +387,13 @@ func (d *Downloader) LegacySync(id string, head common.Hash, td, ttd *big.Int, m
|
|||
return err // This is an expected fault, don't keep printing it in a spin-loop
|
||||
}
|
||||
|
||||
log.Warn("Synchronisation failed, retrying", "err", err)
|
||||
// Warn in case of any error thrown by whitelisting module
|
||||
if errors.Is(err, whitelist.ErrNoRemote) || errors.Is(err, whitelist.ErrMismatch) {
|
||||
log.Warn("Synchronisation failed due to whitelist validation", "peer", id, "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Warn("Synchronisation failed, retrying", "peer", id, "err", err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
@ -895,9 +902,10 @@ func (d *Downloader) getFetchHeadersByNumber(p *peerConnection) func(number uint
|
|||
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
|
||||
// the head links match), we do a binary search to find the common ancestor.
|
||||
func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header) (uint64, error) {
|
||||
|
||||
// Check the validity of peer from which the chain is to be downloaded
|
||||
if d.ChainValidator != nil {
|
||||
if _, err := d.IsValidPeer(remoteHeader, d.getFetchHeadersByNumber(p)); err != nil {
|
||||
if _, err := d.IsValidPeer(d.getFetchHeadersByNumber(p)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
|
@ -1989,6 +1997,11 @@ func (d *Downloader) DeliverSnapPacket(peer *snap.Peer, packet snap.Packet) erro
|
|||
}
|
||||
}
|
||||
|
||||
// GetWhitelistService returns the pointer to the whitelist service
|
||||
func (d *Downloader) GetWhitelistService() ethereum.ChainValidator {
|
||||
return d.ChainValidator
|
||||
}
|
||||
|
||||
// readHeaderRange returns a list of headers, using the given last header as the base,
|
||||
// and going backwards towards genesis. This method assumes that the caller already has
|
||||
// placed a reasonable cap on count.
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
|
|||
}
|
||||
|
||||
//nolint: staticcheck
|
||||
tester.downloader = New(0, db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success, whitelist.NewService(10))
|
||||
tester.downloader = New(0, db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success, whitelist.NewService(db))
|
||||
|
||||
return tester
|
||||
}
|
||||
|
|
@ -1965,7 +1965,7 @@ func newWhitelistFake(validate func(count int) (bool, error)) *whitelistFake {
|
|||
|
||||
// IsValidPeer is the mock function which the downloader will use to validate the chain
|
||||
// to be received from a peer.
|
||||
func (w *whitelistFake) IsValidPeer(_ *types.Header, _ func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||
func (w *whitelistFake) IsValidPeer(_ func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||
defer func() {
|
||||
w.count++
|
||||
}()
|
||||
|
|
@ -1978,13 +1978,33 @@ func (w *whitelistFake) IsValidChain(current *types.Header, headers []*types.Hea
|
|||
}
|
||||
func (w *whitelistFake) ProcessCheckpoint(_ uint64, _ common.Hash) {}
|
||||
|
||||
func (w *whitelistFake) GetCheckpointWhitelist() map[uint64]common.Hash {
|
||||
return nil
|
||||
func (w *whitelistFake) GetWhitelistedCheckpoint() (bool, uint64, common.Hash) {
|
||||
return false, 0, common.Hash{}
|
||||
}
|
||||
func (w *whitelistFake) PurgeCheckpointWhitelist() {}
|
||||
func (w *whitelistFake) PurgeWhitelistedCheckpoint() {}
|
||||
|
||||
func (w *whitelistFake) ProcessMilestone(_ uint64, _ common.Hash) {}
|
||||
func (w *whitelistFake) ProcessFutureMilestone(_ uint64, _ common.Hash) {}
|
||||
func (w *whitelistFake) GetWhitelistedMilestone() (bool, uint64, common.Hash) {
|
||||
return false, 0, common.Hash{}
|
||||
}
|
||||
func (w *whitelistFake) PurgeWhitelistedMilestone() {}
|
||||
|
||||
func (w *whitelistFake) GetCheckpoints(current, sidechainHeader *types.Header, sidechainCheckpoints []*types.Header) (map[uint64]*types.Header, error) {
|
||||
return map[uint64]*types.Header{}, nil
|
||||
}
|
||||
func (w *whitelistFake) LockMutex(endBlockNum uint64) bool {
|
||||
return false
|
||||
}
|
||||
func (w *whitelistFake) UnlockMutex(doLock bool, milestoneId string, endBlockNum uint64, endBlockHash common.Hash) {
|
||||
}
|
||||
func (w *whitelistFake) UnlockSprint(endBlockNum uint64) {
|
||||
}
|
||||
func (w *whitelistFake) RemoveMilestoneID(milestoneId string) {
|
||||
}
|
||||
func (w *whitelistFake) GetMilestoneIDsList() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestFakedSyncProgress66WhitelistMismatch tests if in case of whitelisted
|
||||
// checkpoint mismatch with opposite peer, the sync should fail.
|
||||
|
|
@ -1996,7 +2016,7 @@ func TestFakedSyncProgress66WhitelistMismatch(t *testing.T) {
|
|||
|
||||
tester := newTester(t)
|
||||
validate := func(count int) (bool, error) {
|
||||
return false, whitelist.ErrCheckpointMismatch
|
||||
return false, whitelist.ErrMismatch
|
||||
}
|
||||
tester.downloader.ChainValidator = newWhitelistFake(validate)
|
||||
|
||||
|
|
@ -2049,7 +2069,7 @@ func TestFakedSyncProgress66NoRemoteCheckpoint(t *testing.T) {
|
|||
validate := func(count int) (bool, error) {
|
||||
// only return the `ErrNoRemoteCheckpoint` error for the first call
|
||||
if count == 0 {
|
||||
return false, whitelist.ErrNoRemoteCheckpoint
|
||||
return false, whitelist.ErrNoRemote
|
||||
}
|
||||
|
||||
return true, nil
|
||||
|
|
@ -2065,7 +2085,7 @@ func TestFakedSyncProgress66NoRemoteCheckpoint(t *testing.T) {
|
|||
// Synchronise with the peer and make sure all blocks were retrieved
|
||||
// Should fail in first attempt
|
||||
if err := tester.sync("light", nil, mode); err != nil {
|
||||
assert.Equal(t, whitelist.ErrNoRemoteCheckpoint, err, "failed synchronisation")
|
||||
assert.Equal(t, whitelist.ErrNoRemote, err, "failed synchronisation")
|
||||
}
|
||||
|
||||
// Try syncing again, should succeed
|
||||
|
|
|
|||
67
eth/downloader/whitelist/checkpoint.go
Normal file
67
eth/downloader/whitelist/checkpoint.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package whitelist
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
)
|
||||
|
||||
type checkpoint struct {
|
||||
finality[*rawdb.Checkpoint]
|
||||
}
|
||||
|
||||
type checkpointService interface {
|
||||
finalityService
|
||||
}
|
||||
|
||||
var (
|
||||
//Metrics for collecting the whitelisted milestone number
|
||||
whitelistedCheckpointNumberMeter = metrics.NewRegisteredGauge("chain/checkpoint/latest", nil)
|
||||
|
||||
//Metrics for collecting the number of invalid chains received
|
||||
CheckpointChainMeter = metrics.NewRegisteredMeter("chain/checkpoint/isvalidchain", nil)
|
||||
|
||||
//Metrics for collecting the number of valid peers received
|
||||
CheckpointPeerMeter = metrics.NewRegisteredMeter("chain/checkpoint/isvalidpeer", nil)
|
||||
)
|
||||
|
||||
// IsValidChain checks the validity of chain by comparing it
|
||||
// against the local checkpoint entry
|
||||
func (w *checkpoint) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
|
||||
w.finality.RLock()
|
||||
defer w.finality.RUnlock()
|
||||
|
||||
res, err := w.finality.IsValidChain(currentHeader, chain)
|
||||
|
||||
if res {
|
||||
CheckpointChainMeter.Mark(int64(1))
|
||||
} else {
|
||||
CheckpointPeerMeter.Mark(int64(-1))
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
||||
// in terms of reorgs. We won't reorg beyond the last bor finality submitted to mainchain.
|
||||
func (w *checkpoint) IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||
res, err := w.finality.IsValidPeer(fetchHeadersByNumber)
|
||||
|
||||
if res {
|
||||
CheckpointPeerMeter.Mark(int64(1))
|
||||
} else {
|
||||
CheckpointPeerMeter.Mark(int64(-1))
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (w *checkpoint) Process(block uint64, hash common.Hash) {
|
||||
w.finality.Lock()
|
||||
defer w.finality.Unlock()
|
||||
|
||||
w.finality.Process(block, hash)
|
||||
|
||||
whitelistedCheckpointNumberMeter.Update(int64(block))
|
||||
}
|
||||
96
eth/downloader/whitelist/finality.go
Normal file
96
eth/downloader/whitelist/finality.go
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
package whitelist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
type finality[T rawdb.BlockFinality[T]] struct {
|
||||
sync.RWMutex
|
||||
db ethdb.Database
|
||||
Hash common.Hash // Whitelisted Hash, populated by reaching out to heimdall
|
||||
Number uint64 // Number , populated by reaching out to heimdall
|
||||
interval uint64 // Interval, until which we can allow importing
|
||||
doExist bool
|
||||
}
|
||||
|
||||
type finalityService interface {
|
||||
IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error)
|
||||
IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error)
|
||||
Get() (bool, uint64, common.Hash)
|
||||
Process(block uint64, hash common.Hash)
|
||||
Purge()
|
||||
}
|
||||
|
||||
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
||||
// in terms of reorgs. We won't reorg beyond the last bor finality submitted to mainchain.
|
||||
func (f *finality[T]) IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||
// We want to validate the chain by comparing the last finalized block
|
||||
f.RLock()
|
||||
|
||||
doExist := f.doExist
|
||||
number := f.Number
|
||||
hash := f.Hash
|
||||
|
||||
f.RUnlock()
|
||||
|
||||
return isValidPeer(fetchHeadersByNumber, doExist, number, hash)
|
||||
}
|
||||
|
||||
// IsValidChain checks the validity of chain by comparing it
|
||||
// against the local checkpoint entry
|
||||
// todo: need changes
|
||||
func (f *finality[T]) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
|
||||
// Return if we've received empty chain
|
||||
if len(chain) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
res, err := isValidChain(currentHeader, chain, f.doExist, f.Number, f.Hash)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (f *finality[T]) Process(block uint64, hash common.Hash) {
|
||||
f.doExist = true
|
||||
f.Hash = hash
|
||||
f.Number = block
|
||||
|
||||
err := rawdb.WriteLastFinality[T](f.db, block, hash)
|
||||
if err != nil {
|
||||
log.Error("Error in writing whitelist state to db", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the existing whitelisted
|
||||
// entries of checkpoint of the form (doExist,block number,block hash.)
|
||||
func (f *finality[T]) Get() (bool, uint64, common.Hash) {
|
||||
f.RLock()
|
||||
defer f.RUnlock()
|
||||
|
||||
if f.doExist {
|
||||
return f.doExist, f.Number, f.Hash
|
||||
}
|
||||
|
||||
block, hash, err := rawdb.ReadFinality[T](f.db)
|
||||
if err != nil {
|
||||
fmt.Println("Error while reading whitelisted state from Db", "err", err)
|
||||
return false, f.Number, f.Hash
|
||||
}
|
||||
|
||||
return true, block, hash
|
||||
}
|
||||
|
||||
// Purge purges the whitlisted checkpoint
|
||||
func (f *finality[T]) Purge() {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
|
||||
f.doExist = false
|
||||
}
|
||||
315
eth/downloader/whitelist/milestone.go
Normal file
315
eth/downloader/whitelist/milestone.go
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
package whitelist
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/flags"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
)
|
||||
|
||||
type milestone struct {
|
||||
finality[*rawdb.Milestone]
|
||||
|
||||
LockedMilestoneNumber uint64 // Locked sprint number
|
||||
LockedMilestoneHash common.Hash //Hash for the locked endBlock
|
||||
Locked bool //
|
||||
LockedMilestoneIDs map[string]struct{} //list of milestone ids
|
||||
|
||||
FutureMilestoneList map[uint64]common.Hash // Future Milestone list
|
||||
FutureMilestoneOrder []uint64 // Future Milestone Order
|
||||
MaxCapacity int //Capacity of future Milestone list
|
||||
}
|
||||
|
||||
type milestoneService interface {
|
||||
finalityService
|
||||
|
||||
GetMilestoneIDsList() []string
|
||||
RemoveMilestoneID(milestoneId string)
|
||||
LockMutex(endBlockNum uint64) bool
|
||||
UnlockMutex(doLock bool, milestoneId string, endBlockNum uint64, endBlockHash common.Hash)
|
||||
UnlockSprint(endBlockNum uint64)
|
||||
ProcessFutureMilestone(num uint64, hash common.Hash)
|
||||
}
|
||||
|
||||
var (
|
||||
//Metrics for collecting the whitelisted milestone number
|
||||
whitelistedMilestoneMeter = metrics.NewRegisteredGauge("chain/milestone/latest", nil)
|
||||
|
||||
//Metrics for collecting the future milestone number
|
||||
FutureMilestoneMeter = metrics.NewRegisteredGauge("chain/milestone/future", nil)
|
||||
|
||||
//Metrics for collecting the length of the MilestoneIds map
|
||||
MilestoneIdsLengthMeter = metrics.NewRegisteredGauge("chain/milestone/idslength", nil)
|
||||
|
||||
//Metrics for collecting the number of valid chains received
|
||||
MilestoneChainMeter = metrics.NewRegisteredMeter("chain/milestone/isvalidchain", nil)
|
||||
|
||||
//Metrics for collecting the number of valid peers received
|
||||
MilestonePeerMeter = metrics.NewRegisteredMeter("chain/milestone/isvalidpeer", nil)
|
||||
)
|
||||
|
||||
// IsValidChain checks the validity of chain by comparing it
|
||||
// against the local milestone entries
|
||||
func (m *milestone) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
|
||||
//Checking for the milestone flag
|
||||
if !flags.Milestone {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
m.finality.RLock()
|
||||
defer m.finality.RUnlock()
|
||||
|
||||
var isValid bool = false
|
||||
|
||||
defer func() {
|
||||
if isValid {
|
||||
MilestoneChainMeter.Mark(int64(1))
|
||||
} else {
|
||||
MilestoneChainMeter.Mark(int64(-1))
|
||||
}
|
||||
}()
|
||||
|
||||
res, err := m.finality.IsValidChain(currentHeader, chain)
|
||||
|
||||
if !res {
|
||||
isValid = false
|
||||
return isValid, err
|
||||
}
|
||||
|
||||
if m.Locked && !m.IsReorgAllowed(chain, m.LockedMilestoneNumber, m.LockedMilestoneHash) {
|
||||
isValid = false
|
||||
return isValid, nil
|
||||
}
|
||||
|
||||
if !m.IsFutureMilestoneCompatible(chain) {
|
||||
isValid = false
|
||||
return isValid, nil
|
||||
}
|
||||
|
||||
isValid = true
|
||||
|
||||
return isValid, nil
|
||||
}
|
||||
|
||||
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
||||
// in terms of reorgs. We won't reorg beyond the last bor finality submitted to mainchain.
|
||||
func (m *milestone) IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||
if !flags.Milestone {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
res, err := m.finality.IsValidPeer(fetchHeadersByNumber)
|
||||
|
||||
if res {
|
||||
MilestonePeerMeter.Mark(int64(1))
|
||||
} else {
|
||||
MilestonePeerMeter.Mark(int64(-1))
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (m *milestone) Process(block uint64, hash common.Hash) {
|
||||
m.finality.Lock()
|
||||
defer m.finality.Unlock()
|
||||
|
||||
m.finality.Process(block, hash)
|
||||
|
||||
for i := 0; i < len(m.FutureMilestoneOrder); i++ {
|
||||
if m.FutureMilestoneOrder[i] <= block {
|
||||
m.dequeueFutureMilestone()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
whitelistedMilestoneMeter.Update(int64(block))
|
||||
|
||||
m.UnlockSprint(block)
|
||||
}
|
||||
|
||||
// This function will Lock the mutex at the time of voting
|
||||
// fixme: get rid of it
|
||||
func (m *milestone) LockMutex(endBlockNum uint64) bool {
|
||||
m.finality.Lock()
|
||||
|
||||
if m.doExist && endBlockNum <= m.Number { //if endNum is less than whitelisted milestone, then we won't lock the sprint
|
||||
log.Debug("endBlockNumber is less than or equal to latesMilestoneNumber", "endBlock Number", endBlockNum, "LatestMilestone Number", m.Number)
|
||||
return false
|
||||
}
|
||||
|
||||
if m.Locked && endBlockNum < m.LockedMilestoneNumber {
|
||||
log.Debug("endBlockNum is less than locked milestone number", "endBlock Number", endBlockNum, "Locked Milestone Number", m.LockedMilestoneNumber)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// This function will unlock the mutex locked in LockMutex
|
||||
// fixme: get rid of it
|
||||
func (m *milestone) UnlockMutex(doLock bool, milestoneId string, endBlockNum uint64, endBlockHash common.Hash) {
|
||||
m.Locked = m.Locked || doLock
|
||||
|
||||
if doLock {
|
||||
m.UnlockSprint(m.LockedMilestoneNumber)
|
||||
m.Locked = true
|
||||
m.LockedMilestoneHash = endBlockHash
|
||||
m.LockedMilestoneNumber = endBlockNum
|
||||
m.LockedMilestoneIDs[milestoneId] = struct{}{}
|
||||
}
|
||||
|
||||
err := rawdb.WriteLockField(m.db, m.Locked, m.LockedMilestoneNumber, m.LockedMilestoneHash, m.LockedMilestoneIDs)
|
||||
if err != nil {
|
||||
log.Error("Error in writing lock data of milestone to db", "err", err)
|
||||
}
|
||||
|
||||
milestoneIDLength := int64(len(m.LockedMilestoneIDs))
|
||||
MilestoneIdsLengthMeter.Update(milestoneIDLength)
|
||||
|
||||
m.finality.Unlock()
|
||||
}
|
||||
|
||||
// This function will unlock the locked sprint
|
||||
func (m *milestone) UnlockSprint(endBlockNum uint64) {
|
||||
if endBlockNum < m.LockedMilestoneNumber {
|
||||
return
|
||||
}
|
||||
|
||||
m.Locked = false
|
||||
m.purgeMilestoneIDsList()
|
||||
|
||||
err := rawdb.WriteLockField(m.db, m.Locked, m.LockedMilestoneNumber, m.LockedMilestoneHash, m.LockedMilestoneIDs)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Error in writing lock data of milestone to db", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// This function will remove the stored milestoneID
|
||||
func (m *milestone) RemoveMilestoneID(milestoneId string) {
|
||||
m.finality.Lock()
|
||||
|
||||
delete(m.LockedMilestoneIDs, milestoneId)
|
||||
|
||||
if len(m.LockedMilestoneIDs) == 0 {
|
||||
m.Locked = false
|
||||
}
|
||||
|
||||
err := rawdb.WriteLockField(m.db, m.Locked, m.LockedMilestoneNumber, m.LockedMilestoneHash, m.LockedMilestoneIDs)
|
||||
if err != nil {
|
||||
log.Error("Error in writing lock data of milestone to db", "err", err)
|
||||
}
|
||||
|
||||
m.finality.Unlock()
|
||||
}
|
||||
|
||||
// This will check whether the incoming chain matches the locked sprint hash
|
||||
func (m *milestone) IsReorgAllowed(chain []*types.Header, lockedMilestoneNumber uint64, lockedMilestoneHash common.Hash) bool {
|
||||
if chain[len(chain)-1].Number.Uint64() <= lockedMilestoneNumber { //Can't reorg if the end block of incoming
|
||||
return false //chain is less than locked sprint number
|
||||
}
|
||||
|
||||
for i := 0; i < len(chain); i++ {
|
||||
if chain[i].Number.Uint64() == lockedMilestoneNumber {
|
||||
return chain[i].Hash() == lockedMilestoneHash
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// This will return the list of milestoneIDs stored.
|
||||
func (m *milestone) GetMilestoneIDsList() []string {
|
||||
m.finality.RLock()
|
||||
defer m.finality.RUnlock()
|
||||
|
||||
// fixme: use generics :)
|
||||
keys := make([]string, 0, len(m.LockedMilestoneIDs))
|
||||
for key := range m.LockedMilestoneIDs {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
// This is remove the milestoneIDs stored in the list.
|
||||
func (m *milestone) purgeMilestoneIDsList() {
|
||||
m.LockedMilestoneIDs = make(map[string]struct{})
|
||||
}
|
||||
|
||||
func (m *milestone) IsFutureMilestoneCompatible(chain []*types.Header) bool {
|
||||
//Tip of the received chain
|
||||
chainTipNumber := chain[len(chain)-1].Number.Uint64()
|
||||
|
||||
for i := len(m.FutureMilestoneOrder) - 1; i >= 0; i-- {
|
||||
//Finding out the highest future milestone number
|
||||
//which is less or equal to received chain tip
|
||||
if chainTipNumber >= m.FutureMilestoneOrder[i] {
|
||||
//Looking for the received chain 's particular block number(matching future milestone number)
|
||||
for j := len(chain) - 1; j >= 0; j-- {
|
||||
if chain[j].Number.Uint64() == m.FutureMilestoneOrder[i] {
|
||||
endBlockNum := m.FutureMilestoneOrder[i]
|
||||
endBlockHash := m.FutureMilestoneList[endBlockNum]
|
||||
|
||||
//Checking the received chain matches with future milestone
|
||||
return chain[j].Hash() == endBlockHash
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *milestone) ProcessFutureMilestone(num uint64, hash common.Hash) {
|
||||
if len(m.FutureMilestoneOrder) < m.MaxCapacity {
|
||||
m.enqueueFutureMilestone(num, hash)
|
||||
}
|
||||
|
||||
if num < m.LockedMilestoneNumber {
|
||||
return
|
||||
}
|
||||
|
||||
m.Locked = false
|
||||
m.purgeMilestoneIDsList()
|
||||
|
||||
err := rawdb.WriteLockField(m.db, m.Locked, m.LockedMilestoneNumber, m.LockedMilestoneHash, m.LockedMilestoneIDs)
|
||||
|
||||
if err != nil {
|
||||
log.Error("Error in writing lock data of milestone to db", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// EnqueueFutureMilestone add the future milestone to the list
|
||||
func (m *milestone) enqueueFutureMilestone(key uint64, hash common.Hash) {
|
||||
if _, ok := m.FutureMilestoneList[key]; ok {
|
||||
log.Debug("Future milestone already exist", "endBlockNumber", key, "futureMilestoneHash", hash)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debug("Enqueing new future milestone", "endBlockNumber", key, "futureMilestoneHash", hash)
|
||||
|
||||
m.FutureMilestoneList[key] = hash
|
||||
m.FutureMilestoneOrder = append(m.FutureMilestoneOrder, key)
|
||||
|
||||
err := rawdb.WriteFutureMilestoneList(m.db, m.FutureMilestoneOrder, m.FutureMilestoneList)
|
||||
if err != nil {
|
||||
log.Error("Error in writing future milestone data to db", "err", err)
|
||||
}
|
||||
|
||||
FutureMilestoneMeter.Update(int64(key))
|
||||
}
|
||||
|
||||
// DequeueFutureMilestone remove the future milestone entry from the list.
|
||||
func (m *milestone) dequeueFutureMilestone() {
|
||||
delete(m.FutureMilestoneList, m.FutureMilestoneOrder[0])
|
||||
m.FutureMilestoneOrder = m.FutureMilestoneOrder[1:]
|
||||
|
||||
err := rawdb.WriteFutureMilestoneList(m.db, m.FutureMilestoneOrder, m.FutureMilestoneList)
|
||||
if err != nil {
|
||||
log.Error("Error in writing future milestone data to db", "err", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,135 +3,150 @@ package whitelist
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
)
|
||||
|
||||
// Checkpoint whitelist
|
||||
type Service struct {
|
||||
m sync.Mutex
|
||||
checkpointWhitelist map[uint64]common.Hash // Checkpoint whitelist, populated by reaching out to heimdall
|
||||
checkpointOrder []uint64 // Checkpoint order, populated by reaching out to heimdall
|
||||
maxCapacity uint // Max capacity of the whitelist
|
||||
checkpointInterval uint64 // Checkpoint interval, until which we can allow importing
|
||||
}
|
||||
|
||||
func NewService(maxCapacity uint) *Service {
|
||||
return &Service{
|
||||
checkpointWhitelist: make(map[uint64]common.Hash),
|
||||
checkpointOrder: []uint64{},
|
||||
maxCapacity: maxCapacity,
|
||||
checkpointInterval: 256, // TODO: make it configurable through params?
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
ErrMismatch = errors.New("mismatch error")
|
||||
ErrNoRemote = errors.New("remote peer doesn't have a target block number")
|
||||
|
||||
ErrCheckpointMismatch = errors.New("checkpoint mismatch")
|
||||
ErrLongFutureChain = errors.New("received future chain of unacceptable length")
|
||||
ErrNoRemoteCheckpoint = errors.New("remote peer doesn't have a checkpoint")
|
||||
)
|
||||
|
||||
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
||||
// in terms of reorgs. We won't reorg beyond the last bor checkpoint submitted to mainchain.
|
||||
func (w *Service) IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||
// We want to validate the chain by comparing the last checkpointed block
|
||||
// we're storing in `checkpointWhitelist` with the peer's block.
|
||||
//
|
||||
// Check for availaibility of the last checkpointed block.
|
||||
// This can be also be empty if our heimdall is not responding
|
||||
// or we're running without it.
|
||||
if len(w.checkpointWhitelist) == 0 {
|
||||
// worst case, we don't have the checkpoints in memory
|
||||
return true, nil
|
||||
type Service struct {
|
||||
checkpointService
|
||||
milestoneService
|
||||
}
|
||||
|
||||
// Fetch the last checkpoint entry
|
||||
lastCheckpointBlockNum := w.checkpointOrder[len(w.checkpointOrder)-1]
|
||||
lastCheckpointBlockHash := w.checkpointWhitelist[lastCheckpointBlockNum]
|
||||
func NewService(db ethdb.Database) *Service {
|
||||
var checkpointDoExist = true
|
||||
|
||||
checkpointNumber, checkpointHash, err := rawdb.ReadFinality[*rawdb.Checkpoint](db)
|
||||
|
||||
// todo: we can extract this as an interface and mock as well or just test IsValidChain in isolation from downloader passing fake fetchHeadersByNumber functions
|
||||
headers, hashes, err := fetchHeadersByNumber(lastCheckpointBlockNum, 1, 0, false)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("%w: last checkpoint %d, err %v", ErrNoRemoteCheckpoint, lastCheckpointBlockNum, err)
|
||||
checkpointDoExist = false
|
||||
}
|
||||
|
||||
if len(headers) == 0 {
|
||||
return false, fmt.Errorf("%w: last checkpoint %d", ErrNoRemoteCheckpoint, lastCheckpointBlockNum)
|
||||
var milestoneDoExist = true
|
||||
|
||||
milestoneNumber, milestoneHash, err := rawdb.ReadFinality[*rawdb.Milestone](db)
|
||||
if err != nil {
|
||||
milestoneDoExist = false
|
||||
}
|
||||
|
||||
reqBlockNum := headers[0].Number.Uint64()
|
||||
reqBlockHash := hashes[0]
|
||||
|
||||
// Check against the checkpointed blocks
|
||||
if reqBlockNum == lastCheckpointBlockNum && reqBlockHash == lastCheckpointBlockHash {
|
||||
return true, nil
|
||||
locked, lockedMilestoneNumber, lockedMilestoneHash, lockedMilestoneIDs, err := rawdb.ReadLockField(db)
|
||||
if err != nil || !locked {
|
||||
locked = false
|
||||
lockedMilestoneIDs = make(map[string]struct{})
|
||||
}
|
||||
|
||||
return false, ErrCheckpointMismatch
|
||||
order, list, err := rawdb.ReadFutureMilestoneList(db)
|
||||
if err != nil {
|
||||
order = make([]uint64, 0)
|
||||
list = make(map[uint64]common.Hash)
|
||||
}
|
||||
|
||||
// IsValidChain checks the validity of chain by comparing it
|
||||
// against the local checkpoint entries
|
||||
func (w *Service) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
|
||||
// Check if we have checkpoints to validate incoming chain in memory
|
||||
if len(w.checkpointWhitelist) == 0 {
|
||||
// We don't have any entries, no additional validation will be possible
|
||||
return true, nil
|
||||
return &Service{
|
||||
&checkpoint{
|
||||
finality[*rawdb.Checkpoint]{
|
||||
doExist: checkpointDoExist,
|
||||
Number: checkpointNumber,
|
||||
Hash: checkpointHash,
|
||||
interval: 256,
|
||||
db: db,
|
||||
},
|
||||
},
|
||||
|
||||
&milestone{
|
||||
finality: finality[*rawdb.Milestone]{
|
||||
doExist: milestoneDoExist,
|
||||
Number: milestoneNumber,
|
||||
Hash: milestoneHash,
|
||||
interval: 256,
|
||||
db: db,
|
||||
},
|
||||
|
||||
Locked: locked,
|
||||
LockedMilestoneNumber: lockedMilestoneNumber,
|
||||
LockedMilestoneHash: lockedMilestoneHash,
|
||||
LockedMilestoneIDs: lockedMilestoneIDs,
|
||||
FutureMilestoneList: list,
|
||||
FutureMilestoneOrder: order,
|
||||
MaxCapacity: 10,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Return if we've received empty chain
|
||||
if len(chain) == 0 {
|
||||
return false, nil
|
||||
// IsValidPeer checks if the chain we're about to receive from a peer is valid or not
|
||||
// in terms of reorgs. We won't reorg beyond the last bor checkpoint submitted to mainchain and last milestone voted in the heimdall
|
||||
func (s *Service) IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error) {
|
||||
checkpointBool, err := s.checkpointService.IsValidPeer(fetchHeadersByNumber)
|
||||
if !checkpointBool {
|
||||
return checkpointBool, err
|
||||
}
|
||||
|
||||
var (
|
||||
oldestCheckpointNumber uint64 = w.checkpointOrder[0]
|
||||
current uint64 = currentHeader.Number.Uint64()
|
||||
)
|
||||
|
||||
// Check if we have whitelist entries in required range
|
||||
if chain[len(chain)-1].Number.Uint64() < oldestCheckpointNumber {
|
||||
// We have future whitelisted entries, so no additional validation will be possible
|
||||
// This case will occur when bor is in middle of sync, but heimdall is ahead/fully synced.
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Split the chain into past and future chain
|
||||
pastChain, _ := splitChain(current, chain)
|
||||
|
||||
// Note: Do not act on future chain and allow importing all kinds of future chains.
|
||||
|
||||
// Add an offset to future chain if it's not in continuity
|
||||
// offset := 0
|
||||
// if len(futureChain) != 0 {
|
||||
// offset += int(futureChain[0].Number.Uint64()-currentHeader.Number.Uint64()) - 1
|
||||
// }
|
||||
|
||||
// Don't accept future chain of unacceptable length (from current block)
|
||||
// if len(futureChain)+offset > int(w.checkpointInterval) {
|
||||
// return false, ErrLongFutureChain
|
||||
// }
|
||||
|
||||
// Iterate over the chain and validate against the last checkpoint
|
||||
// It will handle all cases where the incoming chain has atleast one checkpoint
|
||||
for i := len(pastChain) - 1; i >= 0; i-- {
|
||||
if _, ok := w.checkpointWhitelist[pastChain[i].Number.Uint64()]; ok {
|
||||
return pastChain[i].Hash() == w.checkpointWhitelist[pastChain[i].Number.Uint64()], nil
|
||||
}
|
||||
milestoneBool, err := s.milestoneService.IsValidPeer(fetchHeadersByNumber)
|
||||
if !milestoneBool {
|
||||
return milestoneBool, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s *Service) PurgeWhitelistedCheckpoint() {
|
||||
s.checkpointService.Purge()
|
||||
}
|
||||
|
||||
func (s *Service) PurgeWhitelistedMilestone() {
|
||||
s.milestoneService.Purge()
|
||||
}
|
||||
|
||||
func (s *Service) GetWhitelistedCheckpoint() (bool, uint64, common.Hash) {
|
||||
return s.checkpointService.Get()
|
||||
}
|
||||
|
||||
func (s *Service) GetWhitelistedMilestone() (bool, uint64, common.Hash) {
|
||||
return s.milestoneService.Get()
|
||||
}
|
||||
|
||||
func (s *Service) ProcessMilestone(endBlockNum uint64, endBlockHash common.Hash) {
|
||||
s.milestoneService.Process(endBlockNum, endBlockHash)
|
||||
}
|
||||
|
||||
func (s *Service) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {
|
||||
s.checkpointService.Process(endBlockNum, endBlockHash)
|
||||
}
|
||||
|
||||
func (s *Service) IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error) {
|
||||
checkpointBool, err := s.checkpointService.IsValidChain(currentHeader, chain)
|
||||
if !checkpointBool {
|
||||
return checkpointBool, err
|
||||
}
|
||||
|
||||
milestoneBool, err := s.milestoneService.IsValidChain(currentHeader, chain)
|
||||
if !milestoneBool {
|
||||
return milestoneBool, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (s *Service) GetMilestoneIDsList() []string {
|
||||
return s.milestoneService.GetMilestoneIDsList()
|
||||
}
|
||||
|
||||
func splitChain(current uint64, chain []*types.Header) ([]*types.Header, []*types.Header) {
|
||||
var (
|
||||
pastChain []*types.Header
|
||||
futureChain []*types.Header
|
||||
first uint64 = chain[0].Number.Uint64()
|
||||
last uint64 = chain[len(chain)-1].Number.Uint64()
|
||||
first = chain[0].Number.Uint64()
|
||||
last = chain[len(chain)-1].Number.Uint64()
|
||||
)
|
||||
|
||||
if current >= first {
|
||||
|
|
@ -153,57 +168,68 @@ func splitChain(current uint64, chain []*types.Header) ([]*types.Header, []*type
|
|||
return pastChain, futureChain
|
||||
}
|
||||
|
||||
func (w *Service) ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash) {
|
||||
w.m.Lock()
|
||||
defer w.m.Unlock()
|
||||
//nolint:unparam
|
||||
func isValidChain(currentHeader *types.Header, chain []*types.Header, doExist bool, number uint64, hash common.Hash) (bool, error) {
|
||||
// Check if we have milestone to validate incoming chain in memory
|
||||
if !doExist {
|
||||
// We don't have any entry, no additional validation will be possible
|
||||
return true, nil
|
||||
}
|
||||
|
||||
w.enqueueCheckpointWhitelist(endBlockNum, endBlockHash)
|
||||
// If size of checkpoint whitelist map is greater than 10, remove the oldest entry.
|
||||
current := currentHeader.Number.Uint64()
|
||||
|
||||
if w.length() > int(w.maxCapacity) {
|
||||
w.dequeueCheckpointWhitelist()
|
||||
// Check if imported chain is less than whitelisted number
|
||||
if chain[len(chain)-1].Number.Uint64() < number {
|
||||
if current >= number { //If current tip of the chain is greater than whitelist number then return false
|
||||
return false, nil
|
||||
} else {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetCheckpointWhitelist returns the existing whitelisted
|
||||
// entries of checkpoint of the form block number -> block hash.
|
||||
func (w *Service) GetCheckpointWhitelist() map[uint64]common.Hash {
|
||||
w.m.Lock()
|
||||
defer w.m.Unlock()
|
||||
// Split the chain into past and future chain
|
||||
pastChain, _ := splitChain(current, chain)
|
||||
|
||||
return w.checkpointWhitelist
|
||||
}
|
||||
// Iterate over the chain and validate against the last milestone
|
||||
// It will handle all cases when the incoming chain has atleast one milestone
|
||||
for i := len(pastChain) - 1; i >= 0; i-- {
|
||||
if pastChain[i].Number.Uint64() == number {
|
||||
res := pastChain[i].Hash() == hash
|
||||
|
||||
// PurgeCheckpointWhitelist purges data from checkpoint whitelist map
|
||||
func (w *Service) PurgeCheckpointWhitelist() {
|
||||
w.m.Lock()
|
||||
defer w.m.Unlock()
|
||||
|
||||
w.checkpointWhitelist = make(map[uint64]common.Hash)
|
||||
w.checkpointOrder = make([]uint64, 0)
|
||||
}
|
||||
|
||||
// EnqueueWhitelistBlock enqueues blockNumber, blockHash to the checkpoint whitelist map
|
||||
func (w *Service) enqueueCheckpointWhitelist(key uint64, val common.Hash) {
|
||||
if _, ok := w.checkpointWhitelist[key]; !ok {
|
||||
log.Debug("Enqueing new checkpoint whitelist", "block number", key, "block hash", val)
|
||||
|
||||
w.checkpointWhitelist[key] = val
|
||||
w.checkpointOrder = append(w.checkpointOrder, key)
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
// DequeueWhitelistBlock dequeues block, blockhash from the checkpoint whitelist map
|
||||
func (w *Service) dequeueCheckpointWhitelist() {
|
||||
if len(w.checkpointOrder) > 0 {
|
||||
log.Debug("Dequeing checkpoint whitelist", "block number", w.checkpointOrder[0], "block hash", w.checkpointWhitelist[w.checkpointOrder[0]])
|
||||
|
||||
delete(w.checkpointWhitelist, w.checkpointOrder[0])
|
||||
w.checkpointOrder = w.checkpointOrder[1:] // fixme: this slice is growing infinitely and never will be released. also a panic is possible if the last element is going to be removed
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// length returns the len of the whitelist.
|
||||
func (w *Service) length() int {
|
||||
return len(w.checkpointWhitelist)
|
||||
// FIXME: remoteHeader is not used
|
||||
func isValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error), doExist bool, number uint64, hash common.Hash) (bool, error) {
|
||||
// Check for availaibility of the last milestone block.
|
||||
// This can be also be empty if our heimdall is not responding
|
||||
// or we're running without it.
|
||||
if !doExist {
|
||||
// worst case, we don't have the milestone in memory
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// todo: we can extract this as an interface and mock as well or just test IsValidChain in isolation from downloader passing fake fetchHeadersByNumber functions
|
||||
headers, hashes, err := fetchHeadersByNumber(number, 1, 0, false)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("%w: last whitelisted block number %d, err %v", ErrNoRemote, number, err)
|
||||
}
|
||||
|
||||
if len(headers) == 0 {
|
||||
return false, fmt.Errorf("%w: last whitlisted block number %d", ErrNoRemote, number)
|
||||
}
|
||||
|
||||
reqBlockNum := headers[0].Number.Uint64()
|
||||
reqBlockHash := hashes[0]
|
||||
|
||||
// Check against the whitelisted blocks
|
||||
if reqBlockNum == number && reqBlockHash == hash {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, ErrMismatch
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// nolint
|
||||
package whitelist
|
||||
|
||||
import (
|
||||
|
|
@ -9,35 +10,243 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"pgregory.net/rapid"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
)
|
||||
|
||||
// NewMockService creates a new mock whitelist service
|
||||
func NewMockService(maxCapacity uint, checkpointInterval uint64) *Service {
|
||||
func NewMockService(db ethdb.Database) *Service {
|
||||
return &Service{
|
||||
checkpointWhitelist: make(map[uint64]common.Hash),
|
||||
checkpointOrder: []uint64{},
|
||||
maxCapacity: maxCapacity,
|
||||
checkpointInterval: checkpointInterval,
|
||||
|
||||
&checkpoint{
|
||||
finality[*rawdb.Checkpoint]{
|
||||
doExist: false,
|
||||
interval: 256,
|
||||
db: db,
|
||||
},
|
||||
},
|
||||
|
||||
&milestone{
|
||||
finality: finality[*rawdb.Milestone]{
|
||||
doExist: false,
|
||||
interval: 256,
|
||||
db: db,
|
||||
},
|
||||
LockedMilestoneIDs: make(map[string]struct{}),
|
||||
FutureMilestoneList: make(map[uint64]common.Hash),
|
||||
FutureMilestoneOrder: make([]uint64, 0),
|
||||
MaxCapacity: 10,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TestWhitelistCheckpoint checks the checkpoint whitelist map queue mechanism
|
||||
func TestWhitelistCheckpoint(t *testing.T) {
|
||||
// TestWhitelistCheckpoint checks the checkpoint whitelist setter and getter functions.
|
||||
func TestWhitelistedCheckpoint(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := NewMockService(10, 10)
|
||||
for i := 0; i < 10; i++ {
|
||||
s.enqueueCheckpointWhitelist(uint64(i), common.Hash{})
|
||||
}
|
||||
require.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
|
||||
s.enqueueCheckpointWhitelist(11, common.Hash{})
|
||||
s.dequeueCheckpointWhitelist()
|
||||
require.Equal(t, s.length(), 10, "expected 10 items in whitelist")
|
||||
//Creating the service for the whitelisting the checkpoints
|
||||
s := NewMockService(db)
|
||||
|
||||
cp := s.checkpointService.(*checkpoint)
|
||||
|
||||
require.Equal(t, cp.doExist, false, "expected false as no cp exist at this point")
|
||||
|
||||
_, _, err := rawdb.ReadFinality[*rawdb.Checkpoint](db)
|
||||
require.NotNil(t, err, "Error should be nil while reading from the db")
|
||||
|
||||
//Adding the checkpoint
|
||||
s.ProcessCheckpoint(11, common.Hash{})
|
||||
|
||||
require.Equal(t, cp.doExist, true, "expected true as cp exist")
|
||||
|
||||
//Removing the checkpoint
|
||||
s.PurgeWhitelistedCheckpoint()
|
||||
|
||||
require.Equal(t, cp.doExist, false, "expected false as no cp exist at this point")
|
||||
|
||||
//Adding the checkpoint
|
||||
s.ProcessCheckpoint(12, common.Hash{1})
|
||||
|
||||
//Receiving the stored checkpoint
|
||||
doExist, number, hash := s.GetWhitelistedCheckpoint()
|
||||
|
||||
//Validating the values received
|
||||
require.Equal(t, doExist, true, "expected true ascheckpoint exist at this point")
|
||||
require.Equal(t, number, uint64(12), "expected number to be 11 but got", number)
|
||||
require.Equal(t, hash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||
require.NotEqual(t, hash, common.Hash{}, "expected the hash to be different from zero hash")
|
||||
|
||||
c1 := s.checkpointService.(*checkpoint)
|
||||
fmt.Println("!!!-0", c1.doExist)
|
||||
s.PurgeWhitelistedCheckpoint()
|
||||
fmt.Println("!!!-1", c1.doExist)
|
||||
doExist, number, hash = s.GetWhitelistedCheckpoint()
|
||||
fmt.Println("!!!-2", c1.doExist)
|
||||
//Validating the values received from the db, not memory
|
||||
require.Equal(t, doExist, true, "expected true ascheckpoint exist at this point")
|
||||
require.Equal(t, number, uint64(12), "expected number to be 11 but got", number)
|
||||
require.Equal(t, hash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||
require.NotEqual(t, hash, common.Hash{}, "expected the hash to be different from zero hash")
|
||||
|
||||
checkpointNumber, checkpointHash, err := rawdb.ReadFinality[*rawdb.Checkpoint](db)
|
||||
require.Nil(t, err, "Error should be nil while reading from the db")
|
||||
require.Equal(t, checkpointHash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||
require.Equal(t, checkpointNumber, uint64(12), "expected number to be 11 but got", number)
|
||||
}
|
||||
|
||||
// TestMilestone checks the milestone whitelist setter and getter functions
|
||||
func TestMilestone(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
s := NewMockService(db)
|
||||
|
||||
milestone := s.milestoneService.(*milestone)
|
||||
|
||||
//Checking for the variables when no milestone is Processed
|
||||
require.Equal(t, milestone.doExist, false, "expected false as no milestone exist at this point")
|
||||
require.Equal(t, milestone.Locked, false, "expected false as it was not locked")
|
||||
require.Equal(t, milestone.LockedMilestoneNumber, uint64(0), "expected 0 as it was not initialized")
|
||||
|
||||
_, _, err := rawdb.ReadFinality[*rawdb.Milestone](db)
|
||||
require.NotNil(t, err, "Error should be nil while reading from the db")
|
||||
|
||||
//Acquiring the mutex lock
|
||||
milestone.LockMutex(11)
|
||||
require.Equal(t, milestone.Locked, false, "expected false as sprint is not locked till this point")
|
||||
|
||||
//Releasing the mutex lock
|
||||
milestone.UnlockMutex(true, "milestoneID1", uint64(11), common.Hash{})
|
||||
require.Equal(t, milestone.LockedMilestoneNumber, uint64(11), "expected 11 as it was not initialized")
|
||||
require.Equal(t, milestone.Locked, true, "expected true as sprint is locked now")
|
||||
require.Equal(t, len(milestone.LockedMilestoneIDs), 1, "expected 1 as only 1 milestoneID has been entered")
|
||||
|
||||
_, ok := milestone.LockedMilestoneIDs["milestoneID1"]
|
||||
require.True(t, ok, "milestoneID1 should exist in the LockedMilestoneIDs map")
|
||||
|
||||
_, ok = milestone.LockedMilestoneIDs["milestoneID2"]
|
||||
require.False(t, ok, "milestoneID2 shouldn't exist in the LockedMilestoneIDs map")
|
||||
|
||||
milestone.LockMutex(11)
|
||||
milestone.UnlockMutex(true, "milestoneID2", uint64(11), common.Hash{})
|
||||
require.Equal(t, len(milestone.LockedMilestoneIDs), 1, "expected 1 as only 1 milestoneID has been entered")
|
||||
|
||||
_, ok = milestone.LockedMilestoneIDs["milestoneID2"]
|
||||
require.True(t, ok, "milestoneID2 should exist in the LockedMilestoneIDs map")
|
||||
|
||||
milestone.RemoveMilestoneID("milestoneID1")
|
||||
require.Equal(t, len(milestone.LockedMilestoneIDs), 1, "expected 1 as one out of two has been removed in previous step")
|
||||
require.Equal(t, milestone.Locked, true, "expected true as sprint is locked now")
|
||||
|
||||
milestone.RemoveMilestoneID("milestoneID2")
|
||||
require.Equal(t, len(milestone.LockedMilestoneIDs), 0, "expected 1 as both the milestonesIDs has been removed in previous step")
|
||||
require.Equal(t, milestone.Locked, false, "expected false")
|
||||
|
||||
milestone.LockMutex(11)
|
||||
milestone.UnlockMutex(true, "milestoneID3", uint64(11), common.Hash{})
|
||||
require.True(t, milestone.Locked, "expected true")
|
||||
require.Equal(t, milestone.LockedMilestoneNumber, uint64(11), "Expected 11")
|
||||
|
||||
milestone.LockMutex(15)
|
||||
require.True(t, milestone.Locked, "expected true")
|
||||
require.Equal(t, milestone.LockedMilestoneNumber, uint64(11), "Expected 11")
|
||||
milestone.UnlockMutex(true, "milestoneID4", uint64(15), common.Hash{})
|
||||
require.True(t, milestone.Locked, "expected true as final confirmation regarding the lock has been made")
|
||||
require.Equal(t, len(milestone.LockedMilestoneIDs), 1, "expected 1 as previous milestonesIDs has been removed in previous step")
|
||||
|
||||
//Adding the milestone
|
||||
s.ProcessMilestone(11, common.Hash{})
|
||||
|
||||
require.True(t, milestone.Locked, "expected true as locked sprint is of number 15")
|
||||
require.Equal(t, milestone.doExist, true, "expected true as milestone exist")
|
||||
require.Equal(t, len(milestone.LockedMilestoneIDs), 1, "expected 1 as still last milestone of sprint number 15 exist")
|
||||
|
||||
//Reading from the Db
|
||||
locked, lockedMilestoneNumber, lockedMilestoneHash, lockedMilestoneIDs, err := rawdb.ReadLockField(db)
|
||||
|
||||
require.Nil(t, err)
|
||||
require.True(t, locked, "expected true as locked sprint is of number 15")
|
||||
require.Equal(t, lockedMilestoneNumber, uint64(15), "Expected 15")
|
||||
require.Equal(t, lockedMilestoneHash, common.Hash{}, "Expected", common.Hash{})
|
||||
require.Equal(t, len(lockedMilestoneIDs), 1, "expected 1 as still last milestone of sprint number 15 exist")
|
||||
|
||||
_, ok = lockedMilestoneIDs["milestoneID4"]
|
||||
require.True(t, ok, "expected true as milestoneIDList should contain 'milestoneID4'")
|
||||
|
||||
//Asking the lock for sprintNumber less than last whitelisted milestone
|
||||
require.False(t, milestone.LockMutex(11), "Cant lock the sprintNumber less than equal to latest whitelisted milestone")
|
||||
milestone.UnlockMutex(false, "", uint64(11), common.Hash{}) //Unlock is required after every lock to release the mutex
|
||||
|
||||
//Adding the milestone
|
||||
s.ProcessMilestone(51, common.Hash{})
|
||||
require.False(t, milestone.Locked, "expected false as lock from sprint number 15 is removed")
|
||||
require.Equal(t, milestone.doExist, true, "expected true as milestone exist")
|
||||
require.Equal(t, len(milestone.LockedMilestoneIDs), 0, "expected 0 as all the milestones have been removed")
|
||||
|
||||
//Reading from the Db
|
||||
locked, _, _, lockedMilestoneIDs, err = rawdb.ReadLockField(db)
|
||||
|
||||
require.Nil(t, err)
|
||||
require.False(t, locked, "expected true as locked sprint is of number 15")
|
||||
require.Equal(t, len(lockedMilestoneIDs), 0, "expected 0 as milestoneID exist in the map")
|
||||
|
||||
//Removing the milestone
|
||||
s.PurgeWhitelistedMilestone()
|
||||
|
||||
require.Equal(t, milestone.doExist, false, "expected false as no milestone exist at this point")
|
||||
|
||||
//Removing the milestone
|
||||
s.ProcessMilestone(11, common.Hash{1})
|
||||
|
||||
doExist, number, hash := s.GetWhitelistedMilestone()
|
||||
|
||||
//validating the values received
|
||||
require.Equal(t, doExist, true, "expected true as milestone exist at this point")
|
||||
require.Equal(t, number, uint64(11), "expected number to be 11 but got", number)
|
||||
require.Equal(t, hash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||
|
||||
s.PurgeWhitelistedMilestone()
|
||||
doExist, number, hash = s.GetWhitelistedMilestone()
|
||||
|
||||
//Validating the values received from the db, not memory
|
||||
require.Equal(t, doExist, true, "expected true as milestone exist at this point")
|
||||
require.Equal(t, number, uint64(11), "expected number to be 11 but got", number)
|
||||
require.Equal(t, hash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||
|
||||
milestoneNumber, milestoneHash, err := rawdb.ReadFinality[*rawdb.Milestone](db)
|
||||
require.Nil(t, err, "Error should be nil while reading from the db")
|
||||
require.Equal(t, milestoneHash, common.Hash{1}, "expected the 1 hash but got", hash)
|
||||
require.Equal(t, milestoneNumber, uint64(11), "expected number to be 11 but got", number)
|
||||
|
||||
_, _, err = rawdb.ReadFutureMilestoneList(db)
|
||||
require.NotNil(t, err, "Error should be not nil")
|
||||
|
||||
s.ProcessFutureMilestone(16, common.Hash{16})
|
||||
require.Equal(t, len(milestone.FutureMilestoneOrder), 1, "expected length is 1 as we added only 1 future milestone")
|
||||
require.Equal(t, milestone.FutureMilestoneOrder[0], uint64(16), "expected value is 16 but got", milestone.FutureMilestoneOrder[0])
|
||||
require.Equal(t, milestone.FutureMilestoneList[16], common.Hash{16}, "expected value is", common.Hash{16}.String()[2:], "but got", milestone.FutureMilestoneList[16])
|
||||
|
||||
order, list, err := rawdb.ReadFutureMilestoneList(db)
|
||||
require.Nil(t, err, "Error should be nil while reading from the db")
|
||||
require.Equal(t, len(order), 1, "expected the 1 hash but got", len(order))
|
||||
require.Equal(t, order[0], uint64(16), "expected number to be 16 but got", order[0])
|
||||
require.Equal(t, list[order[0]], common.Hash{16}, "expected value is", common.Hash{16}.String()[2:], "but got", list[order[0]])
|
||||
|
||||
capicity := milestone.MaxCapacity
|
||||
for i := 16; i <= 16*(capicity+1); i = i + 16 {
|
||||
s.ProcessFutureMilestone(uint64(i), common.Hash{16})
|
||||
}
|
||||
|
||||
require.Equal(t, len(milestone.FutureMilestoneOrder), capicity, "expected length is", capicity)
|
||||
require.Equal(t, milestone.FutureMilestoneOrder[capicity-1], uint64(16*capicity), "expected value is", uint64(16*capicity), "but got", milestone.FutureMilestoneOrder[capicity-1])
|
||||
}
|
||||
|
||||
// TestIsValidPeer checks the IsValidPeer function in isolation
|
||||
|
|
@ -45,18 +254,26 @@ func TestWhitelistCheckpoint(t *testing.T) {
|
|||
func TestIsValidPeer(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := NewMockService(10, 10)
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
s := NewMockService(db)
|
||||
|
||||
// case1: no checkpoint whitelist, should consider the chain as valid
|
||||
res, err := s.IsValidPeer(nil, nil)
|
||||
res, err := s.IsValidPeer(nil)
|
||||
require.NoError(t, err, "expected no error")
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
|
||||
// add checkpoint entries and mock fetchHeadersByNumber function
|
||||
s.ProcessCheckpoint(uint64(0), common.Hash{})
|
||||
// add checkpoint entry and mock fetchHeadersByNumber function
|
||||
s.ProcessCheckpoint(uint64(1), common.Hash{})
|
||||
|
||||
require.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
||||
// add milestone entry and mock fetchHeadersByNumber function
|
||||
s.ProcessMilestone(uint64(1), common.Hash{})
|
||||
|
||||
checkpoint := s.checkpointService.(*checkpoint)
|
||||
milestone := s.milestoneService.(*milestone)
|
||||
|
||||
//Check whether the milestone and checkpoint exist
|
||||
require.Equal(t, checkpoint.doExist, true, "expected true as checkpoint exists")
|
||||
require.Equal(t, milestone.doExist, true, "expected true as milestone exists")
|
||||
|
||||
// create a false function, returning absolutely nothing
|
||||
falseFetchHeadersByNumber := func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error) {
|
||||
|
|
@ -64,20 +281,19 @@ func TestIsValidPeer(t *testing.T) {
|
|||
}
|
||||
|
||||
// case2: false fetchHeadersByNumber function provided, should consider the chain as invalid
|
||||
// and throw `ErrNoRemoteCheckpoint` error
|
||||
res, err = s.IsValidPeer(nil, falseFetchHeadersByNumber)
|
||||
// and throw `ErrNoRemoteCheckoint` error
|
||||
res, err = s.IsValidPeer(falseFetchHeadersByNumber)
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
|
||||
if !errors.Is(err, ErrNoRemoteCheckpoint) {
|
||||
t.Fatalf("expected error ErrNoRemoteCheckpoint, got %v", err)
|
||||
if !errors.Is(err, ErrNoRemote) {
|
||||
t.Fatalf("expected error ErrNoRemote, got %v", err)
|
||||
}
|
||||
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
require.Equal(t, res, false, "expected peer chain to be invalid")
|
||||
|
||||
// case3: correct fetchHeadersByNumber function provided, should consider the chain as valid
|
||||
// create a mock function, returning a the required header
|
||||
// create a mock function, returning the required header
|
||||
fetchHeadersByNumber := func(number uint64, _ int, _ int, _ bool) ([]*types.Header, []common.Hash, error) {
|
||||
hash := common.Hash{}
|
||||
header := types.Header{Number: big.NewInt(0)}
|
||||
|
|
@ -96,18 +312,124 @@ func TestIsValidPeer(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
res, err = s.IsValidPeer(nil, fetchHeadersByNumber)
|
||||
// case3: correct fetchHeadersByNumber function provided, should consider the chain as valid
|
||||
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||
require.NoError(t, err, "expected no error")
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
|
||||
// add one more checkpoint whitelist entry
|
||||
// add checkpoint whitelist entry
|
||||
s.ProcessCheckpoint(uint64(2), common.Hash{})
|
||||
require.Equal(t, s.length(), 3, "expected 3 items in whitelist")
|
||||
require.Equal(t, checkpoint.doExist, true, "expected true as checkpoint exists")
|
||||
|
||||
// case4: correct fetchHeadersByNumber function provided with wrong header
|
||||
// for block number 2. Should consider the chain as invalid and throw an error
|
||||
res, err = s.IsValidPeer(nil, fetchHeadersByNumber)
|
||||
require.Equal(t, err, ErrCheckpointMismatch, "expected checkpoint mismatch error")
|
||||
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||
require.Equal(t, err, ErrMismatch, "expected mismatch error")
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
|
||||
// create a mock function, returning the required header
|
||||
fetchHeadersByNumber = func(number uint64, _ int, _ int, _ bool) ([]*types.Header, []common.Hash, error) {
|
||||
hash := common.Hash{}
|
||||
header := types.Header{Number: big.NewInt(0)}
|
||||
|
||||
switch number {
|
||||
case 0:
|
||||
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||
case 1:
|
||||
header.Number = big.NewInt(1)
|
||||
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||
case 2:
|
||||
header.Number = big.NewInt(2)
|
||||
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||
|
||||
case 3:
|
||||
header.Number = big.NewInt(3)
|
||||
hash3 := common.Hash{3}
|
||||
|
||||
return []*types.Header{&header}, []common.Hash{hash3}, nil
|
||||
|
||||
default:
|
||||
return nil, nil, errors.New("invalid number")
|
||||
}
|
||||
}
|
||||
|
||||
s.ProcessMilestone(uint64(3), common.Hash{})
|
||||
|
||||
//Case5: correct fetchHeadersByNumber function provided with hash mismatch, should consider the chain as invalid
|
||||
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||
require.Equal(t, err, ErrMismatch, "expected milestone mismatch error")
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
|
||||
s.ProcessMilestone(uint64(2), common.Hash{})
|
||||
|
||||
// create a mock function, returning the required header
|
||||
fetchHeadersByNumber = func(number uint64, _ int, _ int, _ bool) ([]*types.Header, []common.Hash, error) {
|
||||
hash := common.Hash{}
|
||||
header := types.Header{Number: big.NewInt(0)}
|
||||
|
||||
switch number {
|
||||
case 0:
|
||||
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||
case 1:
|
||||
header.Number = big.NewInt(1)
|
||||
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||
case 2:
|
||||
header.Number = big.NewInt(2)
|
||||
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||
default:
|
||||
return nil, nil, errors.New("invalid number")
|
||||
}
|
||||
}
|
||||
|
||||
// case6: correct fetchHeadersByNumber function provided, should consider the chain as valid
|
||||
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||
require.NoError(t, err, "expected no error")
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
|
||||
// create a mock function, returning the required header
|
||||
fetchHeadersByNumber = func(number uint64, _ int, _ int, _ bool) ([]*types.Header, []common.Hash, error) {
|
||||
hash := common.Hash{}
|
||||
hash3 := common.Hash{3}
|
||||
header := types.Header{Number: big.NewInt(0)}
|
||||
|
||||
switch number {
|
||||
case 0:
|
||||
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||
case 1:
|
||||
header.Number = big.NewInt(1)
|
||||
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||
case 2:
|
||||
header.Number = big.NewInt(2)
|
||||
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||
|
||||
case 3:
|
||||
header.Number = big.NewInt(2) // sending wrong header for misamatch
|
||||
return []*types.Header{&header}, []common.Hash{hash}, nil
|
||||
|
||||
case 4:
|
||||
header.Number = big.NewInt(4) // sending wrong header for misamatch
|
||||
return []*types.Header{&header}, []common.Hash{hash3}, nil
|
||||
default:
|
||||
return nil, nil, errors.New("invalid number")
|
||||
}
|
||||
}
|
||||
|
||||
//Add one more milestone in the list
|
||||
s.ProcessMilestone(uint64(3), common.Hash{})
|
||||
|
||||
// case7: correct fetchHeadersByNumber function provided with wrong header for block 3, should consider the chain as invalid
|
||||
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||
require.Equal(t, err, ErrMismatch, "expected milestone mismatch error")
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
|
||||
//require.Equal(t, milestone.length(), 3, "expected 3 items in milestoneList")
|
||||
|
||||
//Add one more milestone in the list
|
||||
s.ProcessMilestone(uint64(4), common.Hash{})
|
||||
|
||||
// case8: correct fetchHeadersByNumber function provided with wrong hash for block 3, should consider the chain as valid
|
||||
res, err = s.IsValidPeer(fetchHeadersByNumber)
|
||||
require.Equal(t, err, ErrMismatch, "expected milestone mismatch error")
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
}
|
||||
|
||||
|
|
@ -116,71 +438,479 @@ func TestIsValidPeer(t *testing.T) {
|
|||
func TestIsValidChain(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := NewMockService(10, 10)
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
s := NewMockService(db)
|
||||
chainA := createMockChain(1, 20) // A1->A2...A19->A20
|
||||
// case1: no checkpoint whitelist, should consider the chain as valid
|
||||
|
||||
//Case1: no checkpoint whitelist and no milestone and no locking, should consider the chain as valid
|
||||
res, err := s.IsValidChain(nil, chainA)
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
require.Equal(t, err, nil, "expected error to be nil")
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "Expected chain to be valid")
|
||||
|
||||
tempChain := createMockChain(21, 22) // A21->A22
|
||||
|
||||
// add mock checkpoint entries
|
||||
s.ProcessCheckpoint(tempChain[0].Number.Uint64(), tempChain[0].Hash())
|
||||
// add mock checkpoint entry
|
||||
s.ProcessCheckpoint(tempChain[1].Number.Uint64(), tempChain[1].Hash())
|
||||
|
||||
require.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
||||
//Make the mock chain with zero blocks
|
||||
zeroChain := make([]*types.Header, 0)
|
||||
|
||||
// case2: We're behind the oldest whitelisted block entry, should consider
|
||||
// the chain as valid as we're still far behind the latest blocks
|
||||
//Case2: As input chain is of zero length,should consider the chain as invalid
|
||||
res, err = s.IsValidChain(nil, zeroChain)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid", len(zeroChain))
|
||||
|
||||
//Case3A: As the received chain and current tip of local chain is behind the oldest whitelisted block entry, should consider
|
||||
// the chain as valid
|
||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
require.Equal(t, err, nil, "expected error to be nil")
|
||||
|
||||
// Clear checkpoint whitelist and add blocks A5 and A15 in whitelist
|
||||
s.PurgeCheckpointWhitelist()
|
||||
s.ProcessCheckpoint(chainA[5].Number.Uint64(), chainA[5].Hash())
|
||||
//Case3B: As the received chain is behind the oldest whitelisted block entry,but current tip is at par with whitelisted checkpoint, should consider
|
||||
// the chain as invalid
|
||||
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid ")
|
||||
|
||||
// add mock milestone entry
|
||||
s.ProcessMilestone(tempChain[1].Number.Uint64(), tempChain[1].Hash())
|
||||
|
||||
//Case4A: As the received chain and current tip of local chain is behind the oldest whitelisted block entry, should consider
|
||||
// the chain as valid
|
||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
|
||||
//Case4B: As the received chain is behind the oldest whitelisted block entry and but current tip is at par with whitelisted milestine, should consider
|
||||
// the chain as invalid
|
||||
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
|
||||
//Remove the whitelisted checkpoint
|
||||
s.PurgeWhitelistedCheckpoint()
|
||||
|
||||
//Case5: As the received chain is still invalid after removing the checkpoint as it is
|
||||
//still behind the whitelisted milestone
|
||||
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
|
||||
//Remove the whitelisted milestone
|
||||
s.PurgeWhitelistedMilestone()
|
||||
|
||||
//At this stage there is no whitelisted milestone and checkpoint
|
||||
|
||||
checkpoint := s.checkpointService.(*checkpoint)
|
||||
milestone := s.milestoneService.(*milestone)
|
||||
|
||||
//Locking for sprintNumber 15
|
||||
milestone.LockMutex(chainA[len(chainA)-5].Number.Uint64())
|
||||
milestone.UnlockMutex(true, "MilestoneID1", chainA[len(chainA)-5].Number.Uint64(), chainA[len(chainA)-5].Hash())
|
||||
|
||||
//Case6: As the received chain is valid as the locked sprintHash matches with the incoming chain.
|
||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be valid as incoming chain matches with the locked value ")
|
||||
|
||||
hash3 := common.Hash{3}
|
||||
|
||||
//Locking for sprintNumber 16 with different hash
|
||||
milestone.LockMutex(chainA[len(chainA)-4].Number.Uint64())
|
||||
milestone.UnlockMutex(true, "MilestoneID2", chainA[len(chainA)-4].Number.Uint64(), hash3)
|
||||
|
||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid as incoming chain does match with the locked value hash ")
|
||||
|
||||
//Locking for sprintNumber 19
|
||||
milestone.LockMutex(chainA[len(chainA)-1].Number.Uint64())
|
||||
milestone.UnlockMutex(true, "MilestoneID1", chainA[len(chainA)-1].Number.Uint64(), chainA[len(chainA)-1].Hash())
|
||||
|
||||
//Case7: As the received chain is valid as the locked sprintHash matches with the incoming chain.
|
||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid as incoming chain is less than the locked value ")
|
||||
|
||||
//Locking for sprintNumber 19
|
||||
milestone.LockMutex(uint64(21))
|
||||
milestone.UnlockMutex(true, "MilestoneID1", uint64(21), hash3)
|
||||
|
||||
//Case8: As the received chain is invalid as the locked sprintHash matches is ahead of incoming chain.
|
||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid as incoming chain is less than the locked value ")
|
||||
|
||||
//Unlocking the sprint
|
||||
milestone.UnlockSprint(uint64(21))
|
||||
|
||||
// Clear checkpoint whitelist and add block A15 in whitelist
|
||||
s.PurgeWhitelistedCheckpoint()
|
||||
s.ProcessCheckpoint(chainA[15].Number.Uint64(), chainA[15].Hash())
|
||||
|
||||
require.Equal(t, s.length(), 2, "expected 2 items in whitelist")
|
||||
require.Equal(t, checkpoint.doExist, true, "expected true as checkpoint exists.")
|
||||
|
||||
// case3: Try importing a past chain having valid checkpoint, should
|
||||
// consider the chain as valid
|
||||
// case9: As the received chain is having valid checkpoint,should consider the chain as valid.
|
||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
|
||||
// add mock milestone entries
|
||||
s.ProcessMilestone(tempChain[1].Number.Uint64(), tempChain[1].Hash())
|
||||
|
||||
// case10: Try importing a past chain having valid checkpoint, should
|
||||
// consider the chain as invalid as still lastest milestone is ahead of the chain.
|
||||
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
|
||||
// add mock milestone entries
|
||||
s.ProcessMilestone(chainA[19].Number.Uint64(), chainA[19].Hash())
|
||||
|
||||
// case12: Try importing a chain having valid checkpoint and milestone, should
|
||||
// consider the chain as valid
|
||||
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be invalid")
|
||||
|
||||
// add mock milestone entries
|
||||
s.ProcessMilestone(chainA[19].Number.Uint64(), chainA[19].Hash())
|
||||
|
||||
// case13: Try importing a past chain having valid checkpoint and milestone, should
|
||||
// consider the chain as valid
|
||||
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
|
||||
// add mock milestone entries with wrong hash
|
||||
s.ProcessMilestone(chainA[19].Number.Uint64(), chainA[18].Hash())
|
||||
|
||||
// case14: Try importing a past chain having valid checkpoint and milestone with wrong hash, should
|
||||
// consider the chain as invalid
|
||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid as hash mismatches")
|
||||
|
||||
// Clear milestone and add blocks A15 in whitelist
|
||||
s.ProcessMilestone(chainA[15].Number.Uint64(), chainA[15].Hash())
|
||||
|
||||
// case16: Try importing a past chain having valid checkpoint, should
|
||||
// consider the chain as valid
|
||||
res, err = s.IsValidChain(tempChain[1], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
require.Equal(t, err, nil, "expected error to be nil")
|
||||
|
||||
// Clear checkpoint whitelist and mock blocks in whitelist
|
||||
tempChain = createMockChain(20, 20) // A20
|
||||
|
||||
s.PurgeCheckpointWhitelist()
|
||||
s.PurgeWhitelistedCheckpoint()
|
||||
s.ProcessCheckpoint(tempChain[0].Number.Uint64(), tempChain[0].Hash())
|
||||
|
||||
require.Equal(t, s.length(), 1, "expected 1 items in whitelist")
|
||||
require.Equal(t, checkpoint.doExist, true, "expected true")
|
||||
|
||||
// case4: Try importing a past chain having invalid checkpoint
|
||||
res, _ = s.IsValidChain(chainA[len(chainA)-1], chainA)
|
||||
// case17: Try importing a past chain having invalid checkpoint,should consider the chain as invalid
|
||||
res, err = s.IsValidChain(tempChain[0], chainA)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
// Not checking error here because we return nil in case of checkpoint mismatch
|
||||
|
||||
// case18: Try importing a future chain but within interval, should consider the chain as valid
|
||||
res, err = s.IsValidChain(tempChain[len(tempChain)-1], tempChain)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be invalid")
|
||||
|
||||
// create a future chain to be imported of length <= `checkpointInterval`
|
||||
chainB := createMockChain(21, 30) // B21->B22...B29->B30
|
||||
|
||||
// case5: Try importing a future chain (1)
|
||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainB)
|
||||
// case19: Try importing a future chain of acceptable length,should consider the chain as valid
|
||||
res, err = s.IsValidChain(tempChain[0], chainB)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
require.Equal(t, err, nil, "expected error to be nil")
|
||||
|
||||
// create a future chain to be imported of length > `checkpointInterval`
|
||||
chainB = createMockChain(21, 40) // C21->C22...C39->C40
|
||||
s.PurgeWhitelistedCheckpoint()
|
||||
s.PurgeWhitelistedMilestone()
|
||||
|
||||
// Note: Earlier, it used to reject future chains longer than some threshold.
|
||||
// That check is removed for now.
|
||||
chainB = createMockChain(21, 29) // C21->C22....C29
|
||||
|
||||
// case6: Try importing a future chain (2)
|
||||
res, err = s.IsValidChain(chainA[len(chainA)-1], chainB)
|
||||
s.milestoneService.ProcessFutureMilestone(29, chainB[8].Hash())
|
||||
|
||||
// case20: Try importing a future chain which match the future milestone should the chain as valid
|
||||
res, err = s.IsValidChain(tempChain[0], chainB)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
require.Equal(t, err, nil, "expected error to be nil")
|
||||
|
||||
chainB = createMockChain(21, 27) // C21->C22...C39->C40...C->256
|
||||
|
||||
// case21: Try importing a chain whose end point is less than future milestone
|
||||
res, err = s.IsValidChain(tempChain[0], chainB)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be valid")
|
||||
|
||||
chainB = createMockChain(30, 39) // C21->C22...C39->C40...C->256
|
||||
|
||||
//Processing wrong hash
|
||||
s.milestoneService.ProcessFutureMilestone(38, chainB[9].Hash())
|
||||
|
||||
// case22: Try importing a future chain with mismatch future milestone
|
||||
res, err = s.IsValidChain(tempChain[0], chainB)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, false, "expected chain to be invalid")
|
||||
|
||||
chainB = createMockChain(40, 49) // C40->C41...C48->C49
|
||||
|
||||
// case23: Try importing a future chain whose starting point is ahead of latest future milestone
|
||||
res, err = s.IsValidChain(tempChain[0], chainB)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, res, true, "expected chain to be invalid")
|
||||
|
||||
}
|
||||
|
||||
func TestPropertyBasedTestingMilestone(t *testing.T) {
|
||||
rapid.Check(t, func(t *rapid.T) {
|
||||
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
|
||||
milestone := milestone{
|
||||
finality: finality[*rawdb.Milestone]{
|
||||
doExist: false,
|
||||
Number: 0,
|
||||
Hash: common.Hash{},
|
||||
interval: 256,
|
||||
db: db,
|
||||
},
|
||||
|
||||
Locked: false,
|
||||
LockedMilestoneNumber: 0,
|
||||
LockedMilestoneHash: common.Hash{},
|
||||
LockedMilestoneIDs: make(map[string]struct{}),
|
||||
FutureMilestoneList: make(map[uint64]common.Hash),
|
||||
FutureMilestoneOrder: make([]uint64, 0),
|
||||
MaxCapacity: 10,
|
||||
}
|
||||
|
||||
var (
|
||||
milestoneEndNum = rapid.Uint64().Draw(t, "endBlock")
|
||||
milestoneID = rapid.String().Draw(t, "MilestoneID")
|
||||
doLock = rapid.Bool().Draw(t, "Voted")
|
||||
)
|
||||
|
||||
val := milestone.LockMutex(milestoneEndNum.(uint64))
|
||||
if !val {
|
||||
t.Error("LockMutex need to return true when there is no whitelisted milestone and locked milestone")
|
||||
}
|
||||
|
||||
milestone.UnlockMutex(doLock.(bool), milestoneID.(string), milestoneEndNum.(uint64), common.Hash{})
|
||||
|
||||
if doLock.(bool) {
|
||||
//Milestone should not be whitelisted
|
||||
if milestone.doExist {
|
||||
t.Error("Milestone is not expected to be whitelisted")
|
||||
}
|
||||
|
||||
//Local chain should be locked
|
||||
if !milestone.Locked {
|
||||
t.Error("Milestone is expected to be locked at", milestoneEndNum.(uint64))
|
||||
}
|
||||
|
||||
if milestone.LockedMilestoneNumber != milestoneEndNum.(uint64) {
|
||||
t.Error("Locked milestone number is expected to be", milestoneEndNum.(uint64))
|
||||
}
|
||||
|
||||
if len(milestone.LockedMilestoneIDs) != 1 {
|
||||
t.Error("List should contain 1 milestone")
|
||||
}
|
||||
|
||||
_, ok := milestone.LockedMilestoneIDs[milestoneID.(string)]
|
||||
|
||||
if !ok {
|
||||
t.Error("List doesn't contain correct milestoneID")
|
||||
}
|
||||
}
|
||||
|
||||
if !doLock.(bool) {
|
||||
if milestone.doExist {
|
||||
t.Error("Milestone is not expected to be whitelisted")
|
||||
}
|
||||
|
||||
if milestone.Locked {
|
||||
t.Error("Milestone is expected not to be locked")
|
||||
}
|
||||
|
||||
if milestone.LockedMilestoneNumber != 0 {
|
||||
t.Error("Locked milestone number is expected to be", 0)
|
||||
}
|
||||
|
||||
if len(milestone.LockedMilestoneIDs) != 0 {
|
||||
t.Error("List should not contain milestone")
|
||||
}
|
||||
|
||||
_, ok := milestone.LockedMilestoneIDs[milestoneID.(string)]
|
||||
|
||||
if ok {
|
||||
t.Error("List shouldn't contain any milestoneID")
|
||||
}
|
||||
}
|
||||
|
||||
fitlerFn := func(i uint64) bool {
|
||||
if i <= uint64(1000) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
start = rapid.Uint64Max(milestoneEndNum.(uint64)).Draw(t, "start for mock chain")
|
||||
end = rapid.Uint64Min(start.(uint64)).Filter(fitlerFn).Draw(t, "end for mock chain")
|
||||
)
|
||||
|
||||
chainTemp := createMockChain(start.(uint64), end.(uint64))
|
||||
|
||||
val, err := milestone.IsValidChain(chainTemp[0], chainTemp)
|
||||
if err != nil {
|
||||
t.Error("Error", err)
|
||||
}
|
||||
|
||||
if doLock.(bool) && val {
|
||||
t.Error("When the chain is locked at milestone, it should not pass IsValidChain for incompatible incoming chain")
|
||||
}
|
||||
|
||||
if !doLock.(bool) && !val {
|
||||
t.Error("When the chain is not locked at milestone, it should pass IsValidChain for incoming chain")
|
||||
}
|
||||
|
||||
var (
|
||||
milestoneEndNum2 = rapid.Uint64().Draw(t, "endBlockNum 2")
|
||||
milestoneID2 = rapid.String().Draw(t, "MilestoneID 2")
|
||||
doLock2 = rapid.Bool().Draw(t, "Voted 2")
|
||||
)
|
||||
|
||||
val = milestone.LockMutex(milestoneEndNum2.(uint64))
|
||||
|
||||
if doLock.(bool) && milestoneEndNum.(uint64) > milestoneEndNum2.(uint64) && val {
|
||||
t.Error("LockMutex need to return false as previous locked milestone is greater")
|
||||
}
|
||||
|
||||
if doLock.(bool) && milestoneEndNum.(uint64) <= milestoneEndNum2.(uint64) && !val {
|
||||
t.Error("LockMutex need to return true as previous locked milestone is less")
|
||||
}
|
||||
|
||||
milestone.UnlockMutex(doLock2.(bool), milestoneID2.(string), milestoneEndNum2.(uint64), common.Hash{})
|
||||
|
||||
if doLock2.(bool) {
|
||||
if milestone.doExist {
|
||||
t.Error("Milestone is not expected to be whitelisted")
|
||||
}
|
||||
|
||||
if !milestone.Locked {
|
||||
t.Error("Milestone is expected to be locked at", milestoneEndNum2.(uint64))
|
||||
}
|
||||
|
||||
if milestone.LockedMilestoneNumber != milestoneEndNum2.(uint64) {
|
||||
t.Error("Locked milestone number is expected to be", milestoneEndNum.(uint64))
|
||||
}
|
||||
|
||||
if len(milestone.LockedMilestoneIDs) != 1 {
|
||||
t.Error("List should contain 1 milestone")
|
||||
}
|
||||
|
||||
_, ok := milestone.LockedMilestoneIDs[milestoneID2.(string)]
|
||||
|
||||
if !ok {
|
||||
t.Error("List doesn't contain correct milestoneID")
|
||||
}
|
||||
}
|
||||
|
||||
if !doLock2.(bool) {
|
||||
if milestone.doExist {
|
||||
t.Error("Milestone is not expected to be whitelisted")
|
||||
}
|
||||
|
||||
if !doLock.(bool) && milestone.Locked {
|
||||
t.Error("Milestone is expected not to be locked")
|
||||
}
|
||||
|
||||
if doLock.(bool) && !milestone.Locked {
|
||||
t.Error("Milestone is expected to be locked at", milestoneEndNum.(uint64))
|
||||
}
|
||||
|
||||
if !doLock.(bool) && milestone.LockedMilestoneNumber != 0 {
|
||||
t.Error("Locked milestone number is expected to be", 0)
|
||||
}
|
||||
|
||||
if doLock.(bool) && milestone.LockedMilestoneNumber != milestoneEndNum.(uint64) {
|
||||
t.Error("Locked milestone number is expected to be", milestoneEndNum.(uint64))
|
||||
}
|
||||
|
||||
if !doLock.(bool) && len(milestone.LockedMilestoneIDs) != 0 {
|
||||
t.Error("List should not contain milestone")
|
||||
}
|
||||
|
||||
if doLock.(bool) && len(milestone.LockedMilestoneIDs) != 1 {
|
||||
t.Error("List should not contain milestone")
|
||||
}
|
||||
|
||||
_, ok := milestone.LockedMilestoneIDs[milestoneID.(string)]
|
||||
|
||||
if !doLock.(bool) && ok {
|
||||
t.Error("List shouldn't contain any milestoneID")
|
||||
}
|
||||
|
||||
if doLock.(bool) && !ok {
|
||||
t.Error("List should contain milestoneID")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
milestoneNum = rapid.Uint64().Draw(t, "milestone Number")
|
||||
)
|
||||
|
||||
lockedValue := milestone.LockedMilestoneNumber
|
||||
|
||||
milestone.Process(milestoneNum.(uint64), common.Hash{})
|
||||
|
||||
isChainLocked := doLock.(bool) || doLock2.(bool)
|
||||
|
||||
if !milestone.doExist {
|
||||
t.Error("Should have the whitelisted milestone")
|
||||
}
|
||||
|
||||
if milestone.finality.Number != milestoneNum.(uint64) {
|
||||
t.Error("Should have the whitelisted milestone", milestoneNum.(uint64))
|
||||
}
|
||||
|
||||
if isChainLocked {
|
||||
if milestoneNum.(uint64) < lockedValue {
|
||||
if !milestone.Locked {
|
||||
t.Error("Milestone is expected to be locked")
|
||||
}
|
||||
} else {
|
||||
if milestone.Locked {
|
||||
t.Error("Milestone is expected not to be locked")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
futureMilestoneNum = rapid.Uint64Min(milestoneNum.(uint64)).Draw(t, "future milestone Number")
|
||||
)
|
||||
|
||||
isChainLocked = milestone.Locked
|
||||
|
||||
milestone.ProcessFutureMilestone(futureMilestoneNum.(uint64), common.Hash{})
|
||||
|
||||
if isChainLocked {
|
||||
if futureMilestoneNum.(uint64) < lockedValue {
|
||||
if !milestone.Locked {
|
||||
t.Error("Milestone is expected to be locked")
|
||||
}
|
||||
} else {
|
||||
if milestone.Locked {
|
||||
t.Error("Milestone is expected not to be locked")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSplitChain(t *testing.T) {
|
||||
|
|
@ -386,9 +1116,10 @@ func createMockChain(start, end uint64) []*types.Header {
|
|||
var (
|
||||
i uint64
|
||||
idx uint64
|
||||
chain []*types.Header = make([]*types.Header, end-start+1)
|
||||
)
|
||||
|
||||
chain := make([]*types.Header, end-start+1)
|
||||
|
||||
for i = start; i <= end; i++ {
|
||||
header := &types.Header{
|
||||
Number: big.NewInt(int64(i)),
|
||||
|
|
|
|||
|
|
@ -170,6 +170,12 @@ type Config struct {
|
|||
DatabaseCache int
|
||||
DatabaseFreezer string
|
||||
|
||||
// Database - LevelDB options
|
||||
LevelDbCompactionTableSize uint64
|
||||
LevelDbCompactionTableSizeMultiplier float64
|
||||
LevelDbCompactionTotalSize uint64
|
||||
LevelDbCompactionTotalSizeMultiplier float64
|
||||
|
||||
TrieCleanCache int
|
||||
TrieCleanCacheJournal string `toml:",omitempty"` // Disk journal directory for trie cache to survive node restarts
|
||||
TrieCleanCacheRejournal time.Duration `toml:",omitempty"` // Time interval to regenerate the journal for clean cache
|
||||
|
|
|
|||
|
|
@ -174,6 +174,21 @@ func (mr *MockBackendMockRecorder) GetReceipts(arg0, arg1 interface{}) *gomock.C
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReceipts", reflect.TypeOf((*MockBackend)(nil).GetReceipts), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetVoteOnHash mocks base method.
|
||||
func (m *MockBackend) GetVoteOnHash(arg0 context.Context, arg1, arg2 uint64, arg3, arg4 string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetVoteOnHash", arg0, arg1, arg2, arg3, arg4)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetVoteOnHash indicates an expected call of GetVoteOnHash.
|
||||
func (mr *MockBackendMockRecorder) GetVoteOnHash(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVoteOnHash", reflect.TypeOf((*MockBackend)(nil).GetVoteOnHash), arg0, arg1, arg2, arg3, arg4)
|
||||
}
|
||||
|
||||
// HeaderByHash mocks base method.
|
||||
func (m *MockBackend) HeaderByHash(arg0 context.Context, arg1 common.Hash) (*types.Header, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
|
|||
|
||||
b.Log("Running bloombits benchmark section size:", sectionSize)
|
||||
|
||||
db, err := rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false)
|
||||
db, err := rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false, rawdb.ExtraDBConfig{})
|
||||
if err != nil {
|
||||
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
|
|||
for i := 0; i < benchFilterCnt; i++ {
|
||||
if i%20 == 0 {
|
||||
db.Close()
|
||||
db, _ = rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false)
|
||||
db, _ = rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false, rawdb.ExtraDBConfig{})
|
||||
backend = &testBackend{db: db, sections: cnt}
|
||||
sys = NewFilterSystem(backend, Config{})
|
||||
}
|
||||
|
|
@ -187,7 +187,7 @@ func BenchmarkNoBloomBits(b *testing.B) {
|
|||
|
||||
b.Log("Running benchmark without bloombits")
|
||||
|
||||
db, err := rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false)
|
||||
db, err := rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false, rawdb.ExtraDBConfig{})
|
||||
if err != nil {
|
||||
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -491,6 +491,8 @@ func TestInvalidGetLogsRequest(t *testing.T) {
|
|||
blockHash = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
|
||||
)
|
||||
|
||||
api.SetChainConfig(params.BorUnittestChainConfig)
|
||||
|
||||
// Reason: Cannot specify both BlockHash and FromBlock/ToBlock)
|
||||
testCases := []FilterCriteria{
|
||||
0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)},
|
||||
|
|
@ -808,6 +810,7 @@ func TestPendingLogsSubscription(t *testing.T) {
|
|||
<-testCases[i].sub.Err()
|
||||
}
|
||||
}
|
||||
|
||||
// nolint:gocognit
|
||||
func TestLightFilterLogs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ func makeReceipt(addr common.Address) *types.Receipt {
|
|||
|
||||
func BenchmarkFilters(b *testing.B) {
|
||||
var (
|
||||
db, _ = rawdb.NewLevelDBDatabase(b.TempDir(), 0, 0, "", false)
|
||||
db, _ = rawdb.NewLevelDBDatabase(b.TempDir(), 0, 0, "", false, rawdb.ExtraDBConfig{})
|
||||
_, sys = newTestFilterSystem(b, db, Config{})
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
|
|
@ -106,7 +106,7 @@ func BenchmarkFilters(b *testing.B) {
|
|||
|
||||
func TestFilters(t *testing.T) {
|
||||
var (
|
||||
db, _ = rawdb.NewLevelDBDatabase(t.TempDir(), 0, 0, "", false)
|
||||
db, _ = rawdb.NewLevelDBDatabase(t.TempDir(), 0, 0, "", false, rawdb.ExtraDBConfig{})
|
||||
_, sys = newTestFilterSystem(t, db, Config{})
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
|
|
|
|||
|
|
@ -103,6 +103,10 @@ func (b *TestBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *TestBackend) GetVoteOnHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64, hash string, milestoneId string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (b *TestBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) {
|
||||
receipts := rawdb.ReadReceipts(b.DB, hash, number, params.TestChainConfig)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,94 +10,112 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
// errCheckpointCount is returned when we are unable to fetch
|
||||
// the checkpoint count from local heimdall.
|
||||
errCheckpointCount = errors.New("failed to fetch checkpoint count")
|
||||
|
||||
// errNoCheckpoint is returned when there is not checkpoint proposed
|
||||
// by heimdall yet or heimdall is not in sync
|
||||
errNoCheckpoint = errors.New("no checkpoint proposed")
|
||||
|
||||
// errCheckpoint is returned when we are unable to fetch the
|
||||
// latest checkpoint from the local heimdall.
|
||||
errCheckpoint = errors.New("failed to fetch latest checkpoint")
|
||||
|
||||
// errMissingCheckpoint is returned when we don't have the
|
||||
// checkpoint blocks locally, yet.
|
||||
errMissingCheckpoint = errors.New("missing checkpoint blocks")
|
||||
// errMilestone is returned when we are unable to fetch the
|
||||
// latest milestone from the local heimdall.
|
||||
errMilestone = errors.New("failed to fetch latest milestone")
|
||||
|
||||
// errRootHash is returned when we aren't able to calculate the root hash
|
||||
// locally for a range of blocks.
|
||||
errRootHash = errors.New("failed to get local root hash")
|
||||
|
||||
// errCheckpointRootHashMismatch is returned when the local root hash
|
||||
// doesn't match with the root hash in checkpoint.
|
||||
errCheckpointRootHashMismatch = errors.New("checkpoint roothash mismatch")
|
||||
|
||||
// errEndBlock is returned when we're unable to fetch a block locally.
|
||||
errEndBlock = errors.New("failed to get end block")
|
||||
ErrNotInRejectedList = errors.New("MilestoneID not in rejected list")
|
||||
)
|
||||
|
||||
// fetchWhitelistCheckpoints fetches the latest checkpoint/s from it's local heimdall
|
||||
// fetchWhitelistCheckpoint fetches the latest checkpoint from it's local heimdall
|
||||
// and verifies the data against bor data.
|
||||
func (h *ethHandler) fetchWhitelistCheckpoints(ctx context.Context, bor *bor.Bor, checkpointVerifier *checkpointVerifier, first bool) ([]uint64, []common.Hash, error) {
|
||||
// Create an array for block number and block hashes
|
||||
//nolint:prealloc
|
||||
func (h *ethHandler) fetchWhitelistCheckpoint(ctx context.Context, bor *bor.Bor, eth *Ethereum, verifier *borVerifier) (uint64, common.Hash, error) {
|
||||
var (
|
||||
blockNums []uint64 = make([]uint64, 0)
|
||||
blockHashes []common.Hash = make([]common.Hash, 0)
|
||||
blockNum uint64
|
||||
blockHash common.Hash
|
||||
)
|
||||
|
||||
// Fetch the checkpoint count from heimdall
|
||||
count, err := bor.HeimdallClient.FetchCheckpointCount(ctx)
|
||||
if err != nil {
|
||||
log.Debug("Failed to fetch checkpoint count for whitelisting", "err", err)
|
||||
return blockNums, blockHashes, errCheckpointCount
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return blockNums, blockHashes, errNoCheckpoint
|
||||
}
|
||||
|
||||
var (
|
||||
start int64
|
||||
end int64
|
||||
)
|
||||
|
||||
// Prepare the checkpoint range to fetch
|
||||
if count <= 10 {
|
||||
start = 1
|
||||
} else {
|
||||
start = count - 10 + 1 // 10 is the max number of checkpoints to fetch
|
||||
}
|
||||
|
||||
end = count
|
||||
|
||||
// If we're in not in the first iteration, only fetch the latest checkpoint
|
||||
if !first {
|
||||
start = count
|
||||
}
|
||||
|
||||
for i := start; i <= end; i++ {
|
||||
// fetch `i` indexed checkpoint from heimdall
|
||||
checkpoint, err := bor.HeimdallClient.FetchCheckpoint(ctx, i)
|
||||
// fetch the latest checkpoint from Heimdall
|
||||
checkpoint, err := bor.HeimdallClient.FetchCheckpoint(ctx, -1)
|
||||
if err != nil {
|
||||
log.Debug("Failed to fetch latest checkpoint for whitelisting", "err", err)
|
||||
return blockNums, blockHashes, errCheckpoint
|
||||
return blockNum, blockHash, errCheckpoint
|
||||
}
|
||||
|
||||
log.Info("Got new checkpoint from heimdall", "start", checkpoint.StartBlock.Uint64(), "end", checkpoint.EndBlock.Uint64(), "rootHash", checkpoint.RootHash.String())
|
||||
|
||||
// Verify if the checkpoint fetched can be added to the local whitelist entry or not
|
||||
// If verified, it returns the hash of the end block of the checkpoint. If not,
|
||||
// it will return appropriate error.
|
||||
|
||||
hash, err := checkpointVerifier.verify(ctx, h, checkpoint)
|
||||
hash, err := verifier.verify(ctx, eth, h, checkpoint.StartBlock.Uint64(), checkpoint.EndBlock.Uint64(), checkpoint.RootHash.String()[2:], true)
|
||||
if err != nil {
|
||||
return blockNums, blockHashes, err
|
||||
log.Warn("Failed to whitelist checkpoint", "err", err)
|
||||
return blockNum, blockHash, err
|
||||
}
|
||||
|
||||
blockNums = append(blockNums, checkpoint.EndBlock.Uint64())
|
||||
blockHashes = append(blockHashes, common.HexToHash(hash))
|
||||
blockNum = checkpoint.EndBlock.Uint64()
|
||||
blockHash = common.HexToHash(hash)
|
||||
|
||||
return blockNum, blockHash, nil
|
||||
}
|
||||
|
||||
return blockNums, blockHashes, nil
|
||||
// fetchWhitelistMilestone fetches the latest milestone from it's local heimdall
|
||||
// and verifies the data against bor data.
|
||||
func (h *ethHandler) fetchWhitelistMilestone(ctx context.Context, bor *bor.Bor, eth *Ethereum, verifier *borVerifier) (uint64, common.Hash, error) {
|
||||
var (
|
||||
num uint64
|
||||
hash common.Hash
|
||||
)
|
||||
|
||||
// fetch latest milestone
|
||||
milestone, err := bor.HeimdallClient.FetchMilestone(ctx)
|
||||
if err != nil {
|
||||
log.Error("Failed to fetch latest milestone for whitelisting", "err", err)
|
||||
return num, hash, errMilestone
|
||||
}
|
||||
|
||||
num = milestone.EndBlock.Uint64()
|
||||
hash = milestone.Hash
|
||||
|
||||
log.Info("Got new milestone from heimdall", "start", milestone.StartBlock.Uint64(), "end", milestone.EndBlock.Uint64(), "hash", milestone.Hash.String())
|
||||
|
||||
// Verify if the milestone fetched can be added to the local whitelist entry or not
|
||||
// If verified, it returns the hash of the end block of the milestone. If not,
|
||||
// it will return appropriate error.
|
||||
_, err = verifier.verify(ctx, eth, h, milestone.StartBlock.Uint64(), milestone.EndBlock.Uint64(), milestone.Hash.String()[2:], false)
|
||||
if err != nil {
|
||||
h.downloader.UnlockSprint(milestone.EndBlock.Uint64())
|
||||
return num, hash, err
|
||||
}
|
||||
|
||||
return num, hash, nil
|
||||
}
|
||||
|
||||
func (h *ethHandler) fetchNoAckMilestone(ctx context.Context, bor *bor.Bor) (string, error) {
|
||||
var (
|
||||
milestoneID string
|
||||
)
|
||||
|
||||
// fetch latest milestone
|
||||
milestoneID, err := bor.HeimdallClient.FetchLastNoAckMilestone(ctx)
|
||||
if err != nil {
|
||||
log.Error("Failed to fetch latest no-ack milestone", "err", err)
|
||||
|
||||
return milestoneID, errMilestone
|
||||
}
|
||||
|
||||
return milestoneID, nil
|
||||
}
|
||||
|
||||
func (h *ethHandler) fetchNoAckMilestoneByID(ctx context.Context, bor *bor.Bor, milestoneID string) error {
|
||||
// fetch latest milestone
|
||||
err := bor.HeimdallClient.FetchNoAckMilestone(ctx, milestoneID)
|
||||
|
||||
// fixme: handle different types of errors
|
||||
if errors.Is(err, ErrNotInRejectedList) {
|
||||
log.Warn("MilestoneID not in rejected list", "milestoneID", milestoneID, "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error("Failed to fetch no-ack milestone by ID ", "milestoneID", milestoneID, "err", err)
|
||||
|
||||
return errMilestone
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,17 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/clerk"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/checkpoint"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/milestone"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor/heimdall/span"
|
||||
)
|
||||
|
||||
type mockHeimdall struct {
|
||||
fetchCheckpoint func(ctx context.Context, number int64) (*checkpoint.Checkpoint, error)
|
||||
fetchCheckpointCount func(ctx context.Context) (int64, error)
|
||||
fetchMilestone func(ctx context.Context) (*milestone.Milestone, error)
|
||||
fetchMilestoneCount func(ctx context.Context) (int64, error)
|
||||
fetchNoAckMilestone func(ctx context.Context, milestoneID string) error
|
||||
fetchLastNoAckMilestone func(ctx context.Context) (string, error)
|
||||
}
|
||||
|
||||
func (m *mockHeimdall) StateSyncEvents(ctx context.Context, fromID uint64, to int64) ([]*clerk.EventRecordWithTime, error) {
|
||||
|
|
@ -33,80 +38,114 @@ func (m *mockHeimdall) FetchCheckpoint(ctx context.Context, number int64) (*chec
|
|||
func (m *mockHeimdall) FetchCheckpointCount(ctx context.Context) (int64, error) {
|
||||
return m.fetchCheckpointCount(ctx)
|
||||
}
|
||||
func (m *mockHeimdall) FetchMilestone(ctx context.Context) (*milestone.Milestone, error) {
|
||||
return m.fetchMilestone(ctx)
|
||||
}
|
||||
func (m *mockHeimdall) FetchMilestoneCount(ctx context.Context) (int64, error) {
|
||||
return m.fetchMilestoneCount(ctx)
|
||||
}
|
||||
func (m *mockHeimdall) FetchNoAckMilestone(ctx context.Context, milestoneID string) error {
|
||||
return m.fetchNoAckMilestone(ctx, milestoneID)
|
||||
}
|
||||
func (m *mockHeimdall) FetchLastNoAckMilestone(ctx context.Context) (string, error) {
|
||||
return m.fetchLastNoAckMilestone(ctx)
|
||||
}
|
||||
|
||||
func (m *mockHeimdall) FetchMilestoneID(ctx context.Context, milestoneID string) error {
|
||||
return m.fetchNoAckMilestone(ctx, milestoneID)
|
||||
}
|
||||
|
||||
func (m *mockHeimdall) Close() {}
|
||||
|
||||
func TestFetchWhitelistCheckpoints(t *testing.T) {
|
||||
func TestFetchWhitelistCheckpointAndMilestone(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// create an empty ethHandler
|
||||
handler := ðHandler{}
|
||||
|
||||
// create a mock checkpoint verification function and use it to create a verifier
|
||||
verify := func(ctx context.Context, handler *ethHandler, checkpoint *checkpoint.Checkpoint) (string, error) {
|
||||
verify := func(ctx context.Context, eth *Ethereum, handler *ethHandler, start uint64, end uint64, hash string, isCheckpoint bool) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
verifier := newCheckpointVerifier(verify)
|
||||
verifier := newBorVerifier()
|
||||
verifier.setVerify(verify)
|
||||
|
||||
// Create a mock heimdall instance and use it for creating a bor instance
|
||||
var heimdall mockHeimdall
|
||||
|
||||
bor := &bor.Bor{HeimdallClient: &heimdall}
|
||||
|
||||
// create 20 mock checkpoints
|
||||
checkpoints := createMockCheckpoints(20)
|
||||
fetchCheckpointTest(t, &heimdall, bor, handler, verifier)
|
||||
fetchMilestoneTest(t, &heimdall, bor, handler, verifier)
|
||||
}
|
||||
|
||||
func (b *borVerifier) setVerify(verifyFn func(ctx context.Context, eth *Ethereum, handler *ethHandler, start uint64, end uint64, hash string, isCheckpoint bool) (string, error)) {
|
||||
b.verify = verifyFn
|
||||
}
|
||||
|
||||
func fetchCheckpointTest(t *testing.T, heimdall *mockHeimdall, bor *bor.Bor, handler *ethHandler, verifier *borVerifier) {
|
||||
t.Helper()
|
||||
|
||||
var checkpoints []*checkpoint.Checkpoint
|
||||
// create a mock fetch checkpoint function
|
||||
heimdall.fetchCheckpoint = func(_ context.Context, number int64) (*checkpoint.Checkpoint, error) {
|
||||
return checkpoints[number-1], nil // we're sure that number won't exceed 20
|
||||
if len(checkpoints) == 0 {
|
||||
return nil, errCheckpoint
|
||||
} else if number == -1 {
|
||||
return checkpoints[len(checkpoints)-1], nil
|
||||
} else {
|
||||
return checkpoints[number-1], nil
|
||||
}
|
||||
}
|
||||
|
||||
// create a background context
|
||||
ctx := context.Background()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
first bool
|
||||
count int64
|
||||
length int
|
||||
start uint64
|
||||
end uint64
|
||||
fetchErr error
|
||||
expectedErr error
|
||||
}{
|
||||
{"fail to fetch checkpoint count", false, 0, 0, 0, 0, errCheckpointCount, errCheckpointCount},
|
||||
{"no checkpoints available", false, 0, 0, 0, 0, nil, errNoCheckpoint},
|
||||
{"fetch multiple checkpoints (count < 10)", true, 6, 6, 0, 6, nil, nil},
|
||||
{"fetch multiple checkpoints (count = 10)", true, 10, 10, 0, 10, nil, nil},
|
||||
{"fetch multiple checkpoints (count > 10)", true, 16, 10, 6, 16, nil, nil},
|
||||
{"fetch single checkpoint", false, 18, 1, 17, 18, nil, nil},
|
||||
}
|
||||
_, _, err := handler.fetchWhitelistCheckpoint(ctx, bor, nil, verifier)
|
||||
require.Equal(t, err, errCheckpoint)
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
// create 4 mock checkpoints
|
||||
checkpoints = createMockCheckpoints(4)
|
||||
|
||||
heimdall.fetchCheckpointCount = getMockFetchCheckpointFn(tc.count, tc.fetchErr)
|
||||
blockNums, blockHashes, err := handler.fetchWhitelistCheckpoints(ctx, bor, verifier, tc.first)
|
||||
blockNum, blockHash, err := handler.fetchWhitelistCheckpoint(ctx, bor, nil, verifier)
|
||||
|
||||
// Check if we have expected result
|
||||
require.Equal(t, tc.expectedErr, err)
|
||||
require.Equal(t, tc.length, len(blockNums))
|
||||
require.Equal(t, tc.length, len(blockHashes))
|
||||
validateBlockNumber(t, blockNums, checkpoints[tc.start:tc.end])
|
||||
})
|
||||
}
|
||||
require.Equal(t, err, nil)
|
||||
require.Equal(t, checkpoints[len(checkpoints)-1].EndBlock.Uint64(), blockNum)
|
||||
require.Equal(t, checkpoints[len(checkpoints)-1].RootHash, blockHash)
|
||||
}
|
||||
|
||||
func validateBlockNumber(t *testing.T, blockNums []uint64, checkpoints []*checkpoint.Checkpoint) {
|
||||
func fetchMilestoneTest(t *testing.T, heimdall *mockHeimdall, bor *bor.Bor, handler *ethHandler, verifier *borVerifier) {
|
||||
t.Helper()
|
||||
|
||||
for i, blockNum := range blockNums {
|
||||
require.Equal(t, blockNum, checkpoints[i].EndBlock.Uint64(), "expect block number in array to match with checkpoint")
|
||||
var milestones []*milestone.Milestone
|
||||
// create a mock fetch checkpoint function
|
||||
heimdall.fetchMilestone = func(_ context.Context) (*milestone.Milestone, error) {
|
||||
if len(milestones) == 0 {
|
||||
return nil, errMilestone
|
||||
} else {
|
||||
return milestones[len(milestones)-1], nil
|
||||
}
|
||||
}
|
||||
|
||||
// create a background context
|
||||
ctx := context.Background()
|
||||
|
||||
_, _, err := handler.fetchWhitelistMilestone(ctx, bor, nil, verifier)
|
||||
require.Equal(t, err, errMilestone)
|
||||
|
||||
// create 4 mock checkpoints
|
||||
milestones = createMockMilestones(4)
|
||||
|
||||
num, hash, err := handler.fetchWhitelistMilestone(ctx, bor, nil, verifier)
|
||||
|
||||
// Check if we have expected result
|
||||
require.Equal(t, err, nil)
|
||||
require.Equal(t, milestones[len(milestones)-1].EndBlock.Uint64(), num)
|
||||
require.Equal(t, milestones[len(milestones)-1].Hash, hash)
|
||||
}
|
||||
|
||||
func getMockFetchCheckpointFn(number int64, err error) func(ctx context.Context) (int64, error) {
|
||||
return func(_ context.Context) (int64, error) {
|
||||
return number, err
|
||||
|
|
@ -133,3 +172,24 @@ func createMockCheckpoints(count int) []*checkpoint.Checkpoint {
|
|||
|
||||
return checkpoints
|
||||
}
|
||||
|
||||
func createMockMilestones(count int) []*milestone.Milestone {
|
||||
var (
|
||||
milestones []*milestone.Milestone = make([]*milestone.Milestone, count)
|
||||
startBlock int64 = 257 // any number can be used
|
||||
)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
milestones[i] = &milestone.Milestone{
|
||||
Proposer: common.Address{},
|
||||
StartBlock: big.NewInt(startBlock),
|
||||
EndBlock: big.NewInt(startBlock + 255),
|
||||
Hash: common.Hash{},
|
||||
BorChainID: "137",
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
}
|
||||
startBlock += 256
|
||||
}
|
||||
|
||||
return milestones
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,10 @@ func (p *Peer) broadcastTransactions() {
|
|||
)
|
||||
|
||||
for i := 0; i < len(queue) && size < maxTxPacketSize; i++ {
|
||||
if tx := p.txpool.Get(queue[i]); tx != nil {
|
||||
tx := p.txpool.Get(queue[i])
|
||||
|
||||
// Skip EIP-4337 bundled transactions
|
||||
if tx != nil && tx.GetOptions() == nil {
|
||||
txs = append(txs, tx)
|
||||
size += common.StorageSize(tx.Size())
|
||||
}
|
||||
|
|
@ -158,7 +161,10 @@ func (p *Peer) announceTransactions() {
|
|||
)
|
||||
|
||||
for count = 0; count < len(queue) && size < maxTxPacketSize; count++ {
|
||||
if tx := p.txpool.Get(queue[count]); tx != nil {
|
||||
tx := p.txpool.Get(queue[count])
|
||||
|
||||
// Skip EIP-4337 bundled transactions
|
||||
if tx != nil && tx.GetOptions() == nil {
|
||||
pending = append(pending, queue[count])
|
||||
pendingTypes = append(pendingTypes, tx.Type())
|
||||
pendingSizes = append(pendingSizes, uint32(tx.Size()))
|
||||
|
|
|
|||
|
|
@ -11,13 +11,23 @@ import (
|
|||
// GetRootHash returns the merkle root of the block headers
|
||||
func (ec *Client) GetRootHash(ctx context.Context, startBlockNumber uint64, endBlockNumber uint64) (string, error) {
|
||||
var rootHash string
|
||||
if err := ec.c.CallContext(ctx, &rootHash, "eth_getRootHash", startBlockNumber, endBlockNumber); err != nil {
|
||||
if err := ec.c.CallContext(ctx, &rootHash, "bor_getRootHash", startBlockNumber, endBlockNumber); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return rootHash, nil
|
||||
}
|
||||
|
||||
// GetRootHash returns the merkle root of the block headers
|
||||
func (ec *Client) GetVoteOnHash(ctx context.Context, startBlockNumber uint64, endBlockNumber uint64, hash string, milestoneID string) (bool, error) {
|
||||
var value bool
|
||||
if err := ec.c.CallContext(ctx, &value, "bor_getVoteOnHash", startBlockNumber, endBlockNumber, hash, milestoneID); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// GetBorBlockReceipt returns bor block receipt
|
||||
func (ec *Client) GetBorBlockReceipt(ctx context.Context, hash common.Hash) (*types.Receipt, error) {
|
||||
var r *types.Receipt
|
||||
|
|
|
|||
|
|
@ -83,9 +83,16 @@ type Database struct {
|
|||
log log.Logger // Contextual logger tracking the database path
|
||||
}
|
||||
|
||||
type LevelDBConfig struct {
|
||||
CompactionTableSize uint64 // LevelDB SSTable/file size in mebibytes
|
||||
CompactionTableSizeMultiplier float64 // Multiplier on LevelDB SSTable/file size
|
||||
CompactionTotalSize uint64 // Total size in mebibytes of SSTables in a given LevelDB level
|
||||
CompactionTotalSizeMultiplier float64 // Multiplier on level size on LevelDB levels
|
||||
}
|
||||
|
||||
// New returns a wrapped LevelDB object. The namespace is the prefix that the
|
||||
// metrics reporting should use for surfacing internal stats.
|
||||
func New(file string, cache int, handles int, namespace string, readonly bool) (*Database, error) {
|
||||
func New(file string, cache int, handles int, namespace string, readonly bool, config LevelDBConfig) (*Database, error) {
|
||||
return NewCustom(file, namespace, func(options *opt.Options) {
|
||||
// Ensure we have some minimal caching and file guarantees
|
||||
if cache < minCache {
|
||||
|
|
@ -100,6 +107,22 @@ func New(file string, cache int, handles int, namespace string, readonly bool) (
|
|||
options.BlockCacheCapacity = cache / 2 * opt.MiB
|
||||
options.WriteBuffer = cache / 4 * opt.MiB // Two of these are used internally
|
||||
|
||||
if config.CompactionTableSize != 0 {
|
||||
options.CompactionTableSize = int(config.CompactionTableSize * opt.MiB)
|
||||
}
|
||||
|
||||
if config.CompactionTableSizeMultiplier != 0 {
|
||||
options.CompactionTableSizeMultiplier = config.CompactionTableSizeMultiplier
|
||||
}
|
||||
|
||||
if config.CompactionTotalSize != 0 {
|
||||
options.CompactionTotalSize = int(config.CompactionTotalSize * opt.MiB)
|
||||
}
|
||||
|
||||
if config.CompactionTotalSizeMultiplier != 0 {
|
||||
options.CompactionTotalSizeMultiplier = config.CompactionTotalSizeMultiplier
|
||||
}
|
||||
|
||||
if readonly {
|
||||
options.ReadOnly = true
|
||||
}
|
||||
|
|
@ -114,7 +137,14 @@ func NewCustom(file string, namespace string, customize func(options *opt.Option
|
|||
logger := log.New("database", file)
|
||||
usedCache := options.GetBlockCacheCapacity() + options.GetWriteBuffer()*2
|
||||
|
||||
logCtx := []interface{}{"cache", common.StorageSize(usedCache), "handles", options.GetOpenFilesCacheCapacity()}
|
||||
logCtx := []interface{}{
|
||||
"cache", common.StorageSize(usedCache),
|
||||
"handles", options.GetOpenFilesCacheCapacity(),
|
||||
"compactionTableSize", options.CompactionTableSize,
|
||||
"compactionTableSizeMultiplier", options.CompactionTableSizeMultiplier,
|
||||
"compactionTotalSize", options.CompactionTotalSize,
|
||||
"compactionTotalSizeMultiplier", options.CompactionTotalSizeMultiplier}
|
||||
|
||||
if options.ReadOnly {
|
||||
logCtx = append(logCtx, "readonly", "true")
|
||||
}
|
||||
|
|
|
|||
62
go.mod
62
go.mod
|
|
@ -17,14 +17,14 @@ require (
|
|||
github.com/cloudflare/cloudflare-go v0.14.0
|
||||
github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811
|
||||
github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c
|
||||
github.com/cosmos/cosmos-sdk v0.37.4
|
||||
github.com/cosmos/cosmos-sdk v0.46.2
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/deckarep/golang-set/v2 v2.1.0
|
||||
github.com/docker/docker v1.6.2
|
||||
github.com/docker/docker v24.0.5+incompatible
|
||||
github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7
|
||||
github.com/edsrzf/mmap-go v1.0.0
|
||||
github.com/emirpasic/gods v1.18.1
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
|
|
@ -53,12 +53,13 @@ require (
|
|||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
||||
github.com/jackpal/go-nat-pmp v1.0.2
|
||||
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/julienschmidt/httprouter v1.3.0
|
||||
github.com/karalabe/usb v0.0.2
|
||||
github.com/kylelemons/godebug v1.1.0
|
||||
github.com/maticnetwork/crand v1.0.2
|
||||
github.com/maticnetwork/heimdall v0.3.1-0.20230105132832-d0063f71e3f0
|
||||
github.com/maticnetwork/polyproto v0.0.2
|
||||
github.com/maticnetwork/heimdall v0.3.1-0.20230227104835-81bd1055b0bc
|
||||
github.com/maticnetwork/polyproto v0.0.3-0.20230216113155-340ea926ca53
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
github.com/mattn/go-isatty v0.0.16
|
||||
github.com/mitchellh/cli v1.1.2
|
||||
|
|
@ -88,10 +89,28 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
cloud.google.com/go/iam v0.5.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pborman/uuid v1.2.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.4.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.104.0 // indirect
|
||||
cloud.google.com/go/pubsub v1.3.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect
|
||||
github.com/DataDog/zstd v1.5.2 // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
|
||||
github.com/agext/levenshtein v1.2.1 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect
|
||||
github.com/aws/aws-sdk-go v1.34.28 // 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
|
||||
|
|
@ -119,7 +138,7 @@ require (
|
|||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/pointerstructure v1.2.0 // indirect
|
||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
|
|
@ -141,7 +160,6 @@ require (
|
|||
go.uber.org/goleak v1.1.12
|
||||
golang.org/x/mod v0.9.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
|
||||
gonum.org/v1/gonum v0.11.0
|
||||
google.golang.org/grpc v1.51.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
|
|
@ -168,10 +186,10 @@ require (
|
|||
github.com/go-kit/kit v0.10.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
||||
github.com/go-redis/redis v6.15.7+incompatible // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.5.1 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
|
|
@ -181,25 +199,21 @@ require (
|
|||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/jmhodges/levigo v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/jstemmer/go-junit-report v0.9.1 // indirect
|
||||
github.com/kelseyhightower/envconfig v1.4.0 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
|
||||
github.com/magiconair/properties v1.8.1 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/posener/complete v1.1.1 // indirect
|
||||
github.com/rakyll/statik v0.1.7 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/spf13/afero v1.2.2 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/afero v1.8.2 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/cobra v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.4.0 // indirect
|
||||
github.com/spf13/viper v1.13.0 // indirect
|
||||
github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 // indirect
|
||||
github.com/stumble/gorocksdb v0.0.3 // indirect
|
||||
github.com/tendermint/btcd v0.1.1 // indirect
|
||||
|
|
@ -211,33 +225,27 @@ require (
|
|||
github.com/xdg-go/scram v1.0.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.2 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
|
||||
golang.org/x/oauth2 v0.3.0 // indirect
|
||||
gotest.tools/v3 v3.5.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.65.0 // indirect
|
||||
cloud.google.com/go/pubsub v1.3.1 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae // indirect
|
||||
github.com/RichardKnop/machinery v1.7.4 // indirect
|
||||
github.com/RichardKnop/redsync v1.2.0 // indirect
|
||||
github.com/agext/levenshtein v1.2.1 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect
|
||||
github.com/aws/aws-sdk-go v1.34.28 // indirect
|
||||
github.com/zclconf/go-cty v1.8.0 // indirect
|
||||
github.com/zondax/hid v0.9.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.3.0 // indirect
|
||||
go.opencensus.io v0.22.6 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.2.0
|
||||
go.opentelemetry.io/proto/otlp v0.10.0 // indirect
|
||||
google.golang.org/api v0.34.0 // indirect
|
||||
google.golang.org/api v0.97.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b // indirect
|
||||
google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce // indirect
|
||||
)
|
||||
|
||||
replace github.com/cosmos/cosmos-sdk => github.com/maticnetwork/cosmos-sdk v0.37.5-0.20220311095845-81690c6a53e7
|
||||
|
|
|
|||
269
go.sum
269
go.sum
|
|
@ -4,6 +4,7 @@ cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSR
|
|||
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
|
|
@ -14,8 +15,25 @@ cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bP
|
|||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
||||
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
||||
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
||||
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
|
||||
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
|
||||
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
||||
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
|
||||
cloud.google.com/go v0.104.0 h1:gSmWO7DY1vOm0MVU6DNXM11BWHHsTUmsC5cv1fuW5X8=
|
||||
cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
|
|
@ -23,8 +41,19 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM
|
|||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=
|
||||
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
|
||||
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
|
||||
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
|
||||
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
|
||||
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
|
||||
cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk=
|
||||
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
|
||||
cloud.google.com/go/iam v0.5.0 h1:fz9X5zyTWBmamZsqvqZqD7khbifcZF/q+Z1J8pfhIUg=
|
||||
cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc=
|
||||
cloud.google.com/go/kms v1.4.0 h1:iElbfoE61VeLhnZcGOltqL8HIly8Nhbe5t6JlH9GXjo=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
|
|
@ -35,6 +64,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
|||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
|
||||
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
|
||||
|
|
@ -204,6 +235,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
|||
github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA=
|
||||
github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
|
|
@ -283,8 +315,8 @@ github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/
|
|||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/docker v1.6.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v1.6.2 h1:HlFGsy+9/xrgMmhmN+NGhCc5SHGJ7I+kHosRR1xc/aI=
|
||||
github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=
|
||||
github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
|
||||
github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
|
||||
github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 h1:kgvzE5wLsLa7XKfV85VZl40QXaMCaeFtHpPwJ8fhotY=
|
||||
|
|
@ -306,6 +338,7 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
|
|||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
|
|
@ -322,8 +355,9 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQD
|
|||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
||||
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0=
|
||||
github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
|
||||
|
|
@ -335,6 +369,7 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8
|
|||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
|
|
@ -454,8 +489,9 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er
|
|||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
|
|
@ -464,6 +500,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
|||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
|
@ -483,6 +520,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
|
|
@ -521,6 +559,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
|||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
|
|
@ -528,6 +568,14 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
|||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
|
|
@ -536,9 +584,20 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0 h1:zO8WHNx/MYiAKJ3d5spxZXZE6KHmIQGQcAzwUzV7qQw=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
|
||||
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
||||
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||
github.com/googleapis/gax-go/v2 v2.5.1 h1:kBRZU0PSuI7PspsSb/ChWoVResUcwNVIdpB049pKTiw=
|
||||
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
|
|
@ -609,6 +668,7 @@ github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixH
|
|||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
|
||||
|
|
@ -661,7 +721,6 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
|
|||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
|
|
@ -703,6 +762,7 @@ 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/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
|
|
@ -728,8 +788,9 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
|
|||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
|
|
@ -739,10 +800,12 @@ github.com/maticnetwork/cosmos-sdk v0.37.5-0.20220311095845-81690c6a53e7 h1:8NoE
|
|||
github.com/maticnetwork/cosmos-sdk v0.37.5-0.20220311095845-81690c6a53e7/go.mod h1:uW55Ru86N5o3L8SVkVL1TPE+mV/WRM2la8sC3TR/Ajc=
|
||||
github.com/maticnetwork/crand v1.0.2 h1:Af0tAivC8zrxXDpGWNWVT/0s1fOz8w0eRbahZgURS8I=
|
||||
github.com/maticnetwork/crand v1.0.2/go.mod h1:/NRNL3bj2eYdqpWmoIP5puxndTpi0XRxpj5ZKxfHjyg=
|
||||
github.com/maticnetwork/heimdall v0.3.1-0.20230105132832-d0063f71e3f0 h1:MYTAcBs4y88GEzesT8eAU472ZfQSLluW0qgkZTzNgwM=
|
||||
github.com/maticnetwork/heimdall v0.3.1-0.20230105132832-d0063f71e3f0/go.mod h1:A3bUSe9jjMQHEPPOUW1JytM3x2g3t+jvsbPY66KBPIs=
|
||||
github.com/maticnetwork/polyproto v0.0.2 h1:cPxuxbIDItdwGnucc3lZB58U8Zfe1mH73PWTGd15554=
|
||||
github.com/maticnetwork/heimdall v0.3.1-0.20230227104835-81bd1055b0bc h1:7wEWQbYs6ESGsVBhjiVp7fZZyfaN4lg4XYLOLfRIpmY=
|
||||
github.com/maticnetwork/heimdall v0.3.1-0.20230227104835-81bd1055b0bc/go.mod h1:P2DoKhovYP9G9Kj2EH/zHaiRJF1jNU7ZJOyelG4UCa8=
|
||||
github.com/maticnetwork/polyproto v0.0.2/go.mod h1:e1mU2EXSwEpn5jM7GfNwu3AupsV6WAGoPFFfswXOF0o=
|
||||
github.com/maticnetwork/polyproto v0.0.3-0.20230216113155-340ea926ca53 h1:PjYV+lghs106JKkrYgOnrsfDLoTc11BxZd4rUa4Rus4=
|
||||
github.com/maticnetwork/polyproto v0.0.3-0.20230216113155-340ea926ca53/go.mod h1:e1mU2EXSwEpn5jM7GfNwu3AupsV6WAGoPFFfswXOF0o=
|
||||
github.com/maticnetwork/tendermint v0.26.0-dev0.0.20220923185258-3e7c7f86ce9f h1:iV69PJUEdwJJFXQvbADYVEMxDrkKAsPdHTg4U3F510I=
|
||||
github.com/maticnetwork/tendermint v0.26.0-dev0.0.20220923185258-3e7c7f86ce9f/go.mod h1:90S74348uYSGfWwNIgvzQiRRakSH/c7VVt1TR5mzIuY=
|
||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
|
|
@ -751,6 +814,7 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
|
|||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
|
|
@ -793,8 +857,9 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
|
|||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
|
||||
github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
|
|
@ -859,10 +924,14 @@ github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIw
|
|||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
|
||||
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
|
||||
github.com/peterh/liner v1.2.0 h1:w/UPXyl5GfahFxcTOz2j9wCIHNI+pUPr2laqpojKNCg=
|
||||
|
|
@ -881,6 +950,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
|
|
@ -980,11 +1050,13 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ
|
|||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
|
||||
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||
|
|
@ -998,8 +1070,9 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
|
|||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU=
|
||||
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
|
||||
github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d/go.mod h1:97vT0Rym0wCnK4B++hNA3nCetr0Mh1KXaVxzSt1arjg=
|
||||
github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
|
||||
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
|
||||
|
|
@ -1026,6 +1099,8 @@ github.com/stumble/gorocksdb v0.0.3 h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8
|
|||
github.com/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY=
|
||||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
|
||||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
|
||||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 h1:m+8fKfQwCAy1QjzINvKe/pYtLjo2dl59x2w9YSEJxuY=
|
||||
github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
||||
|
|
@ -1127,8 +1202,10 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.6 h1:BdkrbWrzDlV9dnbzoP7sfN+dHheJ4J9JOaYxcUDL+ok=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/otel v1.2.0 h1:YOQDvxO1FayUcT9MIhJhgMyNO1WqoduiyvQHzGN0kUQ=
|
||||
go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 h1:xzbcGykysUh776gzD1LUPsNNHKWN0kQWDnJhn1ddUuk=
|
||||
|
|
@ -1174,7 +1251,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
|
@ -1218,6 +1297,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
|
|||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
|
|
@ -1228,6 +1308,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
|
|
@ -1278,18 +1360,31 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R
|
|||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
|
|
@ -1300,7 +1395,21 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
|
|||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||
golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8=
|
||||
golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
@ -1315,6 +1424,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
@ -1378,10 +1488,17 @@ golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -1389,19 +1506,36 @@ golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
@ -1498,10 +1632,17 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
|
|||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
|
|
@ -1515,8 +1656,9 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618=
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
|
||||
|
|
@ -1546,8 +1688,32 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
|||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.34.0 h1:k40adF3uR+6x/+hO5Dh4ZFUqFp67vxvbpafFiJxl10A=
|
||||
google.golang.org/api v0.34.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
||||
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
||||
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
||||
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
||||
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
|
||||
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
|
||||
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
|
||||
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
|
||||
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
|
||||
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
|
||||
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
|
||||
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||
google.golang.org/api v0.97.0 h1:x/vEL1XDF/2V4xzdNgFPaKHluRESo2aTsL7QzHnBtGQ=
|
||||
google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
|
@ -1596,10 +1762,60 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D
|
|||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b h1:SfSkJugek6xm7lWywqth4r2iTrYLpD8lOj1nMIIhMNM=
|
||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
|
||||
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
|
||||
google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce h1:+2ye9vAK4F9F/LCex8dT2cDk0VnTAwUL8uRgX/6nAMU=
|
||||
google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI=
|
||||
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
|
|
@ -1622,15 +1838,28 @@ google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
|
|||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
|
||||
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0/go.mod h1:DNq5QpG7LJqD2AamLZ7zvKE0DEpVl2BSEVjFycAAjRY=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
|
|
@ -1661,6 +1890,8 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
|||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
|
|
@ -1689,6 +1920,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
|
||||
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
|||
|
|
@ -1350,7 +1350,8 @@ func (r *Resolver) Blocks(ctx context.Context, args struct {
|
|||
return []*Block{}, nil
|
||||
}
|
||||
|
||||
ret := make([]*Block, 0, to-from+1)
|
||||
// nolint:prealloc
|
||||
var ret []*Block
|
||||
|
||||
for i := from; i <= to; i++ {
|
||||
numberOrHash := rpc.BlockNumberOrHashWithNumber(i)
|
||||
|
|
@ -1370,6 +1371,10 @@ func (r *Resolver) Blocks(ctx context.Context, args struct {
|
|||
}
|
||||
|
||||
ret = append(ret, block)
|
||||
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
|
|
|||
|
|
@ -250,9 +250,19 @@ type StateSyncFilter struct {
|
|||
|
||||
// interface for whitelist service
|
||||
type ChainValidator interface {
|
||||
IsValidPeer(remoteHeader *types.Header, fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error)
|
||||
IsValidPeer(fetchHeadersByNumber func(number uint64, amount int, skip int, reverse bool) ([]*types.Header, []common.Hash, error)) (bool, error)
|
||||
IsValidChain(currentHeader *types.Header, chain []*types.Header) (bool, error)
|
||||
GetWhitelistedCheckpoint() (bool, uint64, common.Hash)
|
||||
GetWhitelistedMilestone() (bool, uint64, common.Hash)
|
||||
ProcessCheckpoint(endBlockNum uint64, endBlockHash common.Hash)
|
||||
GetCheckpointWhitelist() map[uint64]common.Hash
|
||||
PurgeCheckpointWhitelist()
|
||||
ProcessMilestone(endBlockNum uint64, endBlockHash common.Hash)
|
||||
ProcessFutureMilestone(num uint64, hash common.Hash)
|
||||
PurgeWhitelistedCheckpoint()
|
||||
PurgeWhitelistedMilestone()
|
||||
|
||||
LockMutex(endBlockNum uint64) bool
|
||||
UnlockMutex(doLock bool, milestoneId string, endBlockNum uint64, endBlockHash common.Hash)
|
||||
UnlockSprint(endBlockNum uint64)
|
||||
RemoveMilestoneID(milestoneId string)
|
||||
GetMilestoneIDsList() []string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,17 +5,21 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
||||
"github.com/ethereum/go-ethereum/internal/cli/server"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/metrics/prometheus"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
|
|
@ -27,6 +31,8 @@ type BootnodeCommand struct {
|
|||
UI cli.Ui
|
||||
|
||||
listenAddr string
|
||||
enableMetrics bool
|
||||
prometheusAddr string
|
||||
v5 bool
|
||||
verbosity int
|
||||
logLevel string
|
||||
|
|
@ -60,6 +66,18 @@ func (b *BootnodeCommand) Flags() *flagset.Flagset {
|
|||
Usage: "listening address of bootnode (<ip>:<port>)",
|
||||
Value: &b.listenAddr,
|
||||
})
|
||||
flags.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "metrics",
|
||||
Usage: "Enable metrics collection and reporting",
|
||||
Value: &b.enableMetrics,
|
||||
Default: true,
|
||||
})
|
||||
flags.StringFlag(&flagset.StringFlag{
|
||||
Name: "prometheus-addr",
|
||||
Default: "127.0.0.1:7071",
|
||||
Usage: "listening address of bootnode (<ip>:<port>)",
|
||||
Value: &b.prometheusAddr,
|
||||
})
|
||||
flags.BoolFlag(&flagset.BoolFlag{
|
||||
Name: "v5",
|
||||
Default: false,
|
||||
|
|
@ -237,6 +255,26 @@ func (b *BootnodeCommand) Run(args []string) int {
|
|||
}
|
||||
}
|
||||
|
||||
if b.enableMetrics {
|
||||
prometheusMux := http.NewServeMux()
|
||||
|
||||
prometheusMux.Handle("/debug/metrics/prometheus", prometheus.Handler(metrics.DefaultRegistry))
|
||||
|
||||
promServer := &http.Server{
|
||||
Addr: b.prometheusAddr,
|
||||
Handler: prometheusMux,
|
||||
ReadHeaderTimeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := promServer.ListenAndServe(); err != nil {
|
||||
log.Error("Failure in running Prometheus server", "err", err)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Info("Enabling metrics export to prometheus", "path", fmt.Sprintf("http://%s/debug/metrics/prometheus", b.prometheusAddr))
|
||||
}
|
||||
|
||||
signalCh := make(chan os.Signal, 4)
|
||||
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ func (c *DumpconfigCommand) Synopsis() string {
|
|||
func (c *DumpconfigCommand) Run(args []string) int {
|
||||
// Initialize an empty command instance to get flags
|
||||
command := server.Command{}
|
||||
flags := command.Flags()
|
||||
flags := command.Flags(nil)
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
|
|
|
|||
|
|
@ -5,33 +5,42 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Flagset struct {
|
||||
flags []*FlagVar
|
||||
flags map[string]*FlagVar
|
||||
set *flag.FlagSet
|
||||
}
|
||||
|
||||
func NewFlagSet(name string) *Flagset {
|
||||
f := &Flagset{
|
||||
flags: []*FlagVar{},
|
||||
flags: make(map[string]*FlagVar, 0),
|
||||
set: flag.NewFlagSet(name, flag.ContinueOnError),
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// Updatable is a minimalistic representation of a flag which has
|
||||
// the method `UpdateValue` implemented which can be called while
|
||||
// overwriting flags.
|
||||
type Updatable interface {
|
||||
UpdateValue(string)
|
||||
}
|
||||
|
||||
type FlagVar struct {
|
||||
Name string
|
||||
Usage string
|
||||
Group string
|
||||
Default any
|
||||
Value Updatable
|
||||
}
|
||||
|
||||
func (f *Flagset) addFlag(fl *FlagVar) {
|
||||
f.flags = append(f.flags, fl)
|
||||
f.flags[fl.Name] = fl
|
||||
}
|
||||
|
||||
func (f *Flagset) Help() string {
|
||||
|
|
@ -51,9 +60,12 @@ func (f *Flagset) Help() string {
|
|||
}
|
||||
|
||||
func (f *Flagset) GetAllFlags() []string {
|
||||
flags := []string{}
|
||||
for _, flag := range f.flags {
|
||||
flags = append(flags, flag.Name)
|
||||
i := 0
|
||||
flags := make([]string, 0, len(f.flags))
|
||||
|
||||
for name := range f.flags {
|
||||
flags[i] = name
|
||||
i++
|
||||
}
|
||||
|
||||
return flags
|
||||
|
|
@ -110,6 +122,33 @@ func (f *Flagset) Args() []string {
|
|||
return f.set.Args()
|
||||
}
|
||||
|
||||
// UpdateValue updates the underlying value of a flag
|
||||
// given the flag name and value to update using pointer.
|
||||
func (f *Flagset) UpdateValue(names []string, values []string) {
|
||||
for i, name := range names {
|
||||
if flag, ok := f.flags[name]; ok {
|
||||
value := values[i]
|
||||
|
||||
// Call the underlying flag's `UpdateValue` method
|
||||
flag.Value.UpdateValue(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Visit visits all the set flags and returns the name and value
|
||||
// in string to set later.
|
||||
func (f *Flagset) Visit() ([]string, []string) {
|
||||
names := make([]string, 0, len(f.flags))
|
||||
values := make([]string, 0, len(f.flags))
|
||||
|
||||
f.set.Visit(func(flag *flag.Flag) {
|
||||
names = append(names, flag.Name)
|
||||
values = append(values, flag.Value.String())
|
||||
})
|
||||
|
||||
return names, values
|
||||
}
|
||||
|
||||
type BoolFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
|
|
@ -118,12 +157,19 @@ type BoolFlag struct {
|
|||
Group string
|
||||
}
|
||||
|
||||
func (b *BoolFlag) UpdateValue(value string) {
|
||||
v, _ := strconv.ParseBool(value)
|
||||
|
||||
*b.Value = v
|
||||
}
|
||||
|
||||
func (f *Flagset) BoolFlag(b *BoolFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: b.Name,
|
||||
Usage: b.Usage,
|
||||
Group: b.Group,
|
||||
Default: b.Default,
|
||||
Value: b,
|
||||
})
|
||||
f.set.BoolVar(b.Value, b.Name, b.Default, b.Usage)
|
||||
}
|
||||
|
|
@ -137,6 +183,10 @@ type StringFlag struct {
|
|||
HideDefaultFromDoc bool
|
||||
}
|
||||
|
||||
func (b *StringFlag) UpdateValue(value string) {
|
||||
*b.Value = value
|
||||
}
|
||||
|
||||
func (f *Flagset) StringFlag(b *StringFlag) {
|
||||
if b.Default == "" || b.HideDefaultFromDoc {
|
||||
f.addFlag(&FlagVar{
|
||||
|
|
@ -144,6 +194,7 @@ func (f *Flagset) StringFlag(b *StringFlag) {
|
|||
Usage: b.Usage,
|
||||
Group: b.Group,
|
||||
Default: nil,
|
||||
Value: b,
|
||||
})
|
||||
} else {
|
||||
f.addFlag(&FlagVar{
|
||||
|
|
@ -151,6 +202,7 @@ func (f *Flagset) StringFlag(b *StringFlag) {
|
|||
Usage: b.Usage,
|
||||
Group: b.Group,
|
||||
Default: b.Default,
|
||||
Value: b,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -165,12 +217,19 @@ type IntFlag struct {
|
|||
Group string
|
||||
}
|
||||
|
||||
func (b *IntFlag) UpdateValue(value string) {
|
||||
v, _ := strconv.ParseInt(value, 10, 64)
|
||||
|
||||
*b.Value = int(v)
|
||||
}
|
||||
|
||||
func (f *Flagset) IntFlag(i *IntFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: i.Name,
|
||||
Usage: i.Usage,
|
||||
Group: i.Group,
|
||||
Default: i.Default,
|
||||
Value: i,
|
||||
})
|
||||
f.set.IntVar(i.Value, i.Name, i.Default, i.Usage)
|
||||
}
|
||||
|
|
@ -183,12 +242,19 @@ type Uint64Flag struct {
|
|||
Group string
|
||||
}
|
||||
|
||||
func (b *Uint64Flag) UpdateValue(value string) {
|
||||
v, _ := strconv.ParseUint(value, 10, 64)
|
||||
|
||||
*b.Value = v
|
||||
}
|
||||
|
||||
func (f *Flagset) Uint64Flag(i *Uint64Flag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: i.Name,
|
||||
Usage: i.Usage,
|
||||
Group: i.Group,
|
||||
Default: fmt.Sprintf("%d", i.Default),
|
||||
Value: i,
|
||||
})
|
||||
f.set.Uint64Var(i.Value, i.Name, i.Default, i.Usage)
|
||||
}
|
||||
|
|
@ -209,31 +275,47 @@ func (b *BigIntFlag) String() string {
|
|||
return b.Value.String()
|
||||
}
|
||||
|
||||
func (b *BigIntFlag) Set(value string) error {
|
||||
func parseBigInt(value string) *big.Int {
|
||||
num := new(big.Int)
|
||||
|
||||
var ok bool
|
||||
if strings.HasPrefix(value, "0x") {
|
||||
num, ok = num.SetString(value[2:], 16)
|
||||
*b.Value = *num
|
||||
num, _ = num.SetString(value[2:], 16)
|
||||
} else {
|
||||
num, ok = num.SetString(value, 10)
|
||||
*b.Value = *num
|
||||
num, _ = num.SetString(value, 10)
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return num
|
||||
}
|
||||
|
||||
func (b *BigIntFlag) Set(value string) error {
|
||||
num := parseBigInt(value)
|
||||
|
||||
if num == nil {
|
||||
return fmt.Errorf("failed to set big int")
|
||||
}
|
||||
|
||||
*b.Value = *num
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BigIntFlag) UpdateValue(value string) {
|
||||
num := parseBigInt(value)
|
||||
|
||||
if num == nil {
|
||||
return
|
||||
}
|
||||
|
||||
*b.Value = *num
|
||||
}
|
||||
|
||||
func (f *Flagset) BigIntFlag(b *BigIntFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: b.Name,
|
||||
Usage: b.Usage,
|
||||
Group: b.Group,
|
||||
Default: b.Default,
|
||||
Value: b,
|
||||
})
|
||||
f.set.Var(b, b.Name, b.Usage)
|
||||
}
|
||||
|
|
@ -273,6 +355,10 @@ func (i *SliceStringFlag) Set(value string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (i *SliceStringFlag) UpdateValue(value string) {
|
||||
*i.Value = SplitAndTrim(value)
|
||||
}
|
||||
|
||||
func (f *Flagset) SliceStringFlag(s *SliceStringFlag) {
|
||||
if s.Default == nil || len(s.Default) == 0 {
|
||||
f.addFlag(&FlagVar{
|
||||
|
|
@ -280,6 +366,7 @@ func (f *Flagset) SliceStringFlag(s *SliceStringFlag) {
|
|||
Usage: s.Usage,
|
||||
Group: s.Group,
|
||||
Default: nil,
|
||||
Value: s,
|
||||
})
|
||||
} else {
|
||||
f.addFlag(&FlagVar{
|
||||
|
|
@ -287,6 +374,7 @@ func (f *Flagset) SliceStringFlag(s *SliceStringFlag) {
|
|||
Usage: s.Usage,
|
||||
Group: s.Group,
|
||||
Default: strings.Join(s.Default, ","),
|
||||
Value: s,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -301,12 +389,19 @@ type DurationFlag struct {
|
|||
Group string
|
||||
}
|
||||
|
||||
func (d *DurationFlag) UpdateValue(value string) {
|
||||
v, _ := time.ParseDuration(value)
|
||||
|
||||
*d.Value = v
|
||||
}
|
||||
|
||||
func (f *Flagset) DurationFlag(d *DurationFlag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: d.Name,
|
||||
Usage: d.Usage,
|
||||
Group: d.Group,
|
||||
Default: d.Default,
|
||||
Value: d,
|
||||
})
|
||||
f.set.DurationVar(d.Value, d.Name, d.Default, "")
|
||||
}
|
||||
|
|
@ -336,24 +431,38 @@ func (m *MapStringFlag) String() string {
|
|||
return formatMapString(*m.Value)
|
||||
}
|
||||
|
||||
func (m *MapStringFlag) Set(value string) error {
|
||||
if m.Value == nil {
|
||||
m.Value = &map[string]string{}
|
||||
}
|
||||
func parseMap(value string) map[string]string {
|
||||
m := make(map[string]string)
|
||||
|
||||
for _, t := range strings.Split(value, ",") {
|
||||
if t != "" {
|
||||
kv := strings.Split(t, "=")
|
||||
|
||||
if len(kv) == 2 {
|
||||
(*m.Value)[kv[0]] = kv[1]
|
||||
m[kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MapStringFlag) Set(value string) error {
|
||||
if m.Value == nil {
|
||||
m.Value = &map[string]string{}
|
||||
}
|
||||
|
||||
m2 := parseMap(value)
|
||||
*m.Value = m2
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MapStringFlag) UpdateValue(value string) {
|
||||
m2 := parseMap(value)
|
||||
*m.Value = m2
|
||||
}
|
||||
|
||||
func (f *Flagset) MapStringFlag(m *MapStringFlag) {
|
||||
if m.Default == nil || len(m.Default) == 0 {
|
||||
f.addFlag(&FlagVar{
|
||||
|
|
@ -361,6 +470,7 @@ func (f *Flagset) MapStringFlag(m *MapStringFlag) {
|
|||
Usage: m.Usage,
|
||||
Group: m.Group,
|
||||
Default: nil,
|
||||
Value: m,
|
||||
})
|
||||
} else {
|
||||
f.addFlag(&FlagVar{
|
||||
|
|
@ -368,6 +478,7 @@ func (f *Flagset) MapStringFlag(m *MapStringFlag) {
|
|||
Usage: m.Usage,
|
||||
Group: m.Group,
|
||||
Default: formatMapString(m.Default),
|
||||
Value: m,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -382,12 +493,19 @@ type Float64Flag struct {
|
|||
Group string
|
||||
}
|
||||
|
||||
func (f *Float64Flag) UpdateValue(value string) {
|
||||
v, _ := strconv.ParseFloat(value, 64)
|
||||
|
||||
*f.Value = v
|
||||
}
|
||||
|
||||
func (f *Flagset) Float64Flag(i *Float64Flag) {
|
||||
f.addFlag(&FlagVar{
|
||||
Name: i.Name,
|
||||
Usage: i.Usage,
|
||||
Group: i.Group,
|
||||
Default: i.Default,
|
||||
Value: i,
|
||||
})
|
||||
f.set.Float64Var(i.Value, i.Name, i.Default, "")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,176 @@
|
|||
package flagset
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFlagsetBool(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := false
|
||||
value := true
|
||||
f.BoolFlag(&BoolFlag{
|
||||
Name: "flag",
|
||||
Value: &value,
|
||||
})
|
||||
|
||||
assert.NoError(t, f.Parse([]string{"--flag", "true"}))
|
||||
assert.Equal(t, value, true)
|
||||
// Parse no value, should have default (of datatype)
|
||||
require.NoError(t, f.Parse([]string{}))
|
||||
require.Equal(t, false, value)
|
||||
|
||||
// Parse --flag true
|
||||
require.NoError(t, f.Parse([]string{"--flag", "true"}))
|
||||
require.Equal(t, true, value)
|
||||
|
||||
// Parse --flag=true
|
||||
require.NoError(t, f.Parse([]string{"--flag=true"}))
|
||||
require.Equal(t, true, value)
|
||||
|
||||
// Parse --flag false: won't parse false
|
||||
require.NoError(t, f.Parse([]string{"--flag", "false"}))
|
||||
require.Equal(t, true, value)
|
||||
|
||||
// Parse --flag=false
|
||||
require.NoError(t, f.Parse([]string{"--flag=false"}))
|
||||
require.Equal(t, false, value)
|
||||
|
||||
// Parse --flag
|
||||
require.NoError(t, f.Parse([]string{"--flag"}))
|
||||
require.Equal(t, true, value)
|
||||
}
|
||||
|
||||
func TestFlagsetString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := "hello"
|
||||
f.StringFlag(&StringFlag{
|
||||
Name: "flag",
|
||||
Value: &value,
|
||||
})
|
||||
|
||||
// Parse no value, should have default
|
||||
require.NoError(t, f.Parse([]string{}))
|
||||
require.Equal(t, "", value)
|
||||
|
||||
// Parse --flag value
|
||||
require.NoError(t, f.Parse([]string{"--flag", "value"}))
|
||||
require.Equal(t, "value", value)
|
||||
|
||||
// Parse --flag ""
|
||||
require.NoError(t, f.Parse([]string{"--flag", ""}))
|
||||
require.Equal(t, "", value)
|
||||
|
||||
// Parse --flag=newvalue
|
||||
require.NoError(t, f.Parse([]string{"--flag=newvalue"}))
|
||||
require.Equal(t, "newvalue", value)
|
||||
|
||||
// Parse --flag: should fail due to no args
|
||||
require.Error(t, f.Parse([]string{"--flag"}))
|
||||
}
|
||||
|
||||
func TestFlagsetInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := 10
|
||||
f.IntFlag(&IntFlag{
|
||||
Name: "flag",
|
||||
Value: &value,
|
||||
})
|
||||
|
||||
// Parse no value, should have default
|
||||
require.NoError(t, f.Parse([]string{}))
|
||||
require.Equal(t, 0, value)
|
||||
|
||||
// Parse --flag 20
|
||||
require.NoError(t, f.Parse([]string{"--flag", "20"}))
|
||||
require.Equal(t, 20, value)
|
||||
|
||||
// Parse --flag 0
|
||||
require.NoError(t, f.Parse([]string{"--flag", "0"}))
|
||||
require.Equal(t, 0, value)
|
||||
|
||||
// Parse --flag=30
|
||||
require.NoError(t, f.Parse([]string{"--flag=30"}))
|
||||
require.Equal(t, 30, value)
|
||||
|
||||
// Parse --flag: should fail due to no args
|
||||
require.Error(t, f.Parse([]string{"--flag"}))
|
||||
}
|
||||
|
||||
func TestFlagsetFloat64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := 10.0
|
||||
f.Float64Flag(&Float64Flag{
|
||||
Name: "flag",
|
||||
Value: &value,
|
||||
})
|
||||
|
||||
// Parse no value, should have default
|
||||
require.NoError(t, f.Parse([]string{}))
|
||||
require.Equal(t, 0.0, value)
|
||||
|
||||
// Parse --flag 20
|
||||
require.NoError(t, f.Parse([]string{"--flag", "20.1"}))
|
||||
require.Equal(t, 20.1, value)
|
||||
|
||||
// Parse --flag 0
|
||||
require.NoError(t, f.Parse([]string{"--flag", "0"}))
|
||||
require.Equal(t, 0.0, value)
|
||||
|
||||
// Parse --flag 0.0
|
||||
require.NoError(t, f.Parse([]string{"--flag", "0.0"}))
|
||||
require.Equal(t, 0.0, value)
|
||||
|
||||
// Parse --flag=30.1
|
||||
require.NoError(t, f.Parse([]string{"--flag=30.1"}))
|
||||
require.Equal(t, 30.1, value)
|
||||
|
||||
// Parse --flag: should fail due to no args
|
||||
require.Error(t, f.Parse([]string{"--flag"}))
|
||||
}
|
||||
|
||||
func TestFlagsetBigInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := big.NewInt(0)
|
||||
f.BigIntFlag(&BigIntFlag{
|
||||
Name: "flag",
|
||||
Value: value,
|
||||
})
|
||||
|
||||
// Parse no value, should have initial value (0 here)
|
||||
require.NoError(t, f.Parse([]string{}))
|
||||
require.Equal(t, big.NewInt(0), value)
|
||||
|
||||
// Parse --flag 20
|
||||
require.NoError(t, f.Parse([]string{"--flag", "20"}))
|
||||
require.Equal(t, big.NewInt(20), value)
|
||||
|
||||
// Parse --flag=30
|
||||
require.NoError(t, f.Parse([]string{"--flag=30"}))
|
||||
require.Equal(t, big.NewInt(30), value)
|
||||
|
||||
// Parse --flag: should fail due to no args
|
||||
require.Error(t, f.Parse([]string{"--flag"}))
|
||||
}
|
||||
|
||||
func TestFlagsetSliceString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := []string{"a", "b", "c"}
|
||||
|
|
@ -30,13 +180,25 @@ func TestFlagsetSliceString(t *testing.T) {
|
|||
Default: value,
|
||||
})
|
||||
|
||||
assert.NoError(t, f.Parse([]string{}))
|
||||
assert.Equal(t, value, []string{"a", "b", "c"})
|
||||
assert.NoError(t, f.Parse([]string{"--flag", "a,b"}))
|
||||
assert.Equal(t, value, []string{"a", "b"})
|
||||
// Parse no value, should have initial value
|
||||
require.NoError(t, f.Parse([]string{}))
|
||||
require.Equal(t, []string{"a", "b", "c"}, value)
|
||||
|
||||
// Parse --flag a,b
|
||||
require.NoError(t, f.Parse([]string{"--flag", "a,b"}))
|
||||
require.Equal(t, []string{"a", "b"}, value)
|
||||
|
||||
// Parse --flag ""
|
||||
require.NoError(t, f.Parse([]string{"--flag", ""}))
|
||||
require.Equal(t, []string(nil), value)
|
||||
|
||||
// Parse --flag: should fail due to no args
|
||||
require.Error(t, f.Parse([]string{"--flag"}))
|
||||
}
|
||||
|
||||
func TestFlagsetDuration(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := time.Duration(0)
|
||||
|
|
@ -45,11 +207,25 @@ func TestFlagsetDuration(t *testing.T) {
|
|||
Value: &value,
|
||||
})
|
||||
|
||||
assert.NoError(t, f.Parse([]string{"--flag", "1m"}))
|
||||
assert.Equal(t, value, 1*time.Minute)
|
||||
// Parse no value, should have initial value
|
||||
require.NoError(t, f.Parse([]string{}))
|
||||
require.Equal(t, time.Duration(0), value)
|
||||
|
||||
// Parse --flag 1m
|
||||
require.NoError(t, f.Parse([]string{"--flag", "1m"}))
|
||||
require.Equal(t, time.Minute, value)
|
||||
|
||||
// Parse --flag=1h
|
||||
require.NoError(t, f.Parse([]string{"--flag=1h"}))
|
||||
require.Equal(t, time.Hour, value)
|
||||
|
||||
// Parse --flag: should fail due to no args
|
||||
require.Error(t, f.Parse([]string{"--flag"}))
|
||||
}
|
||||
|
||||
func TestFlagsetMapString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
f := NewFlagSet("")
|
||||
|
||||
value := map[string]string{}
|
||||
|
|
@ -58,6 +234,18 @@ func TestFlagsetMapString(t *testing.T) {
|
|||
Value: &value,
|
||||
})
|
||||
|
||||
assert.NoError(t, f.Parse([]string{"--flag", "a=b,c=d"}))
|
||||
assert.Equal(t, value, map[string]string{"a": "b", "c": "d"})
|
||||
// Parse no value, should have initial value
|
||||
require.NoError(t, f.Parse([]string{}))
|
||||
require.Equal(t, map[string]string{}, value)
|
||||
|
||||
// Parse --flag a=b,c=d
|
||||
require.NoError(t, f.Parse([]string{"--flag", "a=b,c=d"}))
|
||||
require.Equal(t, map[string]string{"a": "b", "c": "d"}, value)
|
||||
|
||||
// Parse --flag=x=y
|
||||
require.NoError(t, f.Parse([]string{"--flag=x=y"}))
|
||||
require.Equal(t, map[string]string{"x": "y"}, value)
|
||||
|
||||
// Parse --flag: should fail due to no args
|
||||
require.Error(t, f.Parse([]string{"--flag"}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ var mainnetBor = &Chain{
|
|||
Alloc: readPrealloc("allocs/mainnet.json"),
|
||||
},
|
||||
Bootnodes: []string{
|
||||
"enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303",
|
||||
"enode://88116f4295f5a31538ae409e4d44ad40d22e44ee9342869e7d68bdec55b0f83c1530355ce8b41fbec0928a7d75a5745d528450d30aec92066ab6ba1ee351d710@159.203.9.164:30303",
|
||||
"enode://b8f1cc9c5d4403703fbf377116469667d2b1823c0daf16b7250aa576bacf399e42c3930ccfcb02c5df6879565a2b8931335565f0e8d3f8e72385ecf4a4bf160a@3.36.224.80:30303",
|
||||
"enode://8729e0c825f3d9cad382555f3e46dcff21af323e89025a0e6312df541f4a9e73abfa562d64906f5e59c51fe6f0501b3e61b07979606c56329c020ed739910759@54.194.245.5:30303",
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ var mumbaiTestnet = &Chain{
|
|||
Alloc: readPrealloc("allocs/mumbai.json"),
|
||||
},
|
||||
Bootnodes: []string{
|
||||
"enode://320553cda00dfc003f499a3ce9598029f364fbb3ed1222fdc20a94d97dcc4d8ba0cd0bfa996579dcc6d17a534741fb0a5da303a90579431259150de66b597251@54.147.31.250:30303",
|
||||
"enode://f0f48a8781629f95ff02606081e6e43e4aebd503f3d07fc931fad7dd5ca1ba52bd849a6f6c3be0e375cf13c9ae04d859c4a9ae3546dc8ed4f10aa5dbb47d4998@34.226.134.117:30303",
|
||||
"enode://bdcd4786a616a853b8a041f53496d853c68d99d54ff305615cd91c03cd56895e0a7f6e9f35dbf89131044e2114a9a782b792b5661e3aff07faf125a98606a071@43.200.206.40:30303",
|
||||
"enode://209aaf7ed549cf4a5700fd833da25413f80a1248bd3aa7fe2a87203e3f7b236dd729579e5c8df61c97bf508281bae4969d6de76a7393bcbd04a0af70270333b3@54.216.248.9:30303",
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func (c *Command) MarkDown() string {
|
|||
items := []string{
|
||||
"# Server",
|
||||
"The ```bor server``` command runs the Bor client.",
|
||||
c.Flags().MarkDown(),
|
||||
c.Flags(nil).MarkDown(),
|
||||
}
|
||||
|
||||
return strings.Join(items, "\n\n")
|
||||
|
|
@ -46,7 +46,7 @@ func (c *Command) Help() string {
|
|||
return `Usage: bor [options]
|
||||
|
||||
Run the Bor server.
|
||||
` + c.Flags().Help()
|
||||
` + c.Flags(nil).Help()
|
||||
}
|
||||
|
||||
// Synopsis implements the cli.Command interface
|
||||
|
|
@ -54,40 +54,69 @@ func (c *Command) Synopsis() string {
|
|||
return "Run the Bor server"
|
||||
}
|
||||
|
||||
// checkConfigFlag checks if the config flag is set or not. If set,
|
||||
// it returns the value else an empty string.
|
||||
func checkConfigFlag(args []string) string {
|
||||
for i := 0; i < len(args); i++ {
|
||||
arg := args[i]
|
||||
|
||||
// Check for single or double dashes
|
||||
if strings.HasPrefix(arg, "-config") || strings.HasPrefix(arg, "--config") {
|
||||
parts := strings.SplitN(arg, "=", 2)
|
||||
if len(parts) == 2 {
|
||||
return parts[1]
|
||||
}
|
||||
|
||||
// If there's no equal sign, check the next argument
|
||||
if i+1 < len(args) {
|
||||
return args[i+1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *Command) extractFlags(args []string) error {
|
||||
config := *DefaultConfig()
|
||||
// Check if config file is provided or not
|
||||
configFilePath := checkConfigFlag(args)
|
||||
|
||||
flags := c.Flags()
|
||||
if err := flags.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
c.config = &config
|
||||
if configFilePath != "" {
|
||||
log.Info("Reading config file", "path", configFilePath)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Check if this can be removed or not
|
||||
// read cli flags
|
||||
if err := config.Merge(c.cliConfig); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
c.config = &config
|
||||
|
||||
return err
|
||||
}
|
||||
// read if config file is provided, this will overwrite the cli flags, if provided
|
||||
if c.configFile != "" {
|
||||
log.Warn("Config File provided, this will overwrite the cli flags", "path", c.configFile)
|
||||
|
||||
cfg, err := readConfigFile(c.configFile)
|
||||
// Parse the config file
|
||||
cfg, err := readConfigFile(configFilePath)
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
c.config = &config
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if err := config.Merge(cfg); err != nil {
|
||||
log.Warn("Config set via config file will be overridden by cli flags")
|
||||
|
||||
// Initialse a flagset based on the config created above
|
||||
flags := c.Flags(cfg)
|
||||
|
||||
// Check for explicit cli args
|
||||
cmd := Command{} // use a new variable to keep the original config intact
|
||||
|
||||
cliFlags := cmd.Flags(nil)
|
||||
if err := cliFlags.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the list of flags set explicitly
|
||||
names, values := cliFlags.Visit()
|
||||
|
||||
// Set these flags using the flagset created earlier
|
||||
flags.UpdateValue(names, values)
|
||||
} else {
|
||||
flags := c.Flags(nil)
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
c.config = &config
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
@ -95,33 +124,33 @@ func (c *Command) extractFlags(args []string) error {
|
|||
|
||||
// nolint: nestif
|
||||
// check for log-level and verbosity here
|
||||
if c.configFile != "" {
|
||||
data, _ := toml.LoadFile(c.configFile)
|
||||
if configFilePath != "" {
|
||||
data, _ := toml.LoadFile(configFilePath)
|
||||
if data.Has("verbosity") && data.Has("log-level") {
|
||||
log.Warn("Config contains both, verbosity and log-level, log-level will be deprecated soon. Use verbosity only.", "using", data.Get("verbosity"))
|
||||
} else if !data.Has("verbosity") && data.Has("log-level") {
|
||||
log.Warn("Config contains log-level only, note that log-level will be deprecated soon. Use verbosity instead.", "using", data.Get("log-level"))
|
||||
config.Verbosity = VerbosityStringToInt(strings.ToLower(data.Get("log-level").(string)))
|
||||
c.cliConfig.Verbosity = VerbosityStringToInt(strings.ToLower(data.Get("log-level").(string)))
|
||||
}
|
||||
} else {
|
||||
tempFlag := 0
|
||||
|
||||
for _, val := range args {
|
||||
if (strings.HasPrefix(val, "-verbosity") || strings.HasPrefix(val, "--verbosity")) && config.LogLevel != "" {
|
||||
if (strings.HasPrefix(val, "-verbosity") || strings.HasPrefix(val, "--verbosity")) && c.cliConfig.LogLevel != "" {
|
||||
tempFlag = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if tempFlag == 1 {
|
||||
log.Warn("Both, verbosity and log-level flags are provided, log-level will be deprecated soon. Use verbosity only.", "using", config.Verbosity)
|
||||
} else if tempFlag == 0 && config.LogLevel != "" {
|
||||
log.Warn("Only log-level flag is provided, note that log-level will be deprecated soon. Use verbosity instead.", "using", config.LogLevel)
|
||||
config.Verbosity = VerbosityStringToInt(strings.ToLower(config.LogLevel))
|
||||
log.Warn("Both, verbosity and log-level flags are provided, log-level will be deprecated soon. Use verbosity only.", "using", c.cliConfig.Verbosity)
|
||||
} else if tempFlag == 0 && c.cliConfig.LogLevel != "" {
|
||||
log.Warn("Only log-level flag is provided, note that log-level will be deprecated soon. Use verbosity instead.", "using", c.cliConfig.LogLevel)
|
||||
c.cliConfig.Verbosity = VerbosityStringToInt(strings.ToLower(c.cliConfig.LogLevel))
|
||||
}
|
||||
}
|
||||
|
||||
c.config = &config
|
||||
c.config = c.cliConfig
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,43 +8,135 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFlags(t *testing.T) {
|
||||
// TestFlagsWithoutConfig tests all types of flags passed only
|
||||
// via cli args.
|
||||
func TestFlagsWithoutConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var c Command
|
||||
|
||||
args := []string{
|
||||
"--txpool.rejournal", "30m0s",
|
||||
"--txpool.lifetime", "30m0s",
|
||||
"--miner.gasprice", "20000000000",
|
||||
"--gpo.maxprice", "70000000000",
|
||||
"--gpo.ignoreprice", "1",
|
||||
"--cache.trie.rejournal", "40m0s",
|
||||
"--dev",
|
||||
"--dev.period", "2",
|
||||
"--identity", "",
|
||||
"--datadir", "./data",
|
||||
"--maxpeers", "30",
|
||||
"--verbosity", "3",
|
||||
"--rpc.batchlimit", "0",
|
||||
"--snapshot",
|
||||
"--bor.logs=false",
|
||||
"--eth.requiredblocks", "a=b",
|
||||
"--http.api", "eth,web3,bor",
|
||||
"--miner.gasprice", "30000000000",
|
||||
"--miner.recommit", "20s",
|
||||
"--rpc.evmtimeout", "5s",
|
||||
"--rpc.txfeecap", "6.0",
|
||||
"--http.api", "eth,bor",
|
||||
"--ws.api", "",
|
||||
"--gpo.maxprice", "5000000000000",
|
||||
}
|
||||
|
||||
err := c.extractFlags(args)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
txRe, _ := time.ParseDuration("30m0s")
|
||||
txLt, _ := time.ParseDuration("30m0s")
|
||||
caRe, _ := time.ParseDuration("40m0s")
|
||||
recommit, _ := time.ParseDuration("20s")
|
||||
evmTimeout, _ := time.ParseDuration("5s")
|
||||
|
||||
require.Equal(t, c.config.Identity, "")
|
||||
require.Equal(t, c.config.DataDir, "./data")
|
||||
require.Equal(t, c.config.Developer.Enabled, true)
|
||||
require.Equal(t, c.config.Developer.Period, uint64(2))
|
||||
require.Equal(t, c.config.TxPool.Rejournal, txRe)
|
||||
require.Equal(t, c.config.TxPool.LifeTime, txLt)
|
||||
require.Equal(t, c.config.Sealer.GasPrice, big.NewInt(20000000000))
|
||||
require.Equal(t, c.config.Gpo.MaxPrice, big.NewInt(70000000000))
|
||||
require.Equal(t, c.config.Gpo.IgnorePrice, big.NewInt(1))
|
||||
require.Equal(t, c.config.Cache.Rejournal, caRe)
|
||||
require.Equal(t, c.config.P2P.MaxPeers, uint64(30))
|
||||
require.Equal(t, c.config.Verbosity, 3)
|
||||
require.Equal(t, c.config.RPCBatchLimit, uint64(0))
|
||||
require.Equal(t, c.config.Snapshot, true)
|
||||
require.Equal(t, c.config.BorLogs, false)
|
||||
require.Equal(t, c.config.RequiredBlocks, map[string]string{"a": "b"})
|
||||
require.Equal(t, c.config.JsonRPC.Http.API, []string{"eth", "web3", "bor"})
|
||||
require.Equal(t, c.config.Sealer.GasPrice, big.NewInt(30000000000))
|
||||
require.Equal(t, c.config.Sealer.Recommit, recommit)
|
||||
require.Equal(t, c.config.JsonRPC.RPCEVMTimeout, evmTimeout)
|
||||
require.Equal(t, c.config.JsonRPC.Http.API, []string{"eth", "bor"})
|
||||
require.Equal(t, c.config.JsonRPC.Ws.API, []string(nil))
|
||||
require.Equal(t, c.config.Gpo.MaxPrice, big.NewInt(5000000000000))
|
||||
}
|
||||
|
||||
// TestFlagsWithoutConfig tests all types of flags passed only
|
||||
// via config file.
|
||||
func TestFlagsWithConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var c Command
|
||||
|
||||
args := []string{
|
||||
"--config", "./testdata/test.toml",
|
||||
}
|
||||
|
||||
err := c.extractFlags(args)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
recommit, _ := time.ParseDuration("20s")
|
||||
evmTimeout, _ := time.ParseDuration("5s")
|
||||
|
||||
require.Equal(t, c.config.Identity, "")
|
||||
require.Equal(t, c.config.DataDir, "./data")
|
||||
require.Equal(t, c.config.Verbosity, 3)
|
||||
require.Equal(t, c.config.RPCBatchLimit, uint64(0))
|
||||
require.Equal(t, c.config.Snapshot, true)
|
||||
require.Equal(t, c.config.BorLogs, false)
|
||||
require.Equal(t, c.config.RequiredBlocks,
|
||||
map[string]string{
|
||||
"31000000": "0x2087b9e2b353209c2c21e370c82daa12278efd0fe5f0febe6c29035352cf050e",
|
||||
"32000000": "0x875500011e5eecc0c554f95d07b31cf59df4ca2505f4dbbfffa7d4e4da917c68",
|
||||
},
|
||||
)
|
||||
require.Equal(t, c.config.Sealer.GasPrice, big.NewInt(30000000000))
|
||||
require.Equal(t, c.config.Sealer.Recommit, recommit)
|
||||
require.Equal(t, c.config.JsonRPC.RPCEVMTimeout, evmTimeout)
|
||||
require.Equal(t, c.config.JsonRPC.Http.API, []string{"eth", "bor"})
|
||||
require.Equal(t, c.config.JsonRPC.Ws.API, []string{""})
|
||||
require.Equal(t, c.config.Gpo.MaxPrice, big.NewInt(5000000000000))
|
||||
}
|
||||
|
||||
// TestFlagsWithConfig tests all types of flags passed via both
|
||||
// config file and cli args. The cli args should overwrite the
|
||||
// value of flag.
|
||||
func TestFlagsWithConfigAndFlags(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var c Command
|
||||
|
||||
// Set the config and also override
|
||||
args := []string{
|
||||
"--config", "./testdata/test.toml",
|
||||
"--identity", "Anon",
|
||||
"--datadir", "",
|
||||
"--verbosity", "0",
|
||||
"--rpc.batchlimit", "5",
|
||||
"--snapshot=false",
|
||||
"--bor.logs=true",
|
||||
"--eth.requiredblocks", "x=y",
|
||||
"--miner.gasprice", "60000000000",
|
||||
"--miner.recommit", "30s",
|
||||
"--rpc.evmtimeout", "0s",
|
||||
"--rpc.txfeecap", "0",
|
||||
"--http.api", "",
|
||||
"--ws.api", "eth,bor,web3",
|
||||
"--gpo.maxprice", "0",
|
||||
}
|
||||
|
||||
err := c.extractFlags(args)
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
recommit, _ := time.ParseDuration("30s")
|
||||
evmTimeout, _ := time.ParseDuration("0s")
|
||||
|
||||
require.Equal(t, c.config.Identity, "Anon")
|
||||
require.Equal(t, c.config.DataDir, "")
|
||||
require.Equal(t, c.config.Verbosity, 0)
|
||||
require.Equal(t, c.config.RPCBatchLimit, uint64(5))
|
||||
require.Equal(t, c.config.Snapshot, false)
|
||||
require.Equal(t, c.config.BorLogs, true)
|
||||
require.Equal(t, c.config.RequiredBlocks, map[string]string{"x": "y"})
|
||||
require.Equal(t, c.config.Sealer.GasPrice, big.NewInt(60000000000))
|
||||
require.Equal(t, c.config.Sealer.Recommit, recommit)
|
||||
require.Equal(t, c.config.JsonRPC.RPCEVMTimeout, evmTimeout)
|
||||
require.Equal(t, c.config.JsonRPC.Http.API, []string(nil))
|
||||
require.Equal(t, c.config.JsonRPC.Ws.API, []string{"eth", "bor", "web3"})
|
||||
require.Equal(t, c.config.Gpo.MaxPrice, big.NewInt(0))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ type Config struct {
|
|||
// Ancient is the directory to store the state in
|
||||
Ancient string `hcl:"ancient,optional" toml:"ancient,optional"`
|
||||
|
||||
// DBEngine is used to select leveldb or pebble as database
|
||||
DBEngine string `hcl:"db.engine,optional" toml:"db.engine,optional"`
|
||||
|
||||
// KeyStoreDir is the directory to store keystores
|
||||
KeyStoreDir string `hcl:"keystore,optional" toml:"keystore,optional"`
|
||||
|
||||
|
|
@ -118,6 +121,8 @@ type Config struct {
|
|||
// Cache has the cache related settings
|
||||
Cache *CacheConfig `hcl:"cache,block" toml:"cache,block"`
|
||||
|
||||
ExtraDB *ExtraDBConfig `hcl:"leveldb,block" toml:"leveldb,block"`
|
||||
|
||||
// Account has the validator account related settings
|
||||
Accounts *AccountsConfig `hcl:"accounts,block" toml:"accounts,block"`
|
||||
|
||||
|
|
@ -548,6 +553,13 @@ type CacheConfig struct {
|
|||
FDLimit int `hcl:"fdlimit,optional" toml:"fdlimit,optional"`
|
||||
}
|
||||
|
||||
type ExtraDBConfig struct {
|
||||
LevelDbCompactionTableSize uint64 `hcl:"compactiontablesize,optional" toml:"compactiontablesize,optional"`
|
||||
LevelDbCompactionTableSizeMultiplier float64 `hcl:"compactiontablesizemultiplier,optional" toml:"compactiontablesizemultiplier,optional"`
|
||||
LevelDbCompactionTotalSize uint64 `hcl:"compactiontotalsize,optional" toml:"compactiontotalsize,optional"`
|
||||
LevelDbCompactionTotalSizeMultiplier float64 `hcl:"compactiontotalsizemultiplier,optional" toml:"compactiontotalsizemultiplier,optional"`
|
||||
}
|
||||
|
||||
type AccountsConfig struct {
|
||||
// Unlock is the list of addresses to unlock in the node
|
||||
Unlock []string `hcl:"unlock,optional" toml:"unlock,optional"`
|
||||
|
|
@ -592,6 +604,7 @@ func DefaultConfig() *Config {
|
|||
EnablePreimageRecording: false,
|
||||
DataDir: DefaultDataDir(),
|
||||
Ancient: "",
|
||||
DBEngine: "leveldb",
|
||||
Logging: &LoggingConfig{
|
||||
Vmodule: "",
|
||||
Json: false,
|
||||
|
|
@ -738,6 +751,14 @@ func DefaultConfig() *Config {
|
|||
TrieTimeout: 60 * time.Minute,
|
||||
FDLimit: 0,
|
||||
},
|
||||
ExtraDB: &ExtraDBConfig{
|
||||
// These are LevelDB defaults, specifying here for clarity in code and in logging.
|
||||
// See: https://github.com/syndtr/goleveldb/blob/126854af5e6d8295ef8e8bee3040dd8380ae72e8/leveldb/opt/options.go
|
||||
LevelDbCompactionTableSize: 2, // MiB
|
||||
LevelDbCompactionTableSizeMultiplier: 1,
|
||||
LevelDbCompactionTotalSize: 10, // MiB
|
||||
LevelDbCompactionTotalSizeMultiplier: 10,
|
||||
},
|
||||
Accounts: &AccountsConfig{
|
||||
Unlock: []string{},
|
||||
PasswordFile: "",
|
||||
|
|
@ -1097,6 +1118,14 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
|
|||
n.TriesInMemory = c.Cache.TriesInMemory
|
||||
}
|
||||
|
||||
// LevelDB
|
||||
{
|
||||
n.LevelDbCompactionTableSize = c.ExtraDB.LevelDbCompactionTableSize
|
||||
n.LevelDbCompactionTableSizeMultiplier = c.ExtraDB.LevelDbCompactionTableSizeMultiplier
|
||||
n.LevelDbCompactionTotalSize = c.ExtraDB.LevelDbCompactionTotalSize
|
||||
n.LevelDbCompactionTotalSizeMultiplier = c.ExtraDB.LevelDbCompactionTotalSizeMultiplier
|
||||
}
|
||||
|
||||
n.RPCGasCap = c.JsonRPC.GasCap
|
||||
if n.RPCGasCap != 0 {
|
||||
log.Info("Set global gas cap", "cap", n.RPCGasCap)
|
||||
|
|
@ -1278,6 +1307,7 @@ func (c *Config) buildNode() (*node.Config, error) {
|
|||
cfg := &node.Config{
|
||||
Name: clientIdentifier,
|
||||
DataDir: c.DataDir,
|
||||
DBEngine: c.DBEngine,
|
||||
KeyStoreDir: c.KeyStoreDir,
|
||||
UseLightweightKDF: c.Accounts.UseLightweightKDF,
|
||||
InsecureUnlockAllowed: c.Accounts.AllowInsecureUnlock,
|
||||
|
|
|
|||
|
|
@ -15,21 +15,23 @@ func TestConfigLegacy(t *testing.T) {
|
|||
|
||||
testConfig := DefaultConfig()
|
||||
|
||||
testConfig.Identity = ""
|
||||
testConfig.DataDir = "./data"
|
||||
testConfig.Snapshot = false
|
||||
testConfig.Verbosity = 3
|
||||
testConfig.RPCBatchLimit = 0
|
||||
testConfig.Snapshot = true
|
||||
testConfig.BorLogs = false
|
||||
testConfig.RequiredBlocks = map[string]string{
|
||||
"31000000": "0x2087b9e2b353209c2c21e370c82daa12278efd0fe5f0febe6c29035352cf050e",
|
||||
"32000000": "0x875500011e5eecc0c554f95d07b31cf59df4ca2505f4dbbfffa7d4e4da917c68",
|
||||
}
|
||||
testConfig.P2P.MaxPeers = 30
|
||||
testConfig.TxPool.Locals = []string{}
|
||||
testConfig.TxPool.LifeTime = time.Second
|
||||
testConfig.Sealer.Enabled = true
|
||||
testConfig.Sealer.GasCeil = 30000000
|
||||
testConfig.Sealer.GasPrice = big.NewInt(1000000000)
|
||||
testConfig.Gpo.IgnorePrice = big.NewInt(4)
|
||||
testConfig.Cache.Cache = 1024
|
||||
testConfig.Cache.Rejournal = time.Second
|
||||
testConfig.Sealer.GasPrice = big.NewInt(30000000000)
|
||||
testConfig.Sealer.Recommit = 20 * time.Second
|
||||
testConfig.JsonRPC.RPCEVMTimeout = 5 * time.Second
|
||||
testConfig.JsonRPC.TxFeeCap = 6.0
|
||||
testConfig.JsonRPC.Http.API = []string{"eth", "bor"}
|
||||
testConfig.JsonRPC.Ws.API = []string{""}
|
||||
testConfig.Gpo.MaxPrice = big.NewInt(5000000000000)
|
||||
|
||||
assert.Equal(t, expectedConfig, testConfig)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,12 @@ import (
|
|||
"github.com/ethereum/go-ethereum/internal/cli/flagset"
|
||||
)
|
||||
|
||||
func (c *Command) Flags() *flagset.Flagset {
|
||||
func (c *Command) Flags(config *Config) *flagset.Flagset {
|
||||
if config != nil {
|
||||
c.cliConfig = config
|
||||
} else {
|
||||
c.cliConfig = DefaultConfig()
|
||||
}
|
||||
|
||||
f := flagset.NewFlagSet("server")
|
||||
|
||||
|
|
@ -53,6 +57,12 @@ func (c *Command) Flags() *flagset.Flagset {
|
|||
Value: &c.cliConfig.Ancient,
|
||||
Default: c.cliConfig.Ancient,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "db.engine",
|
||||
Usage: "Backing database implementation to use ('leveldb' or 'pebble')",
|
||||
Value: &c.cliConfig.DBEngine,
|
||||
Default: c.cliConfig.DBEngine,
|
||||
})
|
||||
f.StringFlag(&flagset.StringFlag{
|
||||
Name: "keystore",
|
||||
Usage: "Path of the directory where keystores are located",
|
||||
|
|
@ -442,6 +452,36 @@ func (c *Command) Flags() *flagset.Flagset {
|
|||
Group: "Cache",
|
||||
})
|
||||
|
||||
// LevelDB options
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "leveldb.compaction.table.size",
|
||||
Usage: "LevelDB SSTable/file size in mebibytes",
|
||||
Value: &c.cliConfig.ExtraDB.LevelDbCompactionTableSize,
|
||||
Default: c.cliConfig.ExtraDB.LevelDbCompactionTableSize,
|
||||
Group: "ExtraDB",
|
||||
})
|
||||
f.Float64Flag(&flagset.Float64Flag{
|
||||
Name: "leveldb.compaction.table.size.multiplier",
|
||||
Usage: "Multiplier on LevelDB SSTable/file size. Size for a level is determined by: `leveldb.compaction.table.size * (leveldb.compaction.table.size.multiplier ^ Level)`",
|
||||
Value: &c.cliConfig.ExtraDB.LevelDbCompactionTableSizeMultiplier,
|
||||
Default: c.cliConfig.ExtraDB.LevelDbCompactionTableSizeMultiplier,
|
||||
Group: "ExtraDB",
|
||||
})
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "leveldb.compaction.total.size",
|
||||
Usage: "Total size in mebibytes of SSTables in a given LevelDB level. Size for a level is determined by: `leveldb.compaction.total.size * (leveldb.compaction.total.size.multiplier ^ Level)`",
|
||||
Value: &c.cliConfig.ExtraDB.LevelDbCompactionTotalSize,
|
||||
Default: c.cliConfig.ExtraDB.LevelDbCompactionTotalSize,
|
||||
Group: "ExtraDB",
|
||||
})
|
||||
f.Float64Flag(&flagset.Float64Flag{
|
||||
Name: "leveldb.compaction.total.size.multiplier",
|
||||
Usage: "Multiplier on level size on LevelDB levels. Size for a level is determined by: `leveldb.compaction.total.size * (leveldb.compaction.total.size.multiplier ^ Level)`",
|
||||
Value: &c.cliConfig.ExtraDB.LevelDbCompactionTotalSizeMultiplier,
|
||||
Default: c.cliConfig.ExtraDB.LevelDbCompactionTotalSizeMultiplier,
|
||||
Group: "ExtraDB",
|
||||
})
|
||||
|
||||
// rpc options
|
||||
f.Uint64Flag(&flagset.Uint64Flag{
|
||||
Name: "rpc.gascap",
|
||||
|
|
|
|||
32
internal/cli/server/testdata/test.toml
vendored
32
internal/cli/server/testdata/test.toml
vendored
|
|
@ -1,25 +1,25 @@
|
|||
identity = ""
|
||||
datadir = "./data"
|
||||
snapshot = false
|
||||
verbosity = 3
|
||||
"rpc.batchlimit" = 0
|
||||
snapshot = true
|
||||
"bor.logs" = false
|
||||
|
||||
["eth.requiredblocks"]
|
||||
"31000000" = "0x2087b9e2b353209c2c21e370c82daa12278efd0fe5f0febe6c29035352cf050e"
|
||||
"32000000" = "0x875500011e5eecc0c554f95d07b31cf59df4ca2505f4dbbfffa7d4e4da917c68"
|
||||
|
||||
[p2p]
|
||||
maxpeers = 30
|
||||
|
||||
[txpool]
|
||||
locals = []
|
||||
lifetime = "1s"
|
||||
|
||||
[miner]
|
||||
mine = true
|
||||
gaslimit = 30000000
|
||||
gasprice = "1000000000"
|
||||
gasprice = "30000000000"
|
||||
recommit = "20s"
|
||||
|
||||
[jsonrpc]
|
||||
evmtimeout = "5s"
|
||||
txfeecap = 6.0
|
||||
[jsonrpc.http]
|
||||
api = ["eth", "bor"]
|
||||
[jsonrpc.ws]
|
||||
api = [""]
|
||||
|
||||
[gpo]
|
||||
ignoreprice = "4"
|
||||
|
||||
[cache]
|
||||
cache = 1024
|
||||
rejournal = "1s"
|
||||
maxprice = "5000000000000"
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue