Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
21f42d27c7 | ||
|
a031f9abca | ||
|
47bafe4619 | ||
|
fc0ade482d | ||
|
dbaaef07c7 | ||
|
b9e7398220 | ||
|
1aa98edb04 | ||
|
9794007231 | ||
|
d41612b891 | ||
|
3ef957206c | ||
|
151747bc81 | ||
|
5a6e2ec46f | ||
|
34cc262218 | ||
|
db925906f3 | ||
|
95dde36e1c | ||
|
9301487351 | ||
|
505ad2ab70 | ||
|
d28ef888ff | ||
|
feb9790325 |
@ -1,5 +0,0 @@
|
||||
# Configuration docs: https://bencher.orijtech.com/configuration/
|
||||
suppress_failure_on_regression: false
|
||||
global:
|
||||
reg_min: 10
|
||||
imp_min: -10
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
Language: Proto
|
||||
BasedOnStyle: google
|
||||
ColumnLimit: 120
|
||||
IndentWidth: 2
|
||||
...
|
@ -1,7 +1,5 @@
|
||||
Dockerfile
|
||||
# localnet-setup
|
||||
localnet-setup
|
||||
|
||||
**/node_modules
|
||||
init.sh
|
||||
|
||||
build
|
||||
localnet-setup
|
||||
# build
|
||||
build
|
5
.flake8
5
.flake8
@ -1,5 +0,0 @@
|
||||
[flake8]
|
||||
ignore = BLK100, W503
|
||||
max-line-length = 88
|
||||
extend-ignore = E203
|
||||
exclude = .git,__pycache__,node_modules,.direnv
|
8
.gitattributes
vendored
8
.gitattributes
vendored
@ -1,8 +0,0 @@
|
||||
client/docs/swagger-ui/* linguist-vendored
|
||||
client/docs/statik/* linguist-vendored
|
||||
third-party/* linguist-vendored
|
||||
client/docs/* linguist-documentation
|
||||
docs/* linguist-documentation
|
||||
x/**/spec/* linguist-documentation
|
||||
**/*.pb.go linguist-generated
|
||||
**/*.pb.gw.go linguist-generated
|
@ -1,17 +0,0 @@
|
||||
name: Build
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.21
|
||||
check-latest: true
|
||||
- run: |
|
||||
make build
|
@ -1,20 +0,0 @@
|
||||
name: Deploy Contract
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.21
|
||||
check-latest: true
|
||||
- name: Test contract
|
||||
run: |
|
||||
make contract-tools
|
||||
# This seems to be an empty placeholder.
|
||||
make test-contract
|
@ -1,28 +0,0 @@
|
||||
name: Publish on release
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
jobs:
|
||||
build:
|
||||
name: Run docker build and publish
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run docker build
|
||||
run: docker build -t cerc-io/laconicd -f Dockerfile .
|
||||
- name: Get the version
|
||||
id: vars
|
||||
run: |
|
||||
echo ::set-output name=sha::$(echo ${GITHUB_SHA:0:7})
|
||||
echo ::set-output name=tag::$(echo ${GITHUB_REF#refs/tags/})
|
||||
- name: Tag docker image
|
||||
run: docker tag cerc-io/laconicd git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.sha}}
|
||||
- name: Tag docker image
|
||||
run: docker tag git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.sha}} git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.tag}}
|
||||
- name: Docker Login
|
||||
run: echo ${{ secrets.CICD_PUBLISH_TOKEN }} | docker login https://git.vdb.to -u cerccicd --password-stdin
|
||||
- name: Docker Push
|
||||
run: docker push git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.sha}}
|
||||
- name: Docker Push TAGGED
|
||||
run: docker push git.vdb.to/cerc-io/laconicd/laconicd:${{steps.vars.outputs.tag}}
|
||||
|
@ -1,42 +0,0 @@
|
||||
name: Lint
|
||||
# Lint runs golangci-lint over the entire ethermint repository This workflow is
|
||||
# run on every pull request and push to main The `golangci` will pass without
|
||||
# running if no *.{go, mod, sum} files have been changed.
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
golangci:
|
||||
name: Run golangci-lint
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
# Required: setup-go, for all versions v3.0.0+ of golangci-lint
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.21
|
||||
check-latest: true
|
||||
- uses: actions/checkout@v3
|
||||
- uses: golangci/golangci-lint-action@v3.3.1
|
||||
with:
|
||||
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
||||
version: latest
|
||||
args: --timeout 10m
|
||||
github-token: ${{ secrets.github_token }}
|
||||
|
||||
python-lint:
|
||||
# For compatibility with Gitea
|
||||
env:
|
||||
USER: root
|
||||
name: Run flake8 on python integration tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: cachix/install-nix-action@v20
|
||||
- uses: cachix/cachix-action@v12
|
||||
with:
|
||||
name: ethermint
|
||||
- run: |
|
||||
nix-shell -I nixpkgs=./nix -p test-env --run "make lint-py"
|
@ -1,28 +0,0 @@
|
||||
name: Protobuf
|
||||
# Protobuf runs buf (https://buf.build/) lint and check-breakage
|
||||
# This workflow is only run when a .proto file has been changed
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "proto/**"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: bufbuild/buf-setup-action@v1.9.0
|
||||
- uses: bufbuild/buf-lint-action@v1
|
||||
with:
|
||||
input: "proto"
|
||||
|
||||
break-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: bufbuild/buf-setup-action@v1.9.0
|
||||
- uses: bufbuild/buf-breaking-action@v1
|
||||
with:
|
||||
input: "proto"
|
||||
against: "https://github.com/${{ github.repository }}.git#branch=${{ github.event.pull_request.base.ref }},ref=HEAD~1,subdir=proto"
|
@ -1,21 +0,0 @@
|
||||
name: Tests
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/**
|
||||
|
||||
jobs:
|
||||
test-importer:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.21
|
||||
check-latest: true
|
||||
- uses: actions/checkout@v3
|
||||
- name: test-importer
|
||||
run: |
|
||||
make test-import
|
@ -1,21 +0,0 @@
|
||||
name: Tests
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/**
|
||||
|
||||
jobs:
|
||||
test-rpc:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.21
|
||||
check-latest: true
|
||||
- uses: actions/checkout@v3
|
||||
- name: Test rpc endpoint
|
||||
run: |
|
||||
make test-rpc
|
@ -1,40 +0,0 @@
|
||||
name: Tests
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/**
|
||||
|
||||
jobs:
|
||||
sdk_tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Checkout laconic-sdk
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: "./laconic-sdk/"
|
||||
repository: cerc-io/laconic-sdk
|
||||
fetch-depth: 0
|
||||
ref: main
|
||||
- name: Environment
|
||||
run: ls -tlh && env
|
||||
|
||||
- name: Build laconicd container
|
||||
working-directory: tests/sdk_tests
|
||||
run: ./build-laconicd-container.sh
|
||||
|
||||
- name: Build laconic-sdk container
|
||||
working-directory: laconic-sdk
|
||||
run: ./scripts/build-sdk-test-container.sh
|
||||
|
||||
- name: Start containers (auctions enabled)
|
||||
working-directory: tests/sdk_tests
|
||||
env:
|
||||
TEST_AUCTION_ENABLED: true
|
||||
run: docker compose up -d
|
||||
|
||||
- name: Run auction tests
|
||||
working-directory: tests/sdk_tests
|
||||
run: ./run-tests.sh test:auctions
|
@ -1,40 +0,0 @@
|
||||
name: Tests
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/**
|
||||
|
||||
jobs:
|
||||
sdk_tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Checkout laconic-sdk
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: "./laconic-sdk/"
|
||||
repository: cerc-io/laconic-sdk
|
||||
fetch-depth: 0
|
||||
ref: main
|
||||
- name: Environment
|
||||
run: ls -tlh && env
|
||||
|
||||
- name: Build laconicd container
|
||||
working-directory: tests/sdk_tests
|
||||
run: ./build-laconicd-container.sh
|
||||
|
||||
- name: Build laconic-sdk container
|
||||
working-directory: laconic-sdk
|
||||
run: ./scripts/build-sdk-test-container.sh
|
||||
|
||||
- name: Start containers (expiry enabled)
|
||||
working-directory: tests/sdk_tests
|
||||
env:
|
||||
TEST_REGISTRY_EXPIRY: true
|
||||
run: docker compose up -d
|
||||
|
||||
- name: Run nameservice expiry tests
|
||||
working-directory: tests/sdk_tests
|
||||
run: ./run-tests.sh test:nameservice-expiry
|
@ -1,38 +0,0 @@
|
||||
name: Tests
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/**
|
||||
|
||||
jobs:
|
||||
sdk_tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Checkout laconic-sdk
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: "./laconic-sdk/"
|
||||
repository: cerc-io/laconic-sdk
|
||||
fetch-depth: 0
|
||||
ref: main
|
||||
- name: Environment
|
||||
run: ls -tlh && env
|
||||
|
||||
- name: Build laconicd container
|
||||
working-directory: tests/sdk_tests
|
||||
run: ./build-laconicd-container.sh
|
||||
|
||||
- name: Build laconic-sdk container
|
||||
working-directory: laconic-sdk
|
||||
run: ./scripts/build-sdk-test-container.sh
|
||||
|
||||
- name: Start containers
|
||||
working-directory: tests/sdk_tests
|
||||
run: docker compose up -d
|
||||
|
||||
- name: Run tests
|
||||
working-directory: tests/sdk_tests
|
||||
run: ./run-tests.sh
|
@ -1,23 +0,0 @@
|
||||
name: Tests
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/**
|
||||
|
||||
jobs:
|
||||
test-unit:
|
||||
# This test case doesn't work in CI, run as root.
|
||||
env:
|
||||
SKIP_UNIT_TESTS: TestInitConfigNonNotExistError
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.21
|
||||
check-latest: true
|
||||
- uses: actions/checkout@v3
|
||||
- name: Test
|
||||
run: |
|
||||
make test-unit
|
4
.github/CODEOWNERS
vendored
Normal file
4
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
|
||||
|
||||
# Primary repo maintainers
|
||||
* @fedekunze @khoslaventures @nzoghb
|
18
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: create a bug report
|
||||
---
|
||||
|
||||
__System info:__ [Include Ethermint commit, operating system name, and other relevant details]
|
||||
|
||||
__Steps to reproduce:__
|
||||
|
||||
1. [First Step]
|
||||
2. [Second Step]
|
||||
3. [and so on...]
|
||||
|
||||
__Expected behavior:__ [What you expected to happen]
|
||||
|
||||
__Actual behavior:__ [What actually happened]
|
||||
|
||||
__Additional info:__ [Include gist of relevant config, logs, etc.]
|
15
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
15
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Opening a feature request kicks off a discussion
|
||||
|
||||
---
|
||||
|
||||
__Proposal:__ [Description of the feature]
|
||||
|
||||
__Current behavior:__ [What currently happens]
|
||||
|
||||
__Desired behavior:__ [What you would like to happen]
|
||||
|
||||
__Use case:__ [Why is this important (helps with prioritizing requests)]
|
||||
|
||||
Requests may be closed if we're not actively planning to work on them.
|
34
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
34
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
|
||||
v ✰ Thanks for creating a PR! ✰
|
||||
v Before smashing the submit button please review the checkboxes.
|
||||
v If a checkbox is n/a - please still include it but + a little note why
|
||||
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
|
||||
|
||||
Closes: #XXX
|
||||
|
||||
## Description
|
||||
|
||||
<!-- Add a description of the changes that this PR introduces and the files that
|
||||
are the most critical to review.
|
||||
-->
|
||||
|
||||
______
|
||||
|
||||
For contributor use:
|
||||
|
||||
- [ ] Targeted PR against correct branch (see [CONTRIBUTING.md](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
|
||||
- [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
|
||||
- [ ] Code follows the [module structure standards](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/structure.md).
|
||||
- [ ] Wrote unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
|
||||
- [ ] Updated relevant documentation (`docs/`) or specification (`x/<module>/spec/`)
|
||||
- [ ] Added relevant `godoc` [comments](https://blog.golang.org/godoc-documenting-go-code).
|
||||
- [ ] Added a relevant changelog entry to the `Unreleased` section in `CHANGELOG.md`
|
||||
- [ ] Re-reviewed `Files changed` in the Github PR explorer
|
||||
|
||||
______
|
||||
|
||||
For admin use:
|
||||
|
||||
- [ ] Added appropriate labels to PR (ex. `WIP`, `R4R`, `docs`, etc)
|
||||
- [ ] Reviewers assigned
|
||||
- [ ] Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr))
|
28
.github/dependabot.yml
vendored
Normal file
28
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- fedekunze
|
||||
- khoslaventures
|
||||
labels:
|
||||
- dependencies
|
||||
- package-ecosystem: docker
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- fedekunze
|
||||
- khoslaventures
|
||||
- package-ecosystem: gomod
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
37
.github/labeler.yml
vendored
Normal file
37
.github/labeler.yml
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
"C:Crypto":
|
||||
- crypto/**/*
|
||||
"C:Encoding":
|
||||
- encoding/**/*
|
||||
"C:JSON-RPC":
|
||||
- ethereum/rpc/**/*
|
||||
"C:Proto":
|
||||
- proto/**/*
|
||||
- third_party/**/*
|
||||
- /**/*.pb.go
|
||||
- /**/*.pb.gw.go
|
||||
"C:Types":
|
||||
- types/**/*
|
||||
"C:x/evm":
|
||||
- x/evm/**/*/
|
||||
"Type: Build":
|
||||
- Makefile
|
||||
- Dockerfile
|
||||
- docker-compose.yml
|
||||
- scripts/*
|
||||
- config.yml
|
||||
"Type: CI":
|
||||
- .github/**/*.yml
|
||||
- buf.yaml
|
||||
- .mergify.yml
|
||||
- .golangci.yml
|
||||
"C:CLI":
|
||||
- client/**/*
|
||||
- x/*/client/**/*
|
||||
"Type: Tests":
|
||||
- tests/**/*
|
||||
- /**/*/*_test.go
|
||||
"Type: Docs":
|
||||
- docs/**/*
|
||||
- x/*/spec/**/*
|
||||
"Type: ADR":
|
||||
- docs/architecture/**/*
|
29
.github/workflows/build-docs.yml
vendored
Normal file
29
.github/workflows/build-docs.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
name: Docs build
|
||||
# This workflow runs when a PR is labeled with `docs`
|
||||
# This will check if the docs build successfully by running `npm run build`
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/*
|
||||
|
||||
jobs:
|
||||
check-docs-build:
|
||||
name: Check docs build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
id: git_diff
|
||||
with:
|
||||
PATTERNS: |
|
||||
docs/*
|
||||
SUFFIX_FILTER: |
|
||||
.md
|
||||
- name: Install dependencies and build docs 🧱
|
||||
run: |
|
||||
make build-docs
|
29
.github/workflows/build.yml
vendored
Normal file
29
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
name: Build
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
cleanup-runs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: rokroskar/workflow-run-cleanup-action@master
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/main'"
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
id: git_diff
|
||||
with:
|
||||
SUFFIX_FILTER: |
|
||||
.go
|
||||
.mod
|
||||
.sum
|
||||
- run: |
|
||||
make build
|
||||
if: "env.GIT_DIFF != ''"
|
19
.github/workflows/clean-artifacts.yml
vendored
Normal file
19
.github/workflows/clean-artifacts.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Remove old artifacts
|
||||
# Remove old artifacts runs a crob job that removes old artifacts
|
||||
# generated from the split tests workflow.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Every day at 1am
|
||||
- cron: "0 1 * * *"
|
||||
|
||||
jobs:
|
||||
remove-old-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Remove old artifacts
|
||||
uses: c-hive/gha-remove-artifacts@v1.2.0
|
||||
with:
|
||||
age: "7 days"
|
71
.github/workflows/codeql-analysis.yml
vendored
Normal file
71
.github/workflows/codeql-analysis.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '37 21 * * 4'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go', 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
38
.github/workflows/deploy-contract.yml
vendored
Normal file
38
.github/workflows/deploy-contract.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: Deploy Contract
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
cleanup-runs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: rokroskar/workflow-run-cleanup-action@master
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/main'"
|
||||
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v2.4.0
|
||||
with:
|
||||
node-version: '12.x'
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
id: git_diff
|
||||
with:
|
||||
SUFFIX_FILTER: |
|
||||
.go
|
||||
.mod
|
||||
.sum
|
||||
.sol
|
||||
- name: Test contract
|
||||
run: |
|
||||
sudo make contract-tools
|
||||
sudo make test-contract
|
||||
if: "env.GIT_DIFF != ''"
|
@ -9,20 +9,19 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment: release
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.21
|
||||
check-latest: true
|
||||
go-version: 1.17
|
||||
- name: release dry run
|
||||
run: make release-dry-run
|
||||
- name: setup release environment
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.CICD_PUBLISH_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |-
|
||||
echo 'GITHUB_TOKEN=${{secrets.CICD_PUBLISH_TOKEN}}' > .release-env
|
||||
echo 'GITHUB_TOKEN=${{secrets.GITHUB_TOKEN}}' > .release-env
|
||||
- name: release publish
|
||||
run: make release
|
||||
run: make release
|
14
.github/workflows/labeler.yml
vendored
Normal file
14
.github/workflows/labeler.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
name: "Pull Request Labeler"
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v3
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
12
.github/workflows/linkchecker.yml
vendored
Normal file
12
.github/workflows/linkchecker.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
name: Check Markdown links
|
||||
on:
|
||||
schedule:
|
||||
- cron: "* */24 * * *"
|
||||
jobs:
|
||||
markdown-link-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: gaurav-nelson/github-action-markdown-link-check@1.0.13
|
||||
with:
|
||||
folder-path: "docs"
|
30
.github/workflows/lint.yml
vendored
Normal file
30
.github/workflows/lint.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: Lint
|
||||
# Lint runs golangci-lint over the entire ethermint repository This workflow is
|
||||
# run on every pull request and push to main The `golangci` will pass without
|
||||
# running if no *.{go, mod, sum} files have been changed.
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
golangci:
|
||||
name: Run golangci-lint
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
with:
|
||||
SUFFIX_FILTER: |
|
||||
.go
|
||||
.mod
|
||||
.sum
|
||||
- uses: golangci/golangci-lint-action@v2.5.2
|
||||
with:
|
||||
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
||||
version: v1.29
|
||||
args: --timeout 10m
|
||||
github-token: ${{ secrets.github_token }}
|
||||
# Check only if there are differences in the source code
|
||||
if: "env.GIT_DIFF"
|
30
.github/workflows/proto.yml
vendored
Normal file
30
.github/workflows/proto.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: Protobuf
|
||||
# Protobuf runs buf (https://buf.build/) lint and check-breakage
|
||||
# This workflow is only run when a .proto file has been changed
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
with:
|
||||
PATTERNS: |
|
||||
**/**.proto
|
||||
- name: lint
|
||||
run: make proto-lint
|
||||
if: env.GIT_DIFF
|
||||
breakage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
with:
|
||||
PATTERNS: |
|
||||
**/**.proto
|
||||
- name: check-breakage
|
||||
run: make proto-check-breaking
|
||||
if: env.GIT_DIFF
|
21
.github/workflows/stale.yml
vendored
Normal file
21
.github/workflows/stale.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: "Close stale issues & pull requests"
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v4
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-pr-message: "This pull request has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed in 7 days-before-close if no further activity occurs."
|
||||
stale-issue-message: "This issue is stale because it has been open 45 days with no activity. Remove `Status: Stale` label or comment or this will be closed in 7 days."
|
||||
days-before-stale: 45
|
||||
days-before-close: 7
|
||||
exempt-issue-labels: "Status: Blocked, Type: Bug, pinned, automerge"
|
||||
exempt-pr-labels: "Status: Blocked, Type: Bug, pinned, automerge"
|
||||
stale-pr-label: "Status: Stale"
|
||||
stale-issue-label: "Status: Stale"
|
125
.github/workflows/test.yml
vendored
Normal file
125
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
name: Tests
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release/**
|
||||
|
||||
jobs:
|
||||
cleanup-runs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: rokroskar/workflow-run-cleanup-action@master
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/main'"
|
||||
|
||||
install-tparse:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v2.1.4
|
||||
with:
|
||||
go-version: 1.17
|
||||
- name: Display Go Version
|
||||
run: go version
|
||||
- name: Install tparse
|
||||
run: |
|
||||
export GO111MODULE="on" && go get github.com/mfridman/tparse@latest
|
||||
- uses: actions/cache@v2.1.6
|
||||
with:
|
||||
path: ~/go/bin
|
||||
key: ${{ runner.os }}-go-tparse-binary
|
||||
|
||||
test-unit-cover:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v2.1.4
|
||||
with:
|
||||
go-version: 1.17
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
with:
|
||||
PATTERNS: |
|
||||
**/**.sol
|
||||
**/**.go
|
||||
go.mod
|
||||
go.sum
|
||||
- name: Test and Create Coverage Report
|
||||
run: |
|
||||
make test-unit-cover
|
||||
if: env.GIT_DIFF
|
||||
- uses: codecov/codecov-action@v2.1.0
|
||||
with:
|
||||
file: ./coverage.txt
|
||||
fail_ci_if_error: true
|
||||
if: env.GIT_DIFF
|
||||
|
||||
# TODO: refactor before enabling
|
||||
# test-importer:
|
||||
# runs-on: ubuntu-latest
|
||||
# timeout-minutes: 10
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2.3.4
|
||||
# - uses: actions/setup-go@v2.1.4
|
||||
# with:
|
||||
# go-version: 1.17
|
||||
# - uses: technote-space/get-diff-action@v5
|
||||
# id: git_diff
|
||||
# with:
|
||||
# SUFFIX_FILTER: |
|
||||
# .go
|
||||
# .mod
|
||||
# .sum
|
||||
# - name: test-importer
|
||||
# run: |
|
||||
# make test-import
|
||||
# if: "env.GIT_DIFF != ''"
|
||||
|
||||
test-solidity:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
id: git_diff
|
||||
with:
|
||||
PATTERNS: |
|
||||
**/**.sol
|
||||
**/**.go
|
||||
go.mod
|
||||
go.sum
|
||||
- name: test-solidity
|
||||
run: |
|
||||
make test-solidity
|
||||
if: "env.GIT_DIFF != ''"
|
||||
|
||||
liveness-test:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: actions/setup-go@v2.1.4
|
||||
with:
|
||||
go-version: 1.17
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
id: git_diff
|
||||
with:
|
||||
PATTERNS: |
|
||||
**/**.go
|
||||
go.mod
|
||||
go.sum
|
||||
- name: Install Starport
|
||||
run: |
|
||||
curl https://get.starport.network/starport! | bash
|
||||
if: env.GIT_DIFF
|
||||
- name: Start Local Network via Starport
|
||||
run: |
|
||||
starport chain serve --reset-once -v -c ./starport.yml > starport.out 2>&1 &
|
||||
if: env.GIT_DIFF
|
||||
- name: Test Local Network Liveness
|
||||
run: |
|
||||
sleep 2m
|
||||
./contrib/scripts/test_localnet_liveness.sh 100 5 50 localhost
|
||||
if: env.GIT_DIFF
|
||||
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -13,7 +13,6 @@
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
.dccache
|
||||
|
||||
# Build
|
||||
*.test
|
||||
@ -35,14 +34,10 @@ keyring_test_cosmos
|
||||
./**/node_modules
|
||||
./**/dist
|
||||
secret.yml
|
||||
artifacts/*
|
||||
tmp-swagger-gen
|
||||
github.com/
|
||||
# vue/
|
||||
|
||||
# Local docker volume mappings
|
||||
localnet-setup
|
||||
.testnets
|
||||
|
||||
# Testing
|
||||
coverage.txt
|
||||
@ -50,7 +45,6 @@ coverage.txt
|
||||
sim_log_file
|
||||
tests/**/tmp/*
|
||||
yarn.lock
|
||||
x/auction/client/testutil/bidder-bafyre*
|
||||
|
||||
# Vagrant
|
||||
.vagrant/
|
||||
@ -61,7 +55,6 @@ vagrant
|
||||
# IDE
|
||||
.idea/
|
||||
*.iml
|
||||
*.code-workspace
|
||||
|
||||
# Graphviz
|
||||
dependency-graph.png
|
||||
@ -76,8 +69,5 @@ dependency-graph.png
|
||||
*.abi
|
||||
|
||||
# Node.js
|
||||
**/node_modules
|
||||
|
||||
|
||||
# OpenZeppelin contracts
|
||||
contracts/@openzeppelin/*
|
||||
tests/**/node_modules/*
|
||||
tests-solidity/**/node_modules/*
|
2766
.gitleaks.toml
2766
.gitleaks.toml
File diff suppressed because it is too large
Load Diff
@ -6,34 +6,46 @@ run:
|
||||
linters:
|
||||
enable:
|
||||
- bodyclose
|
||||
# - depguard # 20231120 disable until https://github.com/golangci/golangci-lint/issues/3906 is released
|
||||
- deadcode
|
||||
- depguard
|
||||
- dogsled
|
||||
- dupl
|
||||
- errcheck
|
||||
- goconst
|
||||
- gocritic
|
||||
- gofumpt
|
||||
# - revive # 20231120 overly sensitive unused detection
|
||||
- gofmt
|
||||
- goimports
|
||||
- golint
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- lll
|
||||
# - lll TODO: enable
|
||||
- misspell
|
||||
- maligned
|
||||
- nakedret
|
||||
- prealloc
|
||||
- exportloopref
|
||||
- scopelint
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
- nolintlint
|
||||
- asciicheck
|
||||
# - exhaustive
|
||||
- exportloopref
|
||||
- gofumpt
|
||||
- gomodguard
|
||||
- whitespace
|
||||
# - nestif
|
||||
# - nlreturn
|
||||
- noctx
|
||||
- rowserrcheck
|
||||
# - whitespace
|
||||
# - wsl
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
@ -46,8 +58,6 @@ issues:
|
||||
max-same-issues: 50
|
||||
|
||||
linters-settings:
|
||||
lll:
|
||||
line-length: 150
|
||||
dogsled:
|
||||
max-blank-identifiers: 3
|
||||
golint:
|
||||
@ -62,7 +72,7 @@ linters-settings:
|
||||
require-explanation: false
|
||||
require-specific: false
|
||||
gofumpt:
|
||||
lang-version: "1.19"
|
||||
lang-version: "1.17"
|
||||
gomodguard:
|
||||
blocked:
|
||||
versions: # List of blocked module version constraints
|
||||
|
@ -106,4 +106,4 @@ changelog:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
snapshot:
|
||||
name_template: "{{ .Tag }}-next"
|
||||
name_template: "{{ .Tag }}-next"
|
||||
|
@ -1,21 +0,0 @@
|
||||
"default": true
|
||||
"MD001": false
|
||||
"MD004": false
|
||||
"MD007":
|
||||
"indent": 4
|
||||
"MD013": false
|
||||
"MD024":
|
||||
"siblings_only": true
|
||||
"MD025": false
|
||||
"MD026":
|
||||
"punctuation": ".;:"
|
||||
"MD029": false
|
||||
"MD033": false
|
||||
"MD034": false
|
||||
"MD036": false
|
||||
"MD040": false
|
||||
"MD041": false
|
||||
"MD051": false
|
||||
"MD049":
|
||||
"style": "asterisk"
|
||||
"no-hard-tabs": false
|
@ -1,3 +0,0 @@
|
||||
CHANGELOG.md
|
||||
docs/api/proto-docs.md
|
||||
docs/node_modules
|
37
.mergify.yml
37
.mergify.yml
@ -1,41 +1,10 @@
|
||||
queue_rules:
|
||||
- name: default
|
||||
conditions:
|
||||
- "#approved-reviews-by>1"
|
||||
|
||||
pull_request_rules:
|
||||
- name: automerge to main with label "automerge" and branch protection passing
|
||||
- name: automerge to base branch with label automerge and branch protection passing
|
||||
conditions:
|
||||
- "#approved-reviews-by>1"
|
||||
- base=main
|
||||
- label=automerge
|
||||
actions:
|
||||
queue:
|
||||
name: default
|
||||
merge:
|
||||
method: squash
|
||||
commit_message_template: |
|
||||
{{ title }} (#{{ number }})
|
||||
{{ body }}
|
||||
- name: backport patches to main branch
|
||||
conditions:
|
||||
- label=backport/main
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- main
|
||||
- name: backport patches to v0.20.x branch
|
||||
conditions:
|
||||
- base=main
|
||||
- label=backport/0.20.x
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- release/v0.20.x
|
||||
- name: backport patches to v0.19.x branch
|
||||
conditions:
|
||||
- base=main
|
||||
- label=backport/0.19.x
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- release/v0.19.x
|
||||
strict: true
|
||||
|
174
.protolint.yml
174
.protolint.yml
@ -1,174 +0,0 @@
|
||||
---
|
||||
# Lint directives.
|
||||
lint:
|
||||
# # Linter files to ignore.
|
||||
# ignores:
|
||||
# - id: MESSAGE_NAMES_UPPER_CAMEL_CASE
|
||||
# files:
|
||||
# # NOTE: UNIX paths will be properly accepted by both UNIX and Windows.
|
||||
# - _example/proto/simple.proto
|
||||
# - id: ENUM_NAMES_UPPER_CAMEL_CASE
|
||||
# files:
|
||||
# - path/to/foo.proto
|
||||
|
||||
# # Linter files to walk.
|
||||
# files:
|
||||
# # The specific files to exclude.
|
||||
# exclude:
|
||||
# # NOTE: UNIX paths will be properly accepted by both UNIX and Windows.
|
||||
# - path/to/file
|
||||
|
||||
# # Linter directories to walk.
|
||||
# directories:
|
||||
# # The specific directories to exclude.
|
||||
# exclude:
|
||||
# # NOTE: UNIX paths will be properly accepted by both UNIX and Windows.
|
||||
# - path/to/dir
|
||||
|
||||
# Linter rules.
|
||||
# Run `protolint list` to see all available rules.
|
||||
rules:
|
||||
# Determines whether or not to include the default set of linters.
|
||||
no_default: true
|
||||
|
||||
# Set the default to all linters. This option works the other way around as no_default does.
|
||||
# If you want to enable this option, delete the comment out below and no_default.
|
||||
# all_default: true
|
||||
|
||||
# The specific linters to add.
|
||||
add:
|
||||
- FIELD_NAMES_LOWER_SNAKE_CASE
|
||||
- MESSAGE_NAMES_UPPER_CAMEL_CASE
|
||||
- MAX_LINE_LENGTH
|
||||
- INDENT
|
||||
# - SERVICE_NAMES_END_WITH
|
||||
- FIELD_NAMES_EXCLUDE_PREPOSITIONS
|
||||
- MESSAGE_NAMES_EXCLUDE_PREPOSITIONS
|
||||
- FILE_NAMES_LOWER_SNAKE_CASE
|
||||
- IMPORTS_SORTED
|
||||
- PACKAGE_NAME_LOWER_CASE
|
||||
- ORDER
|
||||
- MESSAGES_HAVE_COMMENT
|
||||
- SERVICES_HAVE_COMMENT
|
||||
- RPCS_HAVE_COMMENT
|
||||
- FIELDS_HAVE_COMMENT
|
||||
- PROTO3_FIELDS_AVOID_REQUIRED
|
||||
- PROTO3_GROUPS_AVOID
|
||||
# - REPEATED_FIELD_NAMES_PLURALIZED
|
||||
- ENUMS_HAVE_COMMENT
|
||||
- ENUM_FIELDS_HAVE_COMMENT
|
||||
- SYNTAX_CONSISTENT
|
||||
- RPC_NAMES_UPPER_CAMEL_CASE
|
||||
# - FILE_HAS_COMMENT
|
||||
- QUOTE_CONSISTENT
|
||||
|
||||
# # The specific linters to remove.
|
||||
# remove:
|
||||
# - RPC_NAMES_UPPER_CAMEL_CASE
|
||||
|
||||
# Linter rules option.
|
||||
rules_option:
|
||||
# MAX_LINE_LENGTH rule option.
|
||||
max_line_length:
|
||||
# Enforces a maximum line length
|
||||
max_chars: 120
|
||||
# Specifies the character count for tab characters
|
||||
tab_chars: 2
|
||||
|
||||
# INDENT rule option.
|
||||
indent:
|
||||
# Available styles are 4(4-spaces), 2(2-spaces) or tab.
|
||||
style: 2
|
||||
# Specifies if it should stop considering and inserting new lines at the appropriate positions
|
||||
# when the inner elements are on the same line. Default is false.
|
||||
not_insert_newline: true
|
||||
|
||||
# # FILE_NAMES_LOWER_SNAKE_CASE rule option.
|
||||
# file_names_lower_snake_case:
|
||||
# excludes:
|
||||
# - ../proto/invalidFileName.proto
|
||||
|
||||
# QUOTE_CONSISTENT rule option.
|
||||
quote_consistent:
|
||||
# Available quote are "double" or "single".
|
||||
quote: double
|
||||
|
||||
# ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH rule option.
|
||||
enum_field_names_zero_value_end_with:
|
||||
suffix: INVALID
|
||||
|
||||
# # SERVICE_NAMES_END_WITH rule option.
|
||||
# service_names_end_with:
|
||||
# text: Service
|
||||
|
||||
# FIELD_NAMES_EXCLUDE_PREPOSITIONS rule option.
|
||||
field_names_exclude_prepositions:
|
||||
# The specific prepositions to determine if the field name includes.
|
||||
prepositions:
|
||||
- for
|
||||
- at
|
||||
- of
|
||||
# The specific keywords including prepositions to ignore. E.g. end_of_support is a term you would like to use, and skip checking.
|
||||
excludes:
|
||||
- duration_of_decay
|
||||
|
||||
# # REPEATED_FIELD_NAMES_PLURALIZED rule option.
|
||||
# ## The spec for each rules follows the implementation of https://github.com/gertd/go-pluralize.
|
||||
# ## Plus, you can refer to this rule's test code.
|
||||
# repeated_field_names_pluralized:
|
||||
# uncountable_rules:
|
||||
# - paper
|
||||
# irregular_rules:
|
||||
# Irregular: Regular
|
||||
|
||||
# MESSAGE_NAMES_EXCLUDE_PREPOSITIONS rule option.
|
||||
message_names_exclude_prepositions:
|
||||
# The specific prepositions to determine if the message name includes.
|
||||
prepositions:
|
||||
- With
|
||||
- For
|
||||
- Of
|
||||
# # The specific keywords including prepositions to ignore. E.g. EndOfSupport is a term you would like to use, and skip checking.
|
||||
# excludes:
|
||||
# - EndOfSupport
|
||||
|
||||
# # RPC_NAMES_CASE rule option.
|
||||
# rpc_names_case:
|
||||
# # The specific convention the name should conforms to.
|
||||
# ## Available conventions are "lower_camel_case", "upper_snake_case", or "lower_snake_case".
|
||||
# convention: upper_snake_case
|
||||
|
||||
# MESSAGES_HAVE_COMMENT rule option.
|
||||
messages_have_comment:
|
||||
# Comments need to begin with the name of the thing being described. default is false.
|
||||
should_follow_golang_style: true
|
||||
|
||||
# SERVICES_HAVE_COMMENT rule option.
|
||||
services_have_comment:
|
||||
# Comments need to begin with the name of the thing being described. default is false.
|
||||
should_follow_golang_style: true
|
||||
|
||||
# RPCS_HAVE_COMMENT rule option.
|
||||
rpcs_have_comment:
|
||||
# Comments need to begin with the name of the thing being described. default is false.
|
||||
should_follow_golang_style: true
|
||||
|
||||
# FIELDS_HAVE_COMMENT rule option.
|
||||
fields_have_comment:
|
||||
# Comments need to begin with the name of the thing being described. default is false.
|
||||
should_follow_golang_style: true
|
||||
|
||||
# ENUMS_HAVE_COMMENT rule option.
|
||||
enums_have_comment:
|
||||
# Comments need to begin with the name of the thing being described. default is false.
|
||||
should_follow_golang_style: true
|
||||
|
||||
# ENUM_FIELDS_HAVE_COMMENT rule option.
|
||||
enum_fields_have_comment:
|
||||
# Comments need to begin with the name of the thing being described. default is false.
|
||||
should_follow_golang_style: true
|
||||
|
||||
# # SYNTAX_CONSISTENT rule option.
|
||||
# syntax_consistent:
|
||||
# # Default is proto3.
|
||||
# version: proto2
|
@ -1,32 +0,0 @@
|
||||
# Ignore git items
|
||||
.gitignore
|
||||
.git/
|
||||
:include .gitignore
|
||||
|
||||
# Common large paths
|
||||
node_modules/
|
||||
build/
|
||||
dist/
|
||||
vendor/
|
||||
.env/
|
||||
.venv/
|
||||
.tox/
|
||||
*.min.js
|
||||
*.pb.gw.go
|
||||
|
||||
# Common test paths
|
||||
test/
|
||||
tests/
|
||||
*_test.go
|
||||
|
||||
# false positive; TODO: https://github.com/cerc-io/laconicd/issues/104
|
||||
testutil/network/network.go
|
||||
|
||||
# Semgrep rules folder
|
||||
.semgrep
|
||||
|
||||
# Semgrep-action log folder
|
||||
.semgrep_logs/
|
||||
|
||||
# Documentation
|
||||
client/docs/
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "solhint:default"
|
||||
}
|
31
.yamllint
31
.yamllint
@ -1,31 +0,0 @@
|
||||
---
|
||||
|
||||
yaml-files:
|
||||
- '*.yaml'
|
||||
- '*.yml'
|
||||
- '.yamllint'
|
||||
|
||||
rules:
|
||||
braces: enable
|
||||
brackets: enable
|
||||
colons: enable
|
||||
commas: enable
|
||||
comments:
|
||||
level: warning
|
||||
comments-indentation: disable
|
||||
document-end: disable
|
||||
document-start: disable
|
||||
empty-lines: disable
|
||||
empty-values: disable
|
||||
float-values: disable
|
||||
hyphens: enable
|
||||
indentation: enable
|
||||
key-duplicates: enable
|
||||
key-ordering: disable
|
||||
line-length: disable
|
||||
new-line-at-end-of-file: enable
|
||||
new-lines: enable
|
||||
octal-values: disable
|
||||
quoted-strings: disable
|
||||
trailing-spaces: disable
|
||||
truthy: disable
|
793
CHANGELOG.md
793
CHANGELOG.md
@ -1,4 +1,3 @@
|
||||
|
||||
<!--
|
||||
Guiding Principles:
|
||||
|
||||
@ -36,645 +35,135 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
# Changelog
|
||||
|
||||
## [v0.20.0] - 2022-12-28
|
||||
## Unreleased
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (deps) [#1564](https://github.com/evmos/ethermint/pull/1564) Bump ibc-go to [`v5.2.0`](https://github.com/cosmos/ibc-go/releases/tag/v5.2.0)
|
||||
* (evm) [\#1272](https://github.com/evmos/ethermint/pull/1272) Implement modular interface for the EVM.
|
||||
* (deps) [#1551](https://github.com/evmos/ethermint/pull/1551) Upgrade Cosmos SDK to [`v0.46.7`](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.46.7).
|
||||
* (feemarket) [#1194](https://github.com/evmos/ethermint/pull/1194) Apply feemarket to native cosmos tx.
|
||||
* (eth) [#1346](https://github.com/evmos/ethermint/pull/1346) Added support for `sdk.Dec` and `ed25519` type on eip712.
|
||||
* (evm) [#1452](https://github.com/evmos/ethermint/pull/1452) Simplify Gas Math in `ApplyTransaction`.
|
||||
* (eth) [#1430](https://github.com/evmos/ethermint/pull/1430) Added support for array of type `Any` on eip712.
|
||||
* (ante) [1460](https://github.com/evmos/ethermint/pull/1460) Add KV Gas config on ethereum Txs.
|
||||
* (eth) [#1459](https://github.com/evmos/ethermint/pull/1459) Added support for messages with optional types omitted on eip712.
|
||||
* (geth) [#1413](https://github.com/evmos/ethermint/pull/1413) Update go-ethereum version to [`v1.10.26`](https://github.com/ethereum/go-ethereum/releases/tag/v1.10.26).
|
||||
* (deps) [#1419](https://github.com/evmos/ethermint/pull/1419) Add ics23 patch for dragonberry and bump iavl to v0.19.4
|
||||
* (app) [tharsis#476](https://github.com/tharsis/ethermint/pull/476) Update Bech32 HRP to `ethm`.
|
||||
* (evm) [tharsis#556](https://github.com/tharsis/ethermint/pull/556) Remove tx logs and block bloom from chain state
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (ante) [#1521](https://github.com/evmos/ethermint/pull/1521) Deprecate support for legacy EIP-712 signature verification implementation via AnteHandler decorator.
|
||||
* (ante) [#1214](https://github.com/evmos/ethermint/pull/1214) Set mempool priority to EVM transactions.
|
||||
* (evm) [#1405](https://github.com/evmos/ethermint/pull/1405) Add parameter `chainID` to evm keeper's `EVMConfig` method, so caller can choose to not use the cached `eip155ChainID`.
|
||||
* (evm) [tharsis#469](https://github.com/tharsis/ethermint/pull/469) Deprecate `YoloV3Block` and `EWASMBlock` from `ChainConfig`
|
||||
|
||||
### Features
|
||||
|
||||
* (ci) [#1528](https://github.com/evmos/ethermint/pull/1528) Add Golang dependency vulnerability checker.
|
||||
* (app) [#1501](https://github.com/evmos/ethermint/pull/1501) Set default File store listener for application from [ADR38](https://docs.cosmos.network/v0.47/architecture/adr-038-state-listening)
|
||||
* (evm) [tharsis#469](https://github.com/tharsis/ethermint/pull/469) Support [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)
|
||||
* (evm) [tharsis#417](https://github.com/tharsis/ethermint/pull/417) Add `EvmHooks` for tx post-processing
|
||||
* (rpc) [tharsis#506](https://github.com/tharsis/ethermint/pull/506) Support for `debug_traceTransaction` RPC endpoint
|
||||
* (rpc) [tharsis#555](https://github.com/tharsis/ethermint/pull/555) Support for `debug_traceBlockByNumber` RPC endpoint
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (encoding) [tharsis#478](https://github.com/tharsis/ethermint/pull/478) Register `Evidence` to amino codec.
|
||||
* (rpc) [tharsis#478](https://github.com/tharsis/ethermint/pull/481) Getting the node configuration when calling the `miner` rpc methods.
|
||||
* (cli) [tharsis#561](https://github.com/tharsis/ethermint/pull/561) `Export` and `Start` commands now use the same home directory.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (tests) [#1507](https://github.com/evmos/ethermint/pull/1507) Remove legacy sim tests
|
||||
* (feemarket) [#1508](https://github.com/evmos/ethermint/pull/1508) Remove old x/params migration logic
|
||||
* (evm) [#1499](https://github.com/evmos/ethermint/pull/1499) Add Shanghai and Cancun block
|
||||
* (ante) [#1455](https://github.com/evmos/ethermint/pull/1455) Refactor `AnteHandler` logic
|
||||
* (evm) [#1444](https://github.com/evmos/ethermint/pull/1444) Improve performance of `eth_estimateGas`
|
||||
* (ante) [\#1388](https://github.com/evmos/ethermint/pull/1388) Optimize AnteHandler gas consumption
|
||||
* (lint) [#1298](https://github.com/evmos/ethermint/pull/1298) 150 character line length limit, `gofumpt`, and linting
|
||||
* (feemarket) [\#1165](https://github.com/evmos/ethermint/pull/1165) Add hint in specs about different gas terminology in Cosmos and Ethereum.
|
||||
* (cli) [#1226](https://github.com/evmos/ethermint/pull/1226) Add custom app db backend flag.
|
||||
* (ante) [#1289](https://github.com/evmos/ethermint/pull/1289) Change the fallback tx priority mechanism to be based on gas price.
|
||||
* (test) [#1311](https://github.com/evmos/ethermint/pull/1311) Add integration test for the `rollback` cmd
|
||||
* (ledger) [#1277](https://github.com/evmos/ethermint/pull/1277) Add Ledger preprocessing transaction hook for EIP-712-signed Cosmos payloads.
|
||||
* (rpc) [#1296](https://github.com/evmos/ethermint/pull/1296) Add RPC Backend unit tests.
|
||||
* (rpc) [#1352](https://github.com/evmos/ethermint/pull/1352) Make the grpc queries run concurrently, don't block the consensus state machine.
|
||||
* (cli) [#1360](https://github.com/evmos/ethermint/pull/1360) Introduce a new `grpc-only` flag, such that when enabled, will start the node in a query-only mode. Note, gRPC MUST be enabled with this flag.
|
||||
* (rpc) [#1378](https://github.com/evmos/ethermint/pull/1378) Add support for EVM RPC metrics
|
||||
* (ante) [#1390](https://github.com/evmos/ethermint/pull/1390) Added multisig tx support.
|
||||
* (test) [#1396](https://github.com/evmos/ethermint/pull/1396) Increase test coverage for the EVM module `keeper`
|
||||
* (ante) [#1397](https://github.com/evmos/ethermint/pull/1397) Refactor EIP-712 signature verification to support EIP-712 multi-signing.
|
||||
* (deps) [#1416](https://github.com/evmos/ethermint/pull/1416) Bump Go version to `1.19`
|
||||
* (cmd) [\#1417](https://github.com/evmos/ethermint/pull/1417) Apply Google CLI Syntax for required and optional args.
|
||||
* (deps) [#1456](https://github.com/evmos/ethermint/pull/1456) Migrate errors-related functionality from "github.com/cosmos/cosmos-sdk/types/errors" (deprecated) to "cosmossdk.io/errors"
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (deps) [#1361](https://github.com/evmos/ethermint/pull/1361) Bump ibc-go to [`v5.0.0`](https://github.com/cosmos/ibc-go/releases/tag/v5.0.0)
|
||||
* (evm) [\#1272](https://github.com/evmos/ethermint/pull/1272) Implement modular interface for the EVM.
|
||||
* (deps) [#1168](https://github.com/evmos/ethermint/pull/1168) Upgrade Cosmos SDK to `v0.46`.
|
||||
* (feemarket) [#1194](https://github.com/evmos/ethermint/pull/1194) Apply feemarket to native cosmos tx.
|
||||
* (eth) [#1346](https://github.com/evmos/ethermint/pull/1346) Added support for `sdk.Dec` and `ed25519` type on eip712.
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (ante) [#1214](https://github.com/evmos/ethermint/pull/1214) Set mempool priority to EVM transactions.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (lint) [#1298](https://github.com/evmos/ethermint/pull/1298) 150 character line length limit, `gofumpt`, and linting
|
||||
* (feemarket) [\#1165](https://github.com/evmos/ethermint/pull/1165) Add hint in specs about different gas terminology in Cosmos and Ethereum.
|
||||
* (cli) [#1226](https://github.com/evmos/ethermint/pull/1226) Add custom app db backend flag.
|
||||
* (ante) [#1289](https://github.com/evmos/ethermint/pull/1289) Change the fallback tx priority mechanism to be based on gas price.
|
||||
* (test) [#1311](https://github.com/evmos/ethermint/pull/1311) Add integration test for the `rollback` cmd
|
||||
* (ledger) [#1277](https://github.com/evmos/ethermint/pull/1277) Add Ledger preprocessing transaction hook for EIP-712-signed Cosmos payloads.
|
||||
* (rpc) [#1296](https://github.com/evmos/ethermint/pull/1296) Add RPC Backend unit tests.
|
||||
* (rpc) [#1352](https://github.com/evmos/ethermint/pull/1352) Make the grpc queries run concurrently, don't block the consensus state machine.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [#1561](https://github.com/evmos/ethermint/pull/1561) Fix call to `NewMnemonic` in `personal_newAccount`
|
||||
* (cli) [#1550](https://github.com/evmos/ethermint/pull/1550) Fix signature algorithm validation and default for Ledger.
|
||||
* (eip712) [#1543](https://github.com/evmos/ethermint/pull/1543) Improve error handling for EIP-712 encoding config initialization.
|
||||
* (app) [#1505](https://github.com/evmos/ethermint/pull/1505) Setup gRPC node service with the application.
|
||||
* (server) [#1497](https://github.com/evmos/ethermint/pull/1497) Fix telemetry server setup for observability
|
||||
* (rpc) [#1442](https://github.com/evmos/ethermint/pull/1442) Fix decoding of `finalized` block number.
|
||||
* (rpc) [#1179](https://github.com/evmos/ethermint/pull/1179) Fix gas used in traceTransaction response.
|
||||
* (rpc) [#1284](https://github.com/evmos/ethermint/pull/1284) Fix internal trace response upon incomplete `eth_sendTransaction` call.
|
||||
* (rpc) [#1340](https://github.com/evmos/ethermint/pull/1340) Fix error response when `eth_estimateGas` height provided is not found.
|
||||
* (rpc) [#1354](https://github.com/evmos/ethermint/pull/1354) Fix grpc query failure(`BaseFee` and `EthCall`) on legacy block states.
|
||||
* (cli) [#1362](https://github.com/evmos/ethermint/pull/1362) Fix `index-eth-tx` error when the indexer db is empty.
|
||||
* (state) [#1320](https://github.com/evmos/ethermint/pull/1320) Fix codehash check mismatch when the code has been deleted in the evm state.
|
||||
* (rpc) [#1392](https://github.com/evmos/ethermint/pull/1392) Allow fill the proposer address in json-rpc through tendermint api, and pass explicitly to grpc query handler.
|
||||
* (rpc) [#1431](https://github.com/evmos/ethermint/pull/1431) Align hex-strings proof fields in `eth_getProof` as Ethereum.
|
||||
* (proto) [#1466](https://github.com/evmos/ethermint/pull/1466) Fix proto scripts and upgrade them to mirror current cosmos-sdk scripts
|
||||
* (rpc) [#1405](https://github.com/evmos/ethermint/pull/1405) Fix uninitialized chain ID field in gRPC requests.
|
||||
* (analytics) [#1434](https://github.com/evmos/ethermint/pull/1434) Remove unbound labels from custom tendermint metrics.
|
||||
* (rpc) [#1484](https://github.com/evmos/ethermint/pull/1484) Align empty account result for old blocks as ethereum instead of return account not found error.
|
||||
* (rpc) [#1503](https://github.com/evmos/ethermint/pull/1503) Fix block hashes returned on JSON-RPC filter `eth_newBlockFilter`.
|
||||
* (ante) [#1566](https://github.com/evmos/ethermint/pull/1566) Fix `gasWanted` on `EthGasConsumeDecorator` ante handler when running transaction in `ReCheckMode`
|
||||
|
||||
## [v0.19.3] - 2022-10-14
|
||||
|
||||
* (deps) [1381](https://github.com/evmos/ethermint/pull/1381) Bump sdk to `v0.45.9`
|
||||
|
||||
## [v0.19.2] - 2022-08-29
|
||||
|
||||
### Improvements
|
||||
|
||||
* (deps) [1301](https://github.com/evmos/ethermint/pull/1301) Bump Cosmos SDK to `v0.45.8`, Tendermint to `v0.34.21`, IAVL to `v0.19.1` & store options
|
||||
|
||||
## [v0.19.1] - 2022-08-26
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (eth) [#1305](https://github.com/evmos/ethermint/pull/1305) Added support for optional params, basic types arrays and `time` type on eip712.
|
||||
|
||||
## [v0.19.0] - 2022-08-15
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (deps) [#1159](https://github.com/evmos/ethermint/pull/1159) Bump Geth version to `v1.10.19`.
|
||||
* (ante) [#1176](https://github.com/evmos/ethermint/pull/1176) Fix invalid tx hashes; Remove `Size_` field and validate `Hash`/`From` fields in ante handler,
|
||||
recompute eth tx hashes in JSON-RPC APIs to fix old blocks.
|
||||
* (ante) [#1173](https://github.com/evmos/ethermint/pull/1173) Make `NewAnteHandler` return error if input is invalid
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (rpc) [#1121](https://github.com/tharsis/ethermint/pull/1121) Implement Ethereum tx indexer
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [#1179](https://github.com/evmos/ethermint/pull/1179) Fix gas used in `debug_traceTransaction` response.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (test) [#1196](https://github.com/evmos/ethermint/pull/1196) Integration tests setup
|
||||
* (test) [#1199](https://github.com/evmos/ethermint/pull/1199) Add backend test suite with mock gRPC query client
|
||||
* (test) [#1189](https://github.com/evmos/ethermint/pull/1189) JSON-RPC unit tests
|
||||
* (test) [#1212](https://github.com/evmos/ethermint/pull/1212) Prune node integration tests
|
||||
* (test) [#1207](https://github.com/evmos/ethermint/pull/1207) JSON-RPC types integration tests
|
||||
* (test) [#1218](https://github.com/evmos/ethermint/pull/1218) Restructure JSON-RPC API
|
||||
* (rpc) [#1229](https://github.com/evmos/ethermint/pull/1229) Add support for configuring RPC `MaxOpenConnections`
|
||||
* (cli) [#1230](https://github.com/evmos/ethermint/pull/1230) Remove redundant positional height parameter from feemarket's query cli.
|
||||
* (test)[#1233](https://github.com/evmos/ethermint/pull/1233) Add filters integration tests
|
||||
|
||||
## [v0.18.0] - 2022-08-04
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (evm) [\#1234](https://github.com/evmos/ethermint/pull/1234) Fix [CVE-2022-35936](https://github.com/evmos/ethermint/security/advisories/GHSA-f92v-grc2-w2fg) security vulnerability.
|
||||
* (evm) [\#1174](https://github.com/evmos/ethermint/pull/1174) Don't allow eth txs with 0 in mempool.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (ante) [\#1208](https://github.com/evmos/ethermint/pull/1208) Change default `MaxGasWanted` value.
|
||||
|
||||
## [v0.17.2] - 2022-07-26
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [\#1190](https://github.com/evmos/ethermint/issues/1190) Fix `UnmarshalJSON` panic of breaking EVM and fee market `Params`.
|
||||
* (evm) [\#1187](https://github.com/evmos/ethermint/pull/1187) Fix `TxIndex` value (expected 0, actual 1) when trace the first tx of a block via `debug_traceTransaction` API.
|
||||
|
||||
## [v0.17.1] - 2022-07-13
|
||||
|
||||
### Improvements
|
||||
|
||||
* (rpc) [\#1169](https://github.com/evmos/ethermint/pull/1169) Remove unnecessary queries from `getBlockNumber` function
|
||||
|
||||
## [v0.17.0] - 2022-06-27
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (evm) [\#1128](https://github.com/evmos/ethermint/pull/1128) Clear tx logs if tx failed in post processing hooks
|
||||
* (evm) [\#1124](https://github.com/evmos/ethermint/pull/1124) Reject non-replay-protected tx in `AnteHandler` to prevent replay attack
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (rpc) [\#1126](https://github.com/evmos/ethermint/pull/1126) Make some JSON-RPC APIS work for pruned nodes.
|
||||
* (rpc) [\#1143](https://github.com/evmos/ethermint/pull/1143) Restrict unprotected txs on the node JSON-RPC configuration.
|
||||
* (all) [\#1137](https://github.com/evmos/ethermint/pull/1137) Rename go module to `evmos/ethermint`
|
||||
|
||||
### API Breaking
|
||||
|
||||
- (json-rpc) [tharsis#1121](https://github.com/tharsis/ethermint/pull/1121) Store eth tx index separately
|
||||
|
||||
### Improvements
|
||||
|
||||
* (deps) [\#1147](https://github.com/evmos/ethermint/pull/1147) Bump Go version to `1.18`.
|
||||
* (feemarket) [\#1135](https://github.com/evmos/ethermint/pull/1135) Set lower bound of base fee to min gas price param
|
||||
* (evm) [\#1142](https://github.com/evmos/ethermint/pull/1142) Rename `RejectUnprotectedTx` to `AllowUnprotectedTxs` for consistency with go-ethereum.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [\#1138](https://github.com/evmos/ethermint/pull/1138) Fix GasPrice calculation with relation to `MinGasPrice`
|
||||
|
||||
## [v0.16.1] - 2022-06-09
|
||||
|
||||
### Improvements
|
||||
|
||||
* (feemarket) [\#1120](https://github.com/evmos/ethermint/pull/1120) Make `min-gas-multiplier` parameter accept zero value
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (evm) [\#1118](https://github.com/evmos/ethermint/pull/1118) Fix `Type()` `Account` method `EmptyCodeHash` comparison
|
||||
|
||||
## [v0.16.0] - 2022-06-06
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (feemarket) [tharsis#1105](https://github.com/evmos/ethermint/pull/1105) Update `BaseFee` calculation based on `GasWanted` instead of `GasUsed`.
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (feemarket) [tharsis#1104](https://github.com/evmos/ethermint/pull/1104) Enforce a minimum gas price for Cosmos and EVM transactions through the `MinGasPrice` parameter.
|
||||
* (rpc) [tharsis#1081](https://github.com/evmos/ethermint/pull/1081) Deduplicate some json-rpc logic codes, cleanup several dead functions.
|
||||
* (ante) [tharsis#1062](https://github.com/evmos/ethermint/pull/1062) Emit event of eth tx hash in ante handler to support query failed transactions.
|
||||
* (analytics) [tharsis#1106](https://github.com/evmos/ethermint/pull/1106) Update telemetry to Ethermint modules.
|
||||
* (rpc) [tharsis#1108](https://github.com/evmos/ethermint/pull/1108) Update GetGasPrice RPC endpoint with global `MinGasPrice`
|
||||
|
||||
### Improvements
|
||||
|
||||
* (cli) [tharsis#1086](https://github.com/evmos/ethermint/pull/1086) Add rollback command.
|
||||
* (specs) [tharsis#1095](https://github.com/evmos/ethermint/pull/1095) Add more evm specs concepts.
|
||||
* (evm) [tharsis#1101](https://github.com/evmos/ethermint/pull/1101) Add tx_type, gas and counter telemetry for ethereum txs.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [tharsis#1082](https://github.com/evmos/ethermint/pull/1082) fix gas price returned in getTransaction api.
|
||||
* (evm) [tharsis#1088](https://github.com/evmos/ethermint/pull/1088) Fix ability to append log in tx post processing.
|
||||
* (rpc) [tharsis#1081](https://github.com/evmos/ethermint/pull/1081) fix `debug_getBlockRlp`/`debug_printBlock` don't filter failed transactions.
|
||||
* (ante) [tharsis#1111](https://github.com/evmos/ethermint/pull/1111) Move CanTransfer decorator before GasConsume decorator
|
||||
* (types) [tharsis#1112](https://github.com/evmos/ethermint/pull/1112) Add `GetBaseAccount` to avoid invalid account error when create vesting account.
|
||||
|
||||
## [v0.15.0] - 2022-05-09
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (ante) [tharsis#1060](https://github.com/evmos/ethermint/pull/1060) Check `EnableCreate`/`EnableCall` in `AnteHandler` to short-circuit EVM transactions.
|
||||
* (evm) [tharsis#1087](https://github.com/evmos/ethermint/pull/1087) Minimum GasUsed proportional to GasLimit and `MinGasDenominator` EVM module param.
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (rpc) [tharsis#1070](https://github.com/evmos/ethermint/pull/1070) Refactor `rpc/` package:
|
||||
* `Backend` interface is now `BackendI`, which implements `EVMBackend` (for Ethereum namespaces) and `CosmosBackend` (for Cosmos namespaces)
|
||||
* Previous `EVMBackend` type is now `Backend`, which is the concrete implementation of `BackendI`
|
||||
* Move `rpc/ethereum/types` -> `rpc/types`
|
||||
* Move `rpc/ethereum/backend` -> `rpc/backend`
|
||||
* Move `rpc/ethereum/namespaces` -> `rpc/namespaces/ethereum`
|
||||
* (rpc) [tharsis#1068](https://github.com/evmos/ethermint/pull/1068) Fix London hard-fork check logic in JSON-RPC APIs.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (ci, evm) [tharsis#1063](https://github.com/evmos/ethermint/pull/1063) Run simulations on CI.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [tharsis#1059](https://github.com/evmos/ethermint/pull/1059) Remove unnecessary event filtering logic on the `eth_baseFee` JSON-RPC endpoint.
|
||||
|
||||
## [v0.14.0] - 2022-04-19
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (evm) [tharsis#1051](https://github.com/evmos/ethermint/pull/1051) Context block height fix on TraceTx. Removes `tx_index` on `QueryTraceTxRequest` proto type.
|
||||
* (evm) [tharsis#1091](https://github.com/evmos/ethermint/pull/1091) Add query params command on EVM Module
|
||||
|
||||
### Improvements
|
||||
|
||||
* (deps) [tharsis#1046](https://github.com/evmos/ethermint/pull/1046) Bump Cosmos SDK version to [`v0.45.3`](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.45.3)
|
||||
* (rpc) [tharsis#1056](https://github.com/evmos/ethermint/pull/1056) Make json-rpc namespaces extensible
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [tharsis#1050](https://github.com/evmos/ethermint/pull/1050) `eth_getBlockByNumber` fix on batch transactions
|
||||
* (app) [tharsis#658](https://github.com/evmos/ethermint/issues/658) Support simulations for the EVM.
|
||||
|
||||
## [v0.13.0] - 2022-04-05
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (evm) [tharsis#1027](https://github.com/evmos/ethermint/pull/1027) Change the `PostTxProcessing` hook interface to include the full message data.
|
||||
* (feemarket) [tharsis#1026](https://github.com/evmos/ethermint/pull/1026) Fix REST endpoints to use `/ethermint/feemarket/*` instead of `/feemarket/evm/*`.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (deps) [tharsis#1029](https://github.com/evmos/ethermint/pull/1029) Bump Cosmos SDK version to [`v0.45.2`](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.45.2)
|
||||
* (evm) [tharsis#1025](https://github.com/evmos/ethermint/pull/1025) Allow to append logs after a post processing hook.
|
||||
|
||||
## [v0.12.2] - 2022-03-30
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (feemarket) [tharsis#1021](https://github.com/evmos/ethermint/pull/1021) Fix fee market migration.
|
||||
|
||||
## [v0.12.1] - 2022-03-29
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (evm) [tharsis#1016](https://github.com/evmos/ethermint/pull/1016) Update validate basic check for storage state.
|
||||
|
||||
## [v0.12.0] - 2022-03-24
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [tharsis#1012](https://github.com/evmos/ethermint/pull/1012) fix the tx hash in filter entries created by `eth_newPendingTransactionFilter`.
|
||||
* (rpc) [tharsis#1006](https://github.com/evmos/ethermint/pull/1006) Use `string` as the parameters type to correct ambiguous results.
|
||||
* (ante) [tharsis#1004](https://github.com/evmos/ethermint/pull/1004) Make `MaxTxGasWanted` configurable.
|
||||
* (ante) [tharsis#991](https://github.com/evmos/ethermint/pull/991) Set an upper bound to gasWanted to prevent DoS attack.
|
||||
* (rpc) [tharsis#990](https://github.com/evmos/ethermint/pull/990) Calculate reward values from all `MsgEthereumTx` from a block in `eth_feeHistory`.
|
||||
|
||||
## [v0.11.0] - 2022-03-06
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (ante) [tharsis#964](https://github.com/evmos/ethermint/pull/964) add NewInfiniteGasMeterWithLimit for storing the user provided gas limit. Fixes block's consumed gas calculation in the block creation phase.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [tharsis#975](https://github.com/evmos/ethermint/pull/975) Fix unexpected `nil` values for `reward`, returned by `EffectiveGasTipValue(blockBaseFee)` in the `eth_feeHistory` RPC method.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (rpc) [tharsis#979](https://github.com/evmos/ethermint/pull/979) Add configurable timeouts to http server
|
||||
* (rpc) [tharsis#988](https://github.com/evmos/ethermint/pull/988) json-rpc server always use local rpc client
|
||||
|
||||
## [v0.10.1] - 2022-03-04
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [tharsis#970](https://github.com/evmos/ethermint/pull/970) Fix unexpected nil reward values on `eth_feeHistory` response
|
||||
* (evm) [tharsis#529](https://github.com/evmos/ethermint/issues/529) Add support return value on trace tx response.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (rpc) [tharsis#968](https://github.com/evmos/ethermint/pull/968) Add some buffer to returned gas price to provide better default UX for client.
|
||||
|
||||
## [v0.10.0] - 2022-02-26
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (ante) [tharsis#866](https://github.com/evmos/ethermint/pull/866) `NewAnteHandler` constructor now receives a `HandlerOptions` field.
|
||||
* (evm) [tharsis#849](https://github.com/evmos/ethermint/pull/849) `PostTxProcessing` hook now takes an Ethereum tx `Receipt` and a `from` `Address` as arguments.
|
||||
* (ante) [tharsis#916](https://github.com/evmos/ethermint/pull/916) Don't check min-gas-price for eth tx if london hardfork enabled and feemarket enabled.
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (deps) [tharsis#912](https://github.com/evmos/ethermint/pull/912) Bump Cosmos SDK version to [`v0.45.1`](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.45.1)
|
||||
* (evm) [tharsis#840](https://github.com/evmos/ethermint/pull/840) Store empty topics as empty array rather than nil.
|
||||
* (feemarket) [tharsis#822](https://github.com/evmos/ethermint/pull/822) Update EIP1559 base fee in `BeginBlock`.
|
||||
* (evm) [tharsis#817](https://github.com/evmos/ethermint/pull/817) Use `effectiveGasPrice` in ante handler, add `effectiveGasPrice` to tx receipt.
|
||||
* (evm) [tharsis#808](https://github.com/evmos/ethermint/issues/808) increase nonce in ante handler for contract creation transaction.
|
||||
* (evm) [tharsis#851](https://github.com/evmos/ethermint/pull/851) fix contract address used in EVM, this issue is caused by [tharsis#808](https://github.com/evmos/ethermint/issues/808).
|
||||
* (evm) Reject invalid `MsgEthereumTx` wrapping tx
|
||||
* (evm) Fix `SelfDestruct` opcode by deleting account code and state.
|
||||
* (feemarket) [tharsis#855](https://github.com/evmos/ethermint/pull/855) Consistent `BaseFee` check logic.
|
||||
* (evm) [tharsis#729](https://github.com/evmos/ethermint/pull/729) Refactor EVM `StateDB` implementation.
|
||||
* (evm) [tharsis#945](https://github.com/evmos/ethermint/pull/945) Bumb Go-ethereum version to [`v1.10.16`](https://github.com/ethereum/go-ethereum/releases/tag/v1.10.16)
|
||||
|
||||
### Features
|
||||
|
||||
* (ante) [tharsis#950](https://github.com/evmos/ethermint/pull/950) Add support for EIP712 signed Cosmos transactions
|
||||
|
||||
### Improvements
|
||||
|
||||
* (types) [tharsis#884](https://github.com/evmos/ethermint/pull/884) Introduce a new `EthAccountI` interface for EVM-compatible account types.
|
||||
* (types) [tharsis#849](https://github.com/evmos/ethermint/pull/849) Add `Type` function to distinguish EOAs from Contract accounts.
|
||||
* (evm) [tharsis#826](https://github.com/evmos/ethermint/issues/826) Improve allocation of bytes of `tx.To` address.
|
||||
* (evm) [tharsis#827](https://github.com/evmos/ethermint/issues/827) Speed up creation of event logs by using the slice insertion idiom with indices.
|
||||
* (ante) [tharsis#819](https://github.com/evmos/ethermint/pull/819) Remove redundant ante handlers
|
||||
* (app) [tharsis#873](https://github.com/evmos/ethermint/pull/873) Validate code hash in GenesisAccount
|
||||
* (evm) [tharsis#901](https://github.com/evmos/ethermint/pull/901) Support multiple `MsgEthereumTx` in single tx.
|
||||
* (config) [tharsis#908](https://github.com/evmos/ethermint/pull/908) Add `api.enable` flag for Cosmos SDK Rest server
|
||||
* (feemarket) [tharsis#919](https://github.com/evmos/ethermint/pull/919) Initialize baseFee in default genesis state.
|
||||
* (feemarket) [tharsis#943](https://github.com/evmos/ethermint/pull/943) Store the base fee as a module param instead of using state storage.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [tharsis#955](https://github.com/evmos/ethermint/pull/955) Fix websocket server push duplicated messages to subscriber.
|
||||
* (rpc) [tharsis#953](https://github.com/evmos/ethermint/pull/953) Add `eth_signTypedData` api support.
|
||||
* (log) [tharsis#948](https://github.com/evmos/ethermint/pull/948) Redirect go-ethereum's logs to cosmos-sdk logger.
|
||||
* (evm) [tharsis#884](https://github.com/evmos/ethermint/pull/884) Support multiple account types on the EVM `StateDB`.
|
||||
* (rpc) [tharsis#831](https://github.com/evmos/ethermint/pull/831) Fix BaseFee value when height is specified.
|
||||
* (evm) [tharsis#838](https://github.com/evmos/ethermint/pull/838) Fix splitting of trace.Memory into 32 chunks.
|
||||
* (rpc) [tharsis#860](https://github.com/evmos/ethermint/pull/860) Fix `eth_getLogs` when specify blockHash without address/topics, and limit the response size.
|
||||
* (rpc) [tharsis#865](https://github.com/evmos/ethermint/pull/865) Fix RPC Filter parameters being ignored
|
||||
* (evm) [tharsis#871](https://github.com/evmos/ethermint/pull/871) Set correct nonce in `EthCall` and `EstimateGas` grpc query.
|
||||
* (rpc) [tharsis#878](https://github.com/evmos/ethermint/pull/878) Workaround to make GetBlock RPC api report correct block gas used.
|
||||
* (rpc) [tharsis#900](https://github.com/evmos/ethermint/pull/900) `newPendingTransactions` filter return ethereum tx hash.
|
||||
* (rpc) [tharsis#933](https://github.com/evmos/ethermint/pull/933) Fix `newPendingTransactions` subscription deadlock when a Websocket client exits without unsubscribing and the node errors.
|
||||
* (evm) [tharsis#932](https://github.com/evmos/ethermint/pull/932) Fix base fee check logic in state transition.
|
||||
|
||||
## [v0.9.0] - 2021-12-01
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (evm) [tharsis#802](https://github.com/evmos/ethermint/pull/802) Clear access list for each transaction
|
||||
|
||||
### Improvements
|
||||
|
||||
* (app) [tharsis#794](https://github.com/evmos/ethermint/pull/794) Setup in-place store migrators.
|
||||
* (ci) [tharsis#784](https://github.com/evmos/ethermint/pull/784) Enable automatic backport of PRs.
|
||||
* (rpc) [tharsis#786](https://github.com/evmos/ethermint/pull/786) Improve error message of `SendTransaction`/`SendRawTransaction` JSON-RPC APIs.
|
||||
* (rpc) [tharsis#810](https://github.com/evmos/ethermint/pull/810) Optimize tx index lookup in web3 rpc
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (license) [tharsis#800](https://github.com/evmos/ethermint/pull/800) Re-license project to [LGPLv3](https://choosealicense.com/licenses/lgpl-3.0/#) to comply with go-ethereum.
|
||||
* (evm) [tharsis#794](https://github.com/evmos/ethermint/pull/794) Register EVM gRPC `Msg` server.
|
||||
* (rpc) [tharsis#781](https://github.com/evmos/ethermint/pull/781) Fix get block invalid transactions filter.
|
||||
* (rpc) [tharsis#782](https://github.com/evmos/ethermint/pull/782) Fix wrong block gas limit returned by JSON-RPC.
|
||||
* (evm) [tharsis#798](https://github.com/evmos/ethermint/pull/798) Fix the semantic of `ForEachStorage` callback's return value
|
||||
|
||||
## [v0.8.1] - 2021-11-23
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (feemarket) [tharsis#770](https://github.com/evmos/ethermint/pull/770) Enable fee market (EIP1559) by default.
|
||||
* (rpc) [tharsis#769](https://github.com/evmos/ethermint/pull/769) Fix default Ethereum signer for JSON-RPC.
|
||||
|
||||
## [v0.8.0] - 2021-11-17
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (evm, ante) [tharsis#620](https://github.com/evmos/ethermint/pull/620) Add fee market field to EVM `Keeper` and `AnteHandler`.
|
||||
* (all) [tharsis#231](https://github.com/evmos/ethermint/pull/231) Bump go-ethereum version to [`v1.10.9`](https://github.com/ethereum/go-ethereum/releases/tag/v1.10.9)
|
||||
* (ante) [tharsis#703](https://github.com/evmos/ethermint/pull/703) Fix some fields in transaction are not authenticated by signature.
|
||||
* (evm) [tharsis#751](https://github.com/evmos/ethermint/pull/751) don't revert gas refund logic when transaction reverted
|
||||
|
||||
### Features
|
||||
|
||||
* (rpc, evm) [tharsis#673](https://github.com/evmos/ethermint/pull/673) Use tendermint events to store fee market basefee.
|
||||
* (rpc) [tharsis#624](https://github.com/evmos/ethermint/pull/624) Implement new JSON-RPC endpoints from latest geth version
|
||||
* (evm) [tharsis#662](https://github.com/evmos/ethermint/pull/662) Disable basefee for non london blocks
|
||||
* (cmd) [tharsis#712](https://github.com/evmos/ethermint/pull/712) add tx cli to build evm transaction
|
||||
* (rpc) [tharsis#733](https://github.com/evmos/ethermint/pull/733) add JSON_RPC endpoint `personal_unpair`
|
||||
* (rpc) [tharsis#734](https://github.com/evmos/ethermint/pull/734) add JSON_RPC endpoint `eth_feeHistory`
|
||||
* (rpc) [tharsis#740](https://github.com/evmos/ethermint/pull/740) add JSON_RPC endpoint `personal_initializeWallet`
|
||||
* (rpc) [tharsis#743](https://github.com/evmos/ethermint/pull/743) add JSON_RPC endpoint `debug_traceBlockByHash`
|
||||
* (rpc) [tharsis#748](https://github.com/evmos/ethermint/pull/748) add JSON_RPC endpoint `personal_listWallets`
|
||||
* (rpc) [tharsis#754](https://github.com/evmos/ethermint/pull/754) add JSON_RPC endpoint `debug_intermediateRoots`
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (evm) [tharsis#746](https://github.com/evmos/ethermint/pull/746) Set EVM debugging based on tracer configuration.
|
||||
* (app,cli) [tharsis#725](https://github.com/evmos/ethermint/pull/725) Fix cli-config for `keys` command.
|
||||
* (rpc) [tharsis#727](https://github.com/evmos/ethermint/pull/727) Decode raw transaction using RLP.
|
||||
* (rpc) [tharsis#661](https://github.com/evmos/ethermint/pull/661) Fix OOM bug when creating too many filters using JSON-RPC.
|
||||
* (evm) [tharsis#660](https://github.com/evmos/ethermint/pull/660) Fix `nil` pointer panic in `ApplyNativeMessage`.
|
||||
* (evm, test) [tharsis#649](https://github.com/evmos/ethermint/pull/649) Test DynamicFeeTx.
|
||||
* (evm) [tharsis#702](https://github.com/evmos/ethermint/pull/702) Fix panic in web3 RPC handlers
|
||||
* (rpc) [tharsis#720](https://github.com/evmos/ethermint/pull/720) Fix `debug_traceTransaction` failure
|
||||
* (rpc) [tharsis#741](https://github.com/evmos/ethermint/pull/741) Fix `eth_getBlockByNumberAndHash` return with non eth txs
|
||||
* (rpc) [tharsis#743](https://github.com/evmos/ethermint/pull/743) Fix debug JSON RPC handler crash on non-existing block
|
||||
|
||||
### Improvements
|
||||
|
||||
* (tests) [tharsis#704](https://github.com/evmos/ethermint/pull/704) Introduce E2E testing framework for clients
|
||||
* (deps) [tharsis#737](https://github.com/evmos/ethermint/pull/737) Bump ibc-go to [`v2.0.0`](https://github.com/cosmos/ibc-go/releases/tag/v2.0.0)
|
||||
* (rpc) [tharsis#671](https://github.com/evmos/ethermint/pull/671) Don't pass base fee externally for `EthCall`/`EthEstimateGas` apis.
|
||||
* (evm) [tharsis#674](https://github.com/evmos/ethermint/pull/674) Refactor `ApplyMessage`, remove
|
||||
`ApplyNativeMessage`.
|
||||
* (rpc) [tharsis#714](https://github.com/evmos/ethermint/pull/714) remove `MsgEthereumTx` support in `TxConfig`
|
||||
|
||||
## [v0.7.2] - 2021-10-24
|
||||
|
||||
### Improvements
|
||||
|
||||
* (deps) [tharsis#692](https://github.com/evmos/ethermint/pull/692) Bump Cosmos SDK version to [`v0.44.3`](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.44.3).
|
||||
* (rpc) [tharsis#679](https://github.com/evmos/ethermint/pull/679) Fix file close handle.
|
||||
* (deps) [tharsis#668](https://github.com/evmos/ethermint/pull/668) Bump Tendermint version to [`v0.34.14`](https://github.com/tendermint/tendermint/releases/tag/v0.34.14).
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [tharsis#667](https://github.com/evmos/ethermint/issues/667) Fix `ExpandHome` restrictions bypass
|
||||
|
||||
## [v0.7.1] - 2021-10-08
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (evm) [tharsis#650](https://github.com/evmos/ethermint/pull/650) Fix panic when flattening the cache context in case transaction is reverted.
|
||||
* (rpc, test) [tharsis#608](https://github.com/evmos/ethermint/pull/608) Fix rpc test.
|
||||
|
||||
## [v0.7.0] - 2021-10-07
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (rpc) [tharsis#400](https://github.com/evmos/ethermint/issues/400) Restructure JSON-RPC directory and rename server config
|
||||
|
||||
### Improvements
|
||||
|
||||
* (deps) [tharsis#621](https://github.com/evmos/ethermint/pull/621) Bump IBC-go to [`v1.2.1`](https://github.com/cosmos/ibc-go/releases/tag/v1.2.1)
|
||||
* (evm) [tharsis#613](https://github.com/evmos/ethermint/pull/613) Refactor `traceTx`
|
||||
* (deps) [tharsis#610](https://github.com/evmos/ethermint/pull/610) Bump Cosmos SDK to [v0.44.1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.44.1).
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [tharsis#642](https://github.com/evmos/ethermint/issues/642) Fix `eth_getLogs` when string is specified in filter's from or to fields
|
||||
* (evm) [tharsis#616](https://github.com/evmos/ethermint/issues/616) Fix halt on deeply nested stack of cache context. Stack is now flattened before iterating over the tx logs.
|
||||
* (rpc, evm) [tharsis#614](https://github.com/evmos/ethermint/issues/614) Use JSON for (un)marshaling tx `Log`s from events.
|
||||
* (rpc) [tharsis#611](https://github.com/evmos/ethermint/pull/611) Fix panic on JSON-RPC when querying for an invalid block height.
|
||||
* (cmd) [tharsis#483](https://github.com/evmos/ethermint/pull/483) Use config values on genesis accounts.
|
||||
|
||||
## [v0.6.0] - 2021-09-29
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (app) [tharsis#476](https://github.com/evmos/ethermint/pull/476) Update Bech32 HRP to `ethm`.
|
||||
* (evm) [tharsis#556](https://github.com/evmos/ethermint/pull/556) Remove tx logs and block bloom from chain state
|
||||
* (evm) [tharsis#590](https://github.com/evmos/ethermint/pull/590) Contract storage key is not hashed anymore
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (evm) [tharsis#469](https://github.com/evmos/ethermint/pull/469) Deprecate `YoloV3Block` and `EWASMBlock` from `ChainConfig`
|
||||
|
||||
### Features
|
||||
|
||||
* (evm) [tharsis#469](https://github.com/evmos/ethermint/pull/469) Support [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)
|
||||
* (evm) [tharsis#417](https://github.com/evmos/ethermint/pull/417) Add `EvmHooks` for tx post-processing
|
||||
* (rpc) [tharsis#506](https://github.com/evmos/ethermint/pull/506) Support for `debug_traceTransaction` RPC endpoint
|
||||
* (rpc) [tharsis#555](https://github.com/evmos/ethermint/pull/555) Support for `debug_traceBlockByNumber` RPC endpoint
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc, server) [tharsis#600](https://github.com/evmos/ethermint/pull/600) Add TLS configuration for websocket API
|
||||
* (rpc) [tharsis#598](https://github.com/evmos/ethermint/pull/598) Check truncation when creating a `BlockNumber` from `big.Int`
|
||||
* (evm) [tharsis#597](https://github.com/evmos/ethermint/pull/597) Check for `uint64` -> `int64` block height overflow on `GetHashFn`
|
||||
* (evm) [tharsis#579](https://github.com/evmos/ethermint/pull/579) Update `DeriveChainID` function to handle `v` signature values `< 35`.
|
||||
* (encoding) [tharsis#478](https://github.com/evmos/ethermint/pull/478) Register `Evidence` to amino codec.
|
||||
* (rpc) [tharsis#478](https://github.com/evmos/ethermint/pull/481) Getting the node configuration when calling the `miner` rpc methods.
|
||||
* (cli) [tharsis#561](https://github.com/evmos/ethermint/pull/561) `Export` and `Start` commands now use the same home directory.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (evm) [tharsis#461](https://github.com/evmos/ethermint/pull/461) Increase performance of `StateDB` transaction log storage (r/w).
|
||||
* (evm) [tharsis#566](https://github.com/evmos/ethermint/pull/566) Introduce `stateErr` store in `StateDB` to avoid meaningless operations if any error happened before
|
||||
* (rpc, evm) [tharsis#587](https://github.com/evmos/ethermint/pull/587) Apply bloom filter when query ethlogs with range of blocks
|
||||
* (evm) [tharsis#586](https://github.com/evmos/ethermint/pull/586) Benchmark evm keeper
|
||||
* (evm) [tharsis#461](https://github.com/tharsis/ethermint/pull/461) Increase performance of `StateDB` transaction log storage (r/w).
|
||||
|
||||
## [v0.5.0] - 2021-08-20
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (app, rpc) [tharsis#447](https://github.com/evmos/ethermint/pull/447) Chain ID format has been changed from `<identifier>-<epoch>` to `<identifier>_<EIP155_number>-<epoch>`
|
||||
* (app, rpc) [tharsis#447](https://github.com/tharsis/ethermint/pull/447) Chain ID format has been changed from `<identifier>-<epoch>` to `<identifier>_<EIP155_number>-<epoch>`
|
||||
in order to clearly distinguish permanent vs impermanent components.
|
||||
* (app, evm) [tharsis#434](https://github.com/evmos/ethermint/pull/434) EVM `Keeper` struct and `NewEVM` function now have a new `trace` field to define
|
||||
* (app, evm) [tharsis#434](https://github.com/tharsis/ethermint/pull/434) EVM `Keeper` struct and `NewEVM` function now have a new `trace` field to define
|
||||
the Tracer type used to collect execution traces from the EVM transaction execution.
|
||||
* (evm) [tharsis#175](https://github.com/evmos/ethermint/issues/175) The msg `TxData` field is now represented as a `*proto.Any`.
|
||||
* (evm) [tharsis#84](https://github.com/evmos/ethermint/pull/84) Remove `journal`, `CommitStateDB` and `stateObjects`.
|
||||
* (rpc, evm) [tharsis#81](https://github.com/evmos/ethermint/pull/81) Remove tx `Receipt` from store and replace it with fields obtained from the Tendermint RPC client.
|
||||
* (evm) [tharsis#72](https://github.com/evmos/ethermint/issues/72) Update `AccessList` to use `TransientStore` instead of map.
|
||||
* (evm) [tharsis#68](https://github.com/evmos/ethermint/issues/68) Replace block hash storage map to use staking `HistoricalInfo`.
|
||||
* (evm) [tharsis#276](https://github.com/evmos/ethermint/pull/276) Vm errors don't result in cosmos tx failure, just
|
||||
* (evm) [tharsis#175](https://github.com/tharsis/ethermint/issues/175) The msg `TxData` field is now represented as a `*proto.Any`.
|
||||
* (evm) [tharsis#84](https://github.com/tharsis/ethermint/pull/84) Remove `journal`, `CommitStateDB` and `stateObjects`.
|
||||
* (rpc, evm) [tharsis#81](https://github.com/tharsis/ethermint/pull/81) Remove tx `Receipt` from store and replace it with fields obtained from the Tendermint RPC client.
|
||||
* (evm) [tharsis#72](https://github.com/tharsis/ethermint/issues/72) Update `AccessList` to use `TransientStore` instead of map.
|
||||
* (evm) [tharsis#68](https://github.com/tharsis/ethermint/issues/68) Replace block hash storage map to use staking `HistoricalInfo`.
|
||||
* (evm) [tharsis#276](https://github.com/tharsis/ethermint/pull/276) Vm errors don't result in cosmos tx failure, just
|
||||
different tx state and events.
|
||||
* (evm) [tharsis#342](https://github.com/evmos/ethermint/issues/342) Don't clear balance when resetting the account.
|
||||
* (evm) [tharsis#334](https://github.com/evmos/ethermint/pull/334) Log index changed to the index in block rather than
|
||||
* (evm) [tharsis#342](https://github.com/tharsis/ethermint/issues/342) Don't clear balance when resetting the account.
|
||||
* (evm) [tharsis#334](https://github.com/tharsis/ethermint/pull/334) Log index changed to the index in block rather than
|
||||
tx.
|
||||
* (evm) [tharsis#399](https://github.com/evmos/ethermint/pull/399) Exception in sub-message call reverts the call if it's not propagated.
|
||||
* (evm) [tharsis#399](https://github.com/tharsis/ethermint/pull/399) Exception in sub-message call reverts the call if it's not propagated.
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (proto) [tharsis#448](https://github.com/evmos/ethermint/pull/448) Bump version for all Ethermint messages to `v1`
|
||||
* (server) [tharsis#434](https://github.com/evmos/ethermint/pull/434) `evm-rpc` flags and app config have been renamed to `json-rpc`.
|
||||
* (proto, evm) [tharsis#207](https://github.com/evmos/ethermint/issues/207) Replace `big.Int` in favor of `sdk.Int` for `TxData` fields
|
||||
* (proto, evm) [tharsis#81](https://github.com/evmos/ethermint/pull/81) gRPC Query and Tx service changes:
|
||||
* (proto) [tharsis#448](https://github.com/tharsis/ethermint/pull/448) Bump version for all Ethermint messages to `v1`
|
||||
* (server) [tharsis#434](https://github.com/tharsis/ethermint/pull/434) `evm-rpc` flags and app config have been renamed to `json-rpc`.
|
||||
* (proto, evm) [tharsis#207](https://github.com/tharsis/ethermint/issues/207) Replace `big.Int` in favor of `sdk.Int` for `TxData` fields
|
||||
* (proto, evm) [tharsis#81](https://github.com/tharsis/ethermint/pull/81) gRPC Query and Tx service changes:
|
||||
* The `TxReceipt`, `TxReceiptsByBlockHeight` endpoints have been removed from the Query service.
|
||||
* The `ContractAddress`, `Bloom` have been removed from the `MsgEthereumTxResponse` and the
|
||||
response now contains the ethereum-formatted `Hash` in hex format.
|
||||
* (eth) [tharsis#845](https://github.com/cosmos/ethermint/pull/845) The `eth` namespace must be included in the list of API's as default to run the rpc server without error.
|
||||
* (evm) [tharsis#202](https://github.com/evmos/ethermint/pull/202) Web3 api `SendTransaction`/`SendRawTransaction` returns ethereum compatible transaction hash, and query api `GetTransaction*` also accept that.
|
||||
* (rpc) [tharsis#258](https://github.com/evmos/ethermint/pull/258) Return empty `BloomFilter` instead of throwing an error when it cannot be found (`nil` or empty).
|
||||
* (rpc) [tharsis#277](https://github.com/evmos/ethermint/pull/321) Fix `BloomFilter` response.
|
||||
* (eth) [\#845](https://github.com/cosmos/ethermint/pull/845) The `eth` namespace must be included in the list of API's as default to run the rpc server without error.
|
||||
* (evm) [#202](https://github.com/tharsis/ethermint/pull/202) Web3 api `SendTransaction`/`SendRawTransaction` returns ethereum compatible transaction hash, and query api `GetTransaction*` also accept that.
|
||||
* (rpc) [tharsis#258](https://github.com/tharsis/ethermint/pull/258) Return empty `BloomFilter` instead of throwing an error when it cannot be found (`nil` or empty).
|
||||
* (rpc) [tharsis#277](https://github.com/tharsis/ethermint/pull/321) Fix `BloomFilter` response.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (client) [tharsis#450](https://github.com/evmos/ethermint/issues/450) Add EIP55 hex address support on `debug addr` command.
|
||||
* (server) [tharsis#343](https://github.com/evmos/ethermint/pull/343) Define a wrap tendermint logger `Handler` go-ethereum's `root` logger.
|
||||
* (rpc) [tharsis#457](https://github.com/evmos/ethermint/pull/457) Configure RPC gas cap through app config.
|
||||
* (evm) [tharsis#434](https://github.com/evmos/ethermint/pull/434) Support different `Tracer` types for the EVM.
|
||||
* (deps) [tharsis#427](https://github.com/evmos/ethermint/pull/427) Bump ibc-go to [`v1.0.0`](https://github.com/cosmos/ibc-go/releases/tag/v1.0.0)
|
||||
* (gRPC) [tharsis#239](https://github.com/evmos/ethermint/pull/239) Query `ChainConfig` via gRPC.
|
||||
* (rpc) [tharsis#181](https://github.com/evmos/ethermint/pull/181) Use evm denomination for params on tx fee.
|
||||
* (deps) [tharsis#423](https://github.com/evmos/ethermint/pull/423) Bump Cosmos SDK and Tendermint versions to [v0.43.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.43.0) and [v0.34.11](https://github.com/tendermint/tendermint/releases/tag/v0.34.11), respectively.
|
||||
* (evm) [tharsis#66](https://github.com/evmos/ethermint/issues/66) Support legacy transaction types for signing.
|
||||
* (evm) [tharsis#24](https://github.com/evmos/ethermint/pull/24) Implement metrics for `MsgEthereumTx`, state transitions, `BeginBlock` and `EndBlock`.
|
||||
* (rpc) [tharsis#124](https://github.com/evmos/ethermint/issues/124) Implement `txpool_content`, `txpool_inspect` and `txpool_status` RPC methods
|
||||
* (rpc) [tharsis#112](https://github.com/evmos/ethermint/pull/153) Fix `eth_coinbase` to return the ethereum address of the validator
|
||||
* (rpc) [tharsis#176](https://github.com/evmos/ethermint/issues/176) Support fetching pending nonce
|
||||
* (rpc) [tharsis#272](https://github.com/evmos/ethermint/pull/272) do binary search to estimate gas accurately
|
||||
* (rpc) [tharsis#313](https://github.com/evmos/ethermint/pull/313) Implement internal debug namespace (Not including logger functions nor traces).
|
||||
* (rpc) [tharsis#349](https://github.com/evmos/ethermint/pull/349) Implement configurable JSON-RPC APIs to manage enabled namespaces.
|
||||
* (rpc) [tharsis#377](https://github.com/evmos/ethermint/pull/377) Implement `miner_` namespace. `miner_setEtherbase` and `miner_setGasPrice` are working as intended. All the other calls are not applicable and return `unsupported`.
|
||||
* (eth) [tharsis#460](https://github.com/evmos/ethermint/issues/460) Add support for EIP-1898.
|
||||
* (client) [tharsis#450](https://github.com/tharsis/ethermint/issues/450) Add EIP55 hex address support on `debug addr` command.
|
||||
* (server) [tharsis#343](https://github.com/tharsis/ethermint/pull/343) Define a wrap tendermint logger `Handler` go-ethereum's `root` logger.
|
||||
* (rpc) [tharsis#457](https://github.com/tharsis/ethermint/pull/457) Configure RPC gas cap through app config.
|
||||
* (evm) [tharsis#434](https://github.com/tharsis/ethermint/pull/434) Support different `Tracer` types for the EVM.
|
||||
* (deps) [tharsis#427](https://github.com/tharsis/ethermint/pull/427) Bump ibc-go to [`v1.0.0`](https://github.com/cosmos/ibc-go/releases/tag/v1.0.0)
|
||||
* (gRPC) [tharsis#239](https://github.com/tharsis/ethermint/pull/239) Query `ChainConfig` via gRPC.
|
||||
* (rpc) [tharsis#181](https://github.com/tharsis/ethermint/pull/181) Use evm denomination for params on tx fee.
|
||||
* (deps) [tharsis#423](https://github.com/tharsis/ethermint/pull/423) Bump Cosmos SDK and Tendermint versions to [v0.43.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.43.0) and [v0.34.11](https://github.com/tendermint/tendermint/releases/tag/v0.34.11), respectively.
|
||||
* (evm) [tharsis#66](https://github.com/tharsis/ethermint/issues/66) Support legacy transaction types for signing.
|
||||
* (evm) [tharsis#24](https://github.com/tharsis/ethermint/pull/24) Implement metrics for `MsgEthereumTx`, state transitions, `BeginBlock` and `EndBlock`.
|
||||
* (rpc) [#124](https://github.com/tharsis/ethermint/issues/124) Implement `txpool_content`, `txpool_inspect` and `txpool_status` RPC methods
|
||||
* (rpc) [tharsis#112](https://github.com/tharsis/ethermint/pull/153) Fix `eth_coinbase` to return the ethereum address of the validator
|
||||
* (rpc) [tharsis#176](https://github.com/tharsis/ethermint/issues/176) Support fetching pending nonce
|
||||
* (rpc) [tharsis#272](https://github.com/tharsis/ethermint/pull/272) do binary search to estimate gas accurately
|
||||
* (rpc) [#313](https://github.com/tharsis/ethermint/pull/313) Implement internal debug namespace (Not including logger functions nor traces).
|
||||
* (rpc) [#349](https://github.com/tharsis/ethermint/pull/349) Implement configurable JSON-RPC APIs to manage enabled namespaces.
|
||||
* (rpc) [#377](https://github.com/tharsis/ethermint/pull/377) Implement `miner_` namespace. `miner_setEtherbase` and `miner_setGasPrice` are working as intended. All the other calls are not applicable and return `unsupported`.
|
||||
* (eth) [tharsis#460](https://github.com/tharsis/ethermint/issues/460) Add support for EIP-1898.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (keys) [tharsis#346](https://github.com/evmos/ethermint/pull/346) Fix `keys add` command with `--ledger` flag for the `secp256k1` signing algorithm.
|
||||
* (evm) [tharsis#291](https://github.com/evmos/ethermint/pull/291) Use block proposer address (validator operator) for `COINBASE` opcode.
|
||||
* (rpc) [tharsis#81](https://github.com/evmos/ethermint/pull/81) Fix transaction hashing and decoding on `eth_sendTransaction`.
|
||||
* (rpc) [tharsis#45](https://github.com/evmos/ethermint/pull/45) Use `EmptyUncleHash` and `EmptyRootHash` for empty ethereum `Header` fields.
|
||||
* (keys) [tharsis#346](https://github.com/tharsis/ethermint/pull/346) Fix `keys add` command with `--ledger` flag for the `secp256k1` signing algorithm.
|
||||
* (evm) [tharsis#291](https://github.com/tharsis/ethermint/pull/291) Use block proposer address (validator operator) for `COINBASE` opcode.
|
||||
* (rpc) [tharsis#81](https://github.com/tharsis/ethermint/pull/81) Fix transaction hashing and decoding on `eth_sendTransaction`.
|
||||
* (rpc) [tharsis#45](https://github.com/tharsis/ethermint/pull/45) Use `EmptyUncleHash` and `EmptyRootHash` for empty ethereum `Header` fields.
|
||||
|
||||
## [v0.4.1] - 2021-03-01
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (faucet) [tharsis#678](https://github.com/cosmos/ethermint/pull/678) Faucet module has been removed in favor of client libraries such as [`@cosmjs/faucet`](https://github.com/cosmos/cosmjs/tree/master/packages/faucet).
|
||||
* (evm) [tharsis#670](https://github.com/cosmos/ethermint/pull/670) Migrate types to the ones defined by the protobuf messages, which are required for the stargate release.
|
||||
* (faucet) [\#678](https://github.com/cosmos/ethermint/pull/678) Faucet module has been removed in favor of client libraries such as [`@cosmjs/faucet`](https://github.com/cosmos/cosmjs/tree/master/packages/faucet).
|
||||
* (evm) [\#670](https://github.com/cosmos/ethermint/pull/670) Migrate types to the ones defined by the protobuf messages, which are required for the stargate release.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (evm) [tharsis#799](https://github.com/cosmos/ethermint/issues/799) Fix wrong precision in calculation of gas fee.
|
||||
* (evm) [tharsis#760](https://github.com/cosmos/ethermint/issues/760) Fix Failed to call function EstimateGas.
|
||||
* (evm) [tharsis#767](https://github.com/cosmos/ethermint/issues/767) Fix error of timeout when using Truffle to deploy contract.
|
||||
* (evm) [tharsis#751](https://github.com/cosmos/ethermint/issues/751) Fix misused method to calculate block hash in evm related function.
|
||||
* (evm) [tharsis#721](https://github.com/cosmos/ethermint/issues/721) Fix mismatch block hash in rpc response when use eht.getBlock.
|
||||
* (evm) [tharsis#730](https://github.com/cosmos/ethermint/issues/730) Fix 'EIP2028' not open when Istanbul version has been enabled.
|
||||
* (evm) [tharsis#749](https://github.com/cosmos/ethermint/issues/749) Fix panic in `AnteHandler` when gas price larger than 100000
|
||||
* (evm) [tharsis#747](https://github.com/cosmos/ethermint/issues/747) Fix format errors in String() of QueryETHLogs
|
||||
* (evm) [tharsis#742](https://github.com/cosmos/ethermint/issues/742) Add parameter check for evm query func.
|
||||
* (evm) [tharsis#687](https://github.com/cosmos/ethermint/issues/687) Fix nonce check to explicitly check for the correct nonce, rather than a simple 'greater than' comparison.
|
||||
* (api) [tharsis#687](https://github.com/cosmos/ethermint/issues/687) Returns error for a transaction with an incorrect nonce.
|
||||
* (evm) [tharsis#674](https://github.com/cosmos/ethermint/issues/674) Reset all cache after account data has been committed in `EndBlock` to make sure every node state consistent.
|
||||
* (evm) [tharsis#672](https://github.com/cosmos/ethermint/issues/672) Fix panic of `wrong Block.Header.AppHash` when restart a node with snapshot.
|
||||
* (evm) [tharsis#775](https://github.com/cosmos/ethermint/issues/775) MisUse of headHash as blockHash when create EVM context.
|
||||
* (evm) [\#799](https://github.com/cosmos/ethermint/issues/799) Fix wrong precision in calculation of gas fee.
|
||||
* (evm) [\#760](https://github.com/cosmos/ethermint/issues/760) Fix Failed to call function EstimateGas.
|
||||
* (evm) [\#767](https://github.com/cosmos/ethermint/issues/767) Fix error of timeout when using Truffle to deploy contract.
|
||||
* (evm) [\#751](https://github.com/cosmos/ethermint/issues/751) Fix misused method to calculate block hash in evm related function.
|
||||
* (evm) [\#721](https://github.com/cosmos/ethermint/issues/721) Fix mismatch block hash in rpc response when use eht.getBlock.
|
||||
* (evm) [\#730](https://github.com/cosmos/ethermint/issues/730) Fix 'EIP2028' not open when Istanbul version has been enabled.
|
||||
* (evm) [\#749](https://github.com/cosmos/ethermint/issues/749) Fix panic in `AnteHandler` when gas price larger than 100000
|
||||
* (evm) [\#747](https://github.com/cosmos/ethermint/issues/747) Fix format errors in String() of QueryETHLogs
|
||||
* (evm) [\#742](https://github.com/cosmos/ethermint/issues/742) Add parameter check for evm query func.
|
||||
* (evm) [\#687](https://github.com/cosmos/ethermint/issues/687) Fix nonce check to explicitly check for the correct nonce, rather than a simple 'greater than' comparison.
|
||||
* (api) [\#687](https://github.com/cosmos/ethermint/issues/687) Returns error for a transaction with an incorrect nonce.
|
||||
* (evm) [\#674](https://github.com/cosmos/ethermint/issues/674) Reset all cache after account data has been committed in `EndBlock` to make sure every node state consistent.
|
||||
* (evm) [\#672](https://github.com/cosmos/ethermint/issues/672) Fix panic of `wrong Block.Header.AppHash` when restart a node with snapshot.
|
||||
* (evm) [\#775](https://github.com/cosmos/ethermint/issues/775) MisUse of headHash as blockHash when create EVM context.
|
||||
|
||||
### Features
|
||||
|
||||
* (api) [tharsis#821](https://github.com/cosmos/ethermint/pull/821) Individually enable the api modules. Will be implemented in the latest version of ethermint with the upcoming stargate upgrade.
|
||||
* (api) [\#821](https://github.com/cosmos/ethermint/pull/821) Individually enable the api modules. Will be implemented in the latest version of ethermint with the upcoming stargate upgrade.
|
||||
|
||||
### Features
|
||||
|
||||
* (api) [tharsis#825](https://github.com/cosmos/ethermint/pull/825) Individually enable the api modules. Will be implemented in the latest version of ethermint with the upcoming stargate upgrade.
|
||||
* (api) [\#825](https://github.com/cosmos/ethermint/pull/825) Individually enable the api modules. Will be implemented in the latest version of ethermint with the upcoming stargate upgrade.
|
||||
|
||||
## [v0.4.0] - 2020-12-15
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (evm) [tharsis#661](https://github.com/cosmos/ethermint/pull/661) `Balance` field has been removed from the evm module's `GenesisState`.
|
||||
* (evm) [\#661](https://github.com/cosmos/ethermint/pull/661) `Balance` field has been removed from the evm module's `GenesisState`.
|
||||
|
||||
### Features
|
||||
|
||||
* (rpc) [tharsis#571](https://github.com/cosmos/ethermint/pull/571) Add pending queries to JSON-RPC calls. This allows for the querying of pending transactions and other relevant information that pertains to the pending state:
|
||||
* (rpc) [\#571](https://github.com/cosmos/ethermint/pull/571) Add pending queries to JSON-RPC calls. This allows for the querying of pending transactions and other relevant information that pertains to the pending state:
|
||||
* `eth_getBalance`
|
||||
* `eth_getTransactionCount`
|
||||
* `eth_getBlockTransactionCountByNumber`
|
||||
@ -685,149 +174,149 @@ the Tracer type used to collect execution traces from the EVM transaction execut
|
||||
|
||||
### Improvements
|
||||
|
||||
* (evm) [tharsis#661](https://github.com/cosmos/ethermint/pull/661) Add invariant check for account balance and account nonce.
|
||||
* (deps) [tharsis#654](https://github.com/cosmos/ethermint/pull/654) Bump go-ethereum version to [v1.9.25](https://github.com/ethereum/go-ethereum/releases/tag/v1.9.25)
|
||||
* (evm) [tharsis#627](https://github.com/cosmos/ethermint/issues/627) Add extra EIPs parameter to apply custom EVM jump tables.
|
||||
* (evm) [\#661](https://github.com/cosmos/ethermint/pull/661) Add invariant check for account balance and account nonce.
|
||||
* (deps) [\#654](https://github.com/cosmos/ethermint/pull/654) Bump go-ethereum version to [v1.9.25](https://github.com/ethereum/go-ethereum/releases/tag/v1.9.25)
|
||||
* (evm) [\#627](https://github.com/cosmos/ethermint/issues/627) Add extra EIPs parameter to apply custom EVM jump tables.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (evm) [tharsis#661](https://github.com/cosmos/ethermint/pull/661) Set nonce to the EVM account on genesis initialization.
|
||||
* (rpc) [tharsis#648](https://github.com/cosmos/ethermint/issues/648) Fix block cumulative gas used value.
|
||||
* (evm) [tharsis#621](https://github.com/cosmos/ethermint/issues/621) EVM `GenesisAccount` fields now share the same format as the auth module `Account`.
|
||||
* (evm) [tharsis#618](https://github.com/cosmos/ethermint/issues/618) Add missing EVM `Context` `GetHash` field that retrieves a the header hash from a given block height.
|
||||
* (app) [tharsis#617](https://github.com/cosmos/ethermint/issues/617) Fix genesis export functionality.
|
||||
* (rpc) [tharsis#574](https://github.com/cosmos/ethermint/issues/574) Fix outdated version from `eth_protocolVersion`.
|
||||
* (evm) [\#661](https://github.com/cosmos/ethermint/pull/661) Set nonce to the EVM account on genesis initialization.
|
||||
* (rpc) [\#648](https://github.com/cosmos/ethermint/issues/648) Fix block cumulative gas used value.
|
||||
* (evm) [\#621](https://github.com/cosmos/ethermint/issues/621) EVM `GenesisAccount` fields now share the same format as the auth module `Account`.
|
||||
* (evm) [\#618](https://github.com/cosmos/ethermint/issues/618) Add missing EVM `Context` `GetHash` field that retrieves a the header hash from a given block height.
|
||||
* (app) [\#617](https://github.com/cosmos/ethermint/issues/617) Fix genesis export functionality.
|
||||
* (rpc) [\#574](https://github.com/cosmos/ethermint/issues/574) Fix outdated version from `eth_protocolVersion`.
|
||||
|
||||
## [v0.3.1] - 2020-11-24
|
||||
|
||||
### Improvements
|
||||
|
||||
* (deps) [tharsis#615](https://github.com/cosmos/ethermint/pull/615) Bump Cosmos SDK version to [v0.39.2](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.39.2)
|
||||
* (deps) [tharsis#610](https://github.com/cosmos/ethermint/pull/610) Update Go dependency to 1.15+.
|
||||
* (evm) [tharsis#603](https://github.com/cosmos/ethermint/pull/603) Add state transition params that enable or disable the EVM `Call` and `Create` operations.
|
||||
* (deps) [tharsis#602](https://github.com/cosmos/ethermint/pull/602) Bump tendermint version to [v0.33.9](https://github.com/tendermint/tendermint/releases/tag/v0.33.9)
|
||||
* (deps) [\#615](https://github.com/cosmos/ethermint/pull/615) Bump Cosmos SDK version to [v0.39.2](https://github.com/cosmos/cosmos-sdk/tag/v0.39.2)
|
||||
* (deps) [\#610](https://github.com/cosmos/ethermint/pull/610) Update Go dependency to 1.15+.
|
||||
* (evm) [#603](https://github.com/cosmos/ethermint/pull/603) Add state transition params that enable or disable the EVM `Call` and `Create` operations.
|
||||
* (deps) [\#602](https://github.com/cosmos/ethermint/pull/602) Bump tendermint version to [v0.33.9](https://github.com/tendermint/tendermint/releases/tag/v0.33.9)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (rpc) [tharsis#613](https://github.com/cosmos/ethermint/issues/613) Fix potential deadlock caused if the keyring `List` returned an error.
|
||||
* (rpc) [\#613](https://github.com/cosmos/ethermint/issues/613) Fix potential deadlock caused if the keyring `List` returned an error.
|
||||
|
||||
## [v0.3.0] - 2020-11-16
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (crypto) [tharsis#559](https://github.com/cosmos/ethermint/pull/559) Refactored crypto package in preparation for the SDK's Stargate release:
|
||||
* (crypto) [\#559](https://github.com/cosmos/ethermint/pull/559) Refactored crypto package in preparation for the SDK's Stargate release:
|
||||
* `crypto.PubKeySecp256k1` and `crypto.PrivKeySecp256k1` are now `ethsecp256k1.PubKey` and `ethsecp256k1.PrivKey`, respectively
|
||||
* Moved SDK `SigningAlgo` implementation for Ethermint's Secp256k1 key to `crypto/hd` package.
|
||||
* (rpc) [tharsis#588](https://github.com/cosmos/ethermint/pull/588) The `rpc` package has been refactored to account for the separation of each
|
||||
* (rpc) [\#588](https://github.com/cosmos/ethermint/pull/588) The `rpc` package has been refactored to account for the separation of each
|
||||
corresponding Ethereum API namespace:
|
||||
* `rpc/namespaces/eth`: `eth` namespace. Exposes the `PublicEthereumAPI` and the `PublicFilterAPI`.
|
||||
* `rpc/namespaces/personal`: `personal` namespace. Exposes the `PrivateAccountAPI`.
|
||||
* `rpc/namespaces/net`: `net` namespace. Exposes the `PublicNetAPI`.
|
||||
* `rpc/namespaces/web3`: `web3` namespace. Exposes the `PublicWeb3API`.
|
||||
* (evm) [tharsis#588](https://github.com/cosmos/ethermint/pull/588) The EVM transaction CLI has been removed in favor of the JSON-RPC.
|
||||
* (evm) [\#588](https://github.com/cosmos/ethermint/pull/588) The EVM transaction CLI has been removed in favor of the JSON-RPC.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (deps) [tharsis#594](https://github.com/cosmos/ethermint/pull/594) Bump go-ethereum version to [v1.9.24](https://github.com/ethereum/go-ethereum/releases/tag/v1.9.24)
|
||||
* (deps) [\#594](https://github.com/cosmos/ethermint/pull/594) Bump go-ethereum version to [v1.9.24](https://github.com/ethereum/go-ethereum/releases/tag/v1.9.24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (ante) [tharsis#597](https://github.com/cosmos/ethermint/pull/597) Fix incorrect fee check on `AnteHandler`.
|
||||
* (evm) [tharsis#583](https://github.com/cosmos/ethermint/pull/583) Fixes incorrect resetting of tx count and block bloom during `BeginBlock`, as well as gas consumption.
|
||||
* (crypto) [tharsis#577](https://github.com/cosmos/ethermint/pull/577) Fix `BIP44HDPath` that did not prepend `m/` to the path. This now uses the `DefaultBaseDerivationPath` variable from go-ethereum to ensure addresses are consistent.
|
||||
* (ante) [\#597](https://github.com/cosmos/ethermint/pull/597) Fix incorrect fee check on `AnteHandler`.
|
||||
* (evm) [\#583](https://github.com/cosmos/ethermint/pull/583) Fixes incorrect resetting of tx count and block bloom during `BeginBlock`, as well as gas consumption.
|
||||
* (crypto) [\#577](https://github.com/cosmos/ethermint/pull/577) Fix `BIP44HDPath` that did not prepend `m/` to the path. This now uses the `DefaultBaseDerivationPath` variable from go-ethereum to ensure addresses are consistent.
|
||||
|
||||
## [v0.2.1] - 2020-09-30
|
||||
|
||||
### Features
|
||||
|
||||
* (rpc) [tharsis#552](https://github.com/cosmos/ethermint/pull/552) Implement Eth Personal namespace `personal_importRawKey`.
|
||||
* (rpc) [\#552](https://github.com/cosmos/ethermint/pull/552) Implement Eth Personal namespace `personal_importRawKey`.
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* (keys) [tharsis#554](https://github.com/cosmos/ethermint/pull/554) Fix private key derivation.
|
||||
* (app/ante) [tharsis#550](https://github.com/cosmos/ethermint/pull/550) Update ante handler nonce verification to accept any nonce greater than or equal to the expected nonce to allow to successive transactions.
|
||||
* (keys) [\#554](https://github.com/cosmos/ethermint/pull/554) Fix private key derivation.
|
||||
* (app/ante) [\#550](https://github.com/cosmos/ethermint/pull/550) Update ante handler nonce verification to accept any nonce greater than or equal to the expected nonce to allow to successive transactions.
|
||||
|
||||
## [v0.2.0] - 2020-09-24
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (app) [tharsis#540](https://github.com/cosmos/ethermint/issues/540) Chain identifier's format has been changed to match the Cosmos `chainID` [standard](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-5.md), which is required for IBC. The epoch number of the ID is used as the EVM `chainID`.
|
||||
* (app) [\#540](https://github.com/cosmos/ethermint/issues/540) Chain identifier's format has been changed to match the Cosmos `chainID` [standard](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-5.md), which is required for IBC. The epoch number of the ID is used as the EVM `chainID`.
|
||||
|
||||
### API Breaking
|
||||
|
||||
* (types) [tharsis#503](https://github.com/cosmos/ethermint/pull/503) The `types.DenomDefault` constant for `"aphoton"` has been renamed to `types.AttoPhoton`.
|
||||
* (types) [\#503](https://github.com/cosmos/ethermint/pull/503) The `types.DenomDefault` constant for `"aphoton"` has been renamed to `types.AttoPhoton`.
|
||||
|
||||
### Improvements
|
||||
|
||||
* (types) [tharsis#504](https://github.com/cosmos/ethermint/pull/504) Unmarshal a JSON `EthAccount` using an Ethereum hex address in addition to Bech32.
|
||||
* (types) [tharsis#503](https://github.com/cosmos/ethermint/pull/503) Add `--coin-denom` flag to testnet command that sets the given coin denomination to SDK and Ethermint parameters.
|
||||
* (types) [tharsis#502](https://github.com/cosmos/ethermint/pull/502) `EthAccount` now also exposes the Ethereum hex address in `string` format to clients.
|
||||
* (types) [tharsis#494](https://github.com/cosmos/ethermint/pull/494) Update `EthAccount` public key JSON type to `string`.
|
||||
* (app) [tharsis#471](https://github.com/cosmos/ethermint/pull/471) Add `x/upgrade` module for managing software updates.
|
||||
* (evm) [tharsis#458](https://github.com/cosmos/ethermint/pull/458) Define parameter for token denomination used for the EVM module.
|
||||
* (evm) [tharsis#443](https://github.com/cosmos/ethermint/issues/443) Support custom Ethereum `ChainConfig` params.
|
||||
* (types) [tharsis#434](https://github.com/cosmos/ethermint/issues/434) Update default denomination to Atto Photon (`aphoton`).
|
||||
* (types) [tharsis#515](https://github.com/cosmos/ethermint/pull/515) Update minimum gas price to be 1.
|
||||
* (types) [\#504](https://github.com/cosmos/ethermint/pull/504) Unmarshal a JSON `EthAccount` using an Ethereum hex address in addition to Bech32.
|
||||
* (types) [\#503](https://github.com/cosmos/ethermint/pull/503) Add `--coin-denom` flag to testnet command that sets the given coin denomination to SDK and Ethermint parameters.
|
||||
* (types) [\#502](https://github.com/cosmos/ethermint/pull/502) `EthAccount` now also exposes the Ethereum hex address in `string` format to clients.
|
||||
* (types) [\#494](https://github.com/cosmos/ethermint/pull/494) Update `EthAccount` public key JSON type to `string`.
|
||||
* (app) [\#471](https://github.com/cosmos/ethermint/pull/471) Add `x/upgrade` module for managing software updates.
|
||||
* (`x/evm`) [\#458](https://github.com/cosmos/ethermint/pull/458) Define parameter for token denomination used for the EVM module.
|
||||
* (`x/evm`) [\#443](https://github.com/cosmos/ethermint/issues/443) Support custom Ethereum `ChainConfig` params.
|
||||
* (types) [\#434](https://github.com/cosmos/ethermint/issues/434) Update default denomination to Atto Photon (`aphoton`).
|
||||
* (types) [\#515](https://github.com/cosmos/ethermint/pull/515) Update minimum gas price to be 1.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (ante) [tharsis#525](https://github.com/cosmos/ethermint/pull/525) Add message validation decorator to `AnteHandler` for `MsgEthereumTx`.
|
||||
* (types) [tharsis#507](https://github.com/cosmos/ethermint/pull/507) Fix hardcoded `aphoton` on `EthAccount` balance getter and setter.
|
||||
* (types) [tharsis#501](https://github.com/cosmos/ethermint/pull/501) Fix bech32 encoding error by using the compressed ethereum secp256k1 public key.
|
||||
* (evm) [tharsis#496](https://github.com/cosmos/ethermint/pull/496) Fix bugs on `journal.revert` and `CommitStateDB.Copy`.
|
||||
* (types) [tharsis#480](https://github.com/cosmos/ethermint/pull/480) Update [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) coin type to `60` to satisfy [EIP84](https://github.com/ethereum/EIPs/issues/84).
|
||||
* (types) [tharsis#513](https://github.com/cosmos/ethermint/pull/513) Fix simulated transaction bug that was causing a consensus error by unintentionally affecting the state.
|
||||
* (ante) [\#525](https://github.com/cosmos/ethermint/pull/525) Add message validation decorator to `AnteHandler` for `MsgEthereumTx`.
|
||||
* (types) [\#507](https://github.com/cosmos/ethermint/pull/507) Fix hardcoded `aphoton` on `EthAccount` balance getter and setter.
|
||||
* (types) [\#501](https://github.com/cosmos/ethermint/pull/501) Fix bech32 encoding error by using the compressed ethereum secp256k1 public key.
|
||||
* (`x/evm`) [\#496](https://github.com/cosmos/ethermint/pull/496) Fix bugs on `journal.revert` and `CommitStateDB.Copy`.
|
||||
* (types) [\#480](https://github.com/cosmos/ethermint/pull/480) Update [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) coin type to `60` to satisfy [EIP84](https://github.com/ethereum/EIPs/issues/84).
|
||||
* (types) [\#513](https://github.com/cosmos/ethermint/pull/513) Fix simulated transaction bug that was causing a consensus error by unintentionally affecting the state.
|
||||
|
||||
## [v0.1.0] - 2020-08-23
|
||||
|
||||
### Improvements
|
||||
|
||||
* (sdk) [tharsis#386](https://github.com/cosmos/ethermint/pull/386) Bump Cosmos SDK version to [v0.39.1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.39.1)
|
||||
* (evm) [tharsis#181](https://github.com/cosmos/ethermint/issues/181) Updated EVM module to the recommended module structure.
|
||||
* (app) [tharsis#188](https://github.com/cosmos/ethermint/issues/186) Misc cleanup:
|
||||
* (evm) Rename `EthereumTxMsg` --> `MsgEthereumTx` and `EmintMsg` --> `MsgEthermint` for consistency with SDK standards
|
||||
* (sdk) [\#386](https://github.com/cosmos/ethermint/pull/386) Bump Cosmos SDK version to [v0.39.1](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.39.1)
|
||||
* (`x/evm`) [\#181](https://github.com/cosmos/ethermint/issues/181) Updated EVM module to the recommended module structure.
|
||||
* (app) [\#188](https://github.com/cosmos/ethermint/issues/186) Misc cleanup:
|
||||
* (`x/evm`) Rename `EthereumTxMsg` --> `MsgEthereumTx` and `EmintMsg` --> `MsgEthermint` for consistency with SDK standards
|
||||
* Updated integration and unit tests to use `EthermintApp` as testing suite
|
||||
* Use expected `Keeper` interface for `AccountKeeper`
|
||||
* Replaced `count` type in keeper with `int`
|
||||
* Add SDK events for transactions
|
||||
* [tharsis#236](https://github.com/cosmos/ethermint/pull/236) Changes from upgrade:
|
||||
* [\#236](https://github.com/cosmos/ethermint/pull/236) Changes from upgrade:
|
||||
* (`app/ante`) Moved `AnteHandler` implementation to `app/ante`
|
||||
* (keys) Marked `ExportEthKeyCommand` as **UNSAFE**
|
||||
* (evm) Moved `BeginBlock` and `EndBlock` to `x/evm/abci.go`
|
||||
* (evm) [tharsis#255](https://github.com/cosmos/ethermint/pull/255) Add missing `GenesisState` fields and support `ExportGenesis` functionality.
|
||||
* [tharsis#272](https://github.com/cosmos/ethermint/pull/272) Add `Logger` for evm module.
|
||||
* [tharsis#317](https://github.com/cosmos/ethermint/pull/317) `GenesisAccount` validation.
|
||||
* (evm) [tharsis#319](https://github.com/cosmos/ethermint/pull/319) Various evm improvements:
|
||||
* (`x/evm`) Moved `BeginBlock` and `EndBlock` to `x/evm/abci.go`
|
||||
* (`x/evm`) [\#255](https://github.com/cosmos/ethermint/pull/255) Add missing `GenesisState` fields and support `ExportGenesis` functionality.
|
||||
* [\#272](https://github.com/cosmos/ethermint/pull/272) Add `Logger` for evm module.
|
||||
* [\#317](https://github.com/cosmos/ethermint/pull/317) `GenesisAccount` validation.
|
||||
* (`x/evm`) [\#319](https://github.com/cosmos/ethermint/pull/319) Various evm improvements:
|
||||
* Add transaction `[]*ethtypes.Logs` to evm's `GenesisState` to persist logs after an upgrade.
|
||||
* Remove evm `CodeKey` and `BlockKey`in favor of a prefix `Store`.
|
||||
* Set `BlockBloom` during `EndBlock` instead of `BeginBlock`.
|
||||
* `Commit` state object and `Finalize` storage after `InitGenesis` setup.
|
||||
* (rpc) [tharsis#325](https://github.com/cosmos/ethermint/pull/325) `eth_coinbase` JSON-RPC query now returns the node's validator address.
|
||||
* (rpc) [\#325](https://github.com/cosmos/ethermint/pull/325) `eth_coinbase` JSON-RPC query now returns the node's validator address.
|
||||
|
||||
### Features
|
||||
|
||||
* (build) [tharsis#378](https://github.com/cosmos/ethermint/pull/378) Create multi-node, local, automated testnet setup with `make localnet-start`.
|
||||
* (rpc) [tharsis#330](https://github.com/cosmos/ethermint/issues/330) Implement `PublicFilterAPI`'s `EventSystem` which subscribes to Tendermint events upon `Filter` creation.
|
||||
* (rpc) [tharsis#231](https://github.com/cosmos/ethermint/issues/231) Implement `NewBlockFilter` in rpc/filters.go which instantiates a polling block filter
|
||||
* (build) [\#378](https://github.com/cosmos/ethermint/pull/378) Create multi-node, local, automated testnet setup with `make localnet-start`.
|
||||
* (rpc) [\#330](https://github.com/cosmos/ethermint/issues/330) Implement `PublicFilterAPI`'s `EventSystem` which subscribes to Tendermint events upon `Filter` creation.
|
||||
* (rpc) [\#231](https://github.com/cosmos/ethermint/issues/231) Implement `NewBlockFilter` in rpc/filters.go which instantiates a polling block filter
|
||||
* Polls for new blocks via `BlockNumber` rpc call; if block number changes, it requests the new block via `GetBlockByNumber` rpc call and adds it to its internal list of blocks
|
||||
* Update `uninstallFilter` and `getFilterChanges` accordingly
|
||||
* `uninstallFilter` stops the polling goroutine
|
||||
* `getFilterChanges` returns the filter's internal list of block hashes and resets it
|
||||
* (rpc) [tharsis#54](https://github.com/cosmos/ethermint/issues/54), [tharsis#55](https://github.com/cosmos/ethermint/issues/55)
|
||||
* (rpc) [\#54](https://github.com/cosmos/ethermint/issues/54), [\#55](https://github.com/cosmos/ethermint/issues/55)
|
||||
Implement `eth_getFilterLogs` and `eth_getLogs`:
|
||||
* For a given filter, look through each block for transactions. If there are transactions in the block, get the logs from it, and filter using the filterLogs method
|
||||
* `eth_getLogs` and `eth_getFilterChanges` for log filters use the same underlying method as `eth_getFilterLogs`
|
||||
* update `HandleMsgEthereumTx` to store logs using the ethereum hash
|
||||
* (app) [tharsis#187](https://github.com/cosmos/ethermint/issues/187) Add support for simulations.
|
||||
* (app) [\#187](https://github.com/cosmos/ethermint/issues/187) Add support for simulations.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* (evm) [tharsis#767](https://github.com/cosmos/ethermint/issues/767) Fix error of timeout when using Truffle to deploy contract.
|
||||
* (evm) [tharsis#751](https://github.com/cosmos/ethermint/issues/751) Fix misused method to calculate block hash in evm related function.
|
||||
* (evm) [tharsis#721](https://github.com/cosmos/ethermint/issues/721) Fix mismatch block hash in rpc response when use eth.getBlock.
|
||||
* (evm) [tharsis#730](https://github.com/cosmos/ethermint/issues/730) Fix 'EIP2028' not open when Istanbul version has been enabled.
|
||||
* (app) [tharsis#749](https://github.com/cosmos/ethermint/issues/749) Fix panic in `AnteHandler` when gas price larger than 100000
|
||||
* (rpc) [tharsis#305](https://github.com/cosmos/ethermint/issues/305) Update `eth_getTransactionCount` to check for account existence before getting sequence and return 0 as the nonce if it doesn't exist.
|
||||
* (evm) [tharsis#319](https://github.com/cosmos/ethermint/pull/319) Fix `SetBlockHash` that was setting the incorrect height during `BeginBlock`.
|
||||
* (evm) [tharsis#176](https://github.com/cosmos/ethermint/issues/176) Updated Web3 transaction hash from using RLP hash. Now all transaction hashes exposed are amino hashes:
|
||||
* (evm) [\#767](https://github.com/cosmos/ethermint/issues/767) Fix error of timeout when using Truffle to deploy contract.
|
||||
* (evm) [\#751](https://github.com/cosmos/ethermint/issues/751) Fix misused method to calculate block hash in evm related function.
|
||||
* (evm) [\#721](https://github.com/cosmos/ethermint/issues/721) Fix mismatch block hash in rpc response when use eth.getBlock.
|
||||
* (evm) [\#730](https://github.com/cosmos/ethermint/issues/730) Fix 'EIP2028' not open when Istanbul version has been enabled.
|
||||
* (app) [\#749](https://github.com/cosmos/ethermint/issues/749) Fix panic in `AnteHandler` when gas price larger than 100000
|
||||
* (rpc) [\#305](https://github.com/cosmos/ethermint/issues/305) Update `eth_getTransactionCount` to check for account existence before getting sequence and return 0 as the nonce if it doesn't exist.
|
||||
* (`x/evm`) [\#319](https://github.com/cosmos/ethermint/pull/319) Fix `SetBlockHash` that was setting the incorrect height during `BeginBlock`.
|
||||
* (`x/evm`) [\#176](https://github.com/cosmos/ethermint/issues/176) Updated Web3 transaction hash from using RLP hash. Now all transaction hashes exposed are amino hashes:
|
||||
* Removes `Hash()` (RLP) function from `MsgEthereumTx` to avoid confusion or misuse in future.
|
||||
|
@ -1,23 +1,23 @@
|
||||
# Contributing
|
||||
|
||||
- [Contributing](#contributing)
|
||||
- [Architecture Decision Records (ADR)](#architecture-decision-records-adr)
|
||||
- [Pull Requests](#pull-requests)
|
||||
- [Pull Request Templates](#pull-request-templates)
|
||||
- [Requesting Reviews](#requesting-reviews)
|
||||
- [Reviewing Pull Requests](#reviewing-pull-requests)
|
||||
- [Updating Documentation](#updating-documentation)
|
||||
- [Forking](#forking)
|
||||
- [Dependencies](#dependencies)
|
||||
- [Protobuf](#protobuf)
|
||||
- [Testing](#testing)
|
||||
- [Branching Model and Release](#branching-model-and-release)
|
||||
- [PR Targeting](#pr-targeting)
|
||||
- [Development Procedure](#development-procedure)
|
||||
- [Pull Merge Procedure](#pull-merge-procedure)
|
||||
- [Release Procedure](#release-procedure)
|
||||
- [Point Release Procedure](#point-release-procedure)
|
||||
- [Code Owner Membership](#code-owner-membership)
|
||||
- [Architecture Decision Records (ADR)](#architecture-decision-records-adr)
|
||||
- [Pull Requests](#pull-requests)
|
||||
- [Pull Request Templates](#pull-request-templates)
|
||||
- [Requesting Reviews](#requesting-reviews)
|
||||
- [Reviewing Pull Requests](#reviewing-pull-requests)
|
||||
- [Updating Documentation](#updating-documentation)
|
||||
- [Forking](#forking)
|
||||
- [Dependencies](#dependencies)
|
||||
- [Protobuf](#protobuf)
|
||||
- [Testing](#testing)
|
||||
- [Branching Model and Release](#branching-model-and-release)
|
||||
- [PR Targeting](#pr-targeting)
|
||||
- [Development Procedure](#development-procedure)
|
||||
- [Pull Merge Procedure](#pull-merge-procedure)
|
||||
- [Release Procedure](#release-procedure)
|
||||
- [Point Release Procedure](#point-release-procedure)
|
||||
- [Code Owner Membership](#code-owner-membership)
|
||||
|
||||
Thank you for considering making contributions to Ethermint!
|
||||
|
||||
@ -25,8 +25,8 @@ Contributing to this repo can mean many things such as participating in
|
||||
discussion or proposing code changes. To ensure a smooth workflow for all
|
||||
contributors, the general procedure for contributing has been established:
|
||||
|
||||
1. Either [open](https://github.com/evmos/ethermint/issues/new/choose) or
|
||||
[find](https://github.com/evmos/ethermint/issues) an issue you'd like to help with
|
||||
1. Either [open](https://github.com/tharsis/ethermint/issues/new/choose) or
|
||||
[find](https://github.com/tharsis/ethermint/issues) an issue you'd like to help with
|
||||
2. Participate in thoughtful discussion on that issue
|
||||
3. If you would like to contribute:
|
||||
1. If the issue is a proposal, ensure that the proposal has been accepted
|
||||
@ -55,7 +55,7 @@ taken place in a GitHub issue, that PR runs a high likelihood of being rejected.
|
||||
Other notes:
|
||||
|
||||
- Looking for a good place to start contributing? How about checking out some
|
||||
[good first issues](https://github.com/evmos/ethermint/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
|
||||
[good first issues](https://github.com/tharsis/ethermint/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
|
||||
- Please make sure to run `make format` before every commit - the easiest way
|
||||
to do this is have your editor run it for you upon saving a file. Additionally
|
||||
please ensure that your code is lint compliant by running `make lint-fix`.
|
||||
@ -64,7 +64,7 @@ Other notes:
|
||||
|
||||
## Architecture Decision Records (ADR)
|
||||
|
||||
When proposing an architecture decision for Ethermint, please start by opening an [issue](https://github.com/evmos/ethermint/issues/new/choose) or a [discussion](https://github.com/evmos/ethermint/discussions/new) with a summary of the proposal. Once the proposal has been discussed and there is rough alignment on a high-level approach to the design, the [ADR creation process](https://github.com/evmos/ethermint/blob/main/docs/architecture/PROCESS.md) can begin. We are following this process to ensure all involved parties are in agreement before any party begins coding the proposed implementation. If you would like to see examples of how these are written, please refer to the current [ADRs](https://github.com/evmos/ethermint/tree/main/docs/architecture).
|
||||
When proposing an architecture decision for Ethermint, please start by opening an [issue](https://github.com/tharsis/ethermint/issues/new/choose) or a [discussion](https://github.com/tharsis/ethermint/discussions/new) with a summary of the proposal. Once the proposal has been discussed and there is rough alignment on a high-level approach to the design, the [ADR creation process](https://github.com/tharsis/ethermint/blob/main/docs/architecture/PROCESS.md) can begin. We are following this process to ensure all involved parties are in agreement before any party begins coding the proposed implementation. If you would like to see examples of how these are written, please refer to the current [ADRs](https://github.com/tharsis/ethermint/tree/main/docs/architecture).
|
||||
|
||||
## Pull Requests
|
||||
|
||||
@ -97,27 +97,37 @@ items. In addition, use the following review explanations:
|
||||
|
||||
- `LGTM` without an explicit approval means that the changes look good, but you haven't thoroughly reviewed the reviewer checklist items.
|
||||
- `Approval` means that you have completed some or all of the reviewer checklist items. If you only reviewed selected items, you must add your handle next to the items that you have reviewed. In addition, follow these guidelines:
|
||||
- You must also think through anything which ought to be included but is not
|
||||
- You must think through whether any added code could be partially combined (DRYed) with existing code
|
||||
- You must think through any potential security issues or incentive-compatibility flaws introduced by the changes
|
||||
- Naming must be consistent with conventions and the rest of the codebase
|
||||
- Code must live in a reasonable location, considering dependency structures (for example, not importing testing modules in production code, or including example code modules in production code).
|
||||
- If you approve the PR, you are responsible for any issues mentioned here and any issues that should have been addressed after thoroughly reviewing the reviewer checklist items in the pull request template.
|
||||
- You must also think through anything which ought to be included but is not
|
||||
- You must think through whether any added code could be partially combined (DRYed) with existing code
|
||||
- You must think through any potential security issues or incentive-compatibility flaws introduced by the changes
|
||||
- Naming must be consistent with conventions and the rest of the codebase
|
||||
- Code must live in a reasonable location, considering dependency structures (for example, not importing testing modules in production code, or including example code modules in production code).
|
||||
- If you approve the PR, you are responsible for any issues mentioned here and any issues that should have been addressed after thoroughly reviewing the reviewer checklist items in the pull request template.
|
||||
- If you sat down with the PR submitter and did a pairing review, add this information in the `Approval` or your PR comments.
|
||||
- If you are only making "surface level" reviews, submit any notes as `Comments` without adding a review.
|
||||
|
||||
### Updating Documentation
|
||||
|
||||
If you open a PR on Ethermint, it is mandatory to update the relevant documentation in `/docs`.
|
||||
|
||||
- If your change relates to the core SDK (baseapp, store, ...), be sure to update the content in `docs/basics/`, `docs/core/` and/or `docs/building-modules/` folders.
|
||||
- If your changes relate to the core of the CLI (not specifically to module's CLI/Rest), then modify the content in the `docs/run-node/` folder.
|
||||
- If your changes relate to a module, then be sure to update the module's spec in `x/moduleName/docs/spec/`.
|
||||
|
||||
When writing documentation, follow the [Documentation Writing Guidelines](./docs/DOC_WRITING_GUIDELINES.md).
|
||||
|
||||
## Forking
|
||||
|
||||
Go requires code to live under absolute paths, and this requirement complicates forking.
|
||||
While my fork lives at `https://github.com/rigeyrigerige/ethermint`,
|
||||
the code should never exist at `$GOPATH/src/github.com/rigeyrigerige/ethermint`.
|
||||
Instead, we use `git remote` to add the fork as a new remote for the original repo,
|
||||
`$GOPATH/src/github.com/evmos/ethermint`, and do all the work there.
|
||||
`$GOPATH/src/github.com/tharsis/ethermint`, and do all the work there.
|
||||
|
||||
For instance, to create a fork and work on a branch of it, I would:
|
||||
|
||||
- Create the fork on GitHub, using the fork button.
|
||||
- Go to the original repo checked out locally (i.e. `$GOPATH/src/github.com/evmos/ethermint`)
|
||||
- Go to the original repo checked out locally (i.e. `$GOPATH/src/github.com/tharsis/ethermint`)
|
||||
- `git remote rename origin upstream`
|
||||
- `git remote add origin git@github.com:rigeyrigerige/ethermint.git`
|
||||
|
||||
@ -220,7 +230,7 @@ should be targeted against the release candidate branch.
|
||||
- `main` must never fail `make lint test test-race`
|
||||
- `main` should not fail `make lint`
|
||||
- no `--force` onto `main` (except when reverting a broken commit, which should seldom happen)
|
||||
- create a development branch either on github.com/evmos/ethermint, or your fork (using `git remote add origin`)
|
||||
- create a development branch either on github.com/tharsis/ethermint, or your fork (using `git remote add origin`)
|
||||
- before submitting a pull request, begin `git rebase` on top of `main`
|
||||
|
||||
### Pull Merge Procedure
|
||||
@ -235,10 +245,10 @@ should be targeted against the release candidate branch.
|
||||
- Create the release candidate branch `release/v<major>.<minor>.x` (going forward known as **RC**)
|
||||
and ensure it's protected against pushing from anyone except the release
|
||||
manager/coordinator
|
||||
- **no PRs targeting this branch should be merged unless exceptional circumstances arise**
|
||||
- **no PRs targeting this branch should be merged unless exceptional circumstances arise**
|
||||
- On the `RC` branch, prepare a new version section in the `CHANGELOG.md`
|
||||
- All links must be link-ified: `$ python ./scripts/linkify_changelog.py CHANGELOG.md`
|
||||
- Copy the entries into a `RELEASE_CHANGELOG.md`, this is needed so the bot knows which entries to add to the release page on GitHub.
|
||||
- All links must be link-ified: `$ python ./scripts/linkify_changelog.py CHANGELOG.md`
|
||||
- Copy the entries into a `RELEASE_CHANGELOG.md`, this is needed so the bot knows which entries to add to the release page on GitHub.
|
||||
- Kick off a large round of simulation testing (e.g. 400 seeds for 2k blocks)
|
||||
- If errors are found during the simulation testing, commit the fixes to `main`
|
||||
and push the changes to the `RC` branch
|
||||
@ -343,7 +353,7 @@ is broken up into three distinct stages: **Strategy Discovery**, **Concept Appro
|
||||
|
||||
- Architecture Decision Records (ADRs) may be proposed by any contributors or maintainers of Ethermint,
|
||||
and should follow the guidelines outlined in the
|
||||
[ADR Creation Process](https://github.com/evmos/ethermint/blob/main/docs/architecture/PROCESS.md)
|
||||
[ADR Creation Process](https://github.com/tharsis/ethermint/blob/main/docs/architecture/PROCESS.md)
|
||||
- After proposal, a time bound period for Request for Comment (RFC) on ADRs commences
|
||||
- ADRs are intended to be iterative, and may be merged into `main` while still in a `Proposed` status
|
||||
|
||||
@ -383,8 +393,8 @@ Members must:
|
||||
- Be active contributors to Ethermint, and furthermore should be continuously making substantial contributions
|
||||
to the project's codebase, review process, documentation and ADRs
|
||||
- Have stake in Ethermint, represented by:
|
||||
- Being a client / user of Ethermint
|
||||
- "[giving back](https://www.debian.org/social_contract)" to the software
|
||||
- Being a client / user of Ethermint
|
||||
- "[giving back](https://www.debian.org/social_contract)" to the software
|
||||
- Delegate representation in case of vacation or absence
|
||||
|
||||
Code owners need to maintain participation in the process, ideally as members of **Concept Approval Committee**
|
||||
|
24
Dockerfile
24
Dockerfile
@ -1,14 +1,14 @@
|
||||
FROM golang:alpine AS build-env
|
||||
|
||||
# Install dependencies
|
||||
RUN apk add --update git build-base linux-headers
|
||||
# Set up dependencies
|
||||
ENV PACKAGES git build-base
|
||||
|
||||
# Set working directory for the build
|
||||
WORKDIR /go/src/github.com/cerc-io/laconicd
|
||||
WORKDIR /go/src/github.com/tharsis/ethermint
|
||||
|
||||
# Cache Go modules
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
# Install dependencies
|
||||
RUN apk add --update $PACKAGES
|
||||
RUN apk add linux-headers
|
||||
|
||||
# Add source files
|
||||
COPY . .
|
||||
@ -17,14 +17,14 @@ COPY . .
|
||||
RUN make build
|
||||
|
||||
# Final image
|
||||
FROM alpine:3.17.0
|
||||
FROM alpine
|
||||
|
||||
# Install ca-certificates
|
||||
RUN apk add --update ca-certificates jq curl
|
||||
RUN apk add --update ca-certificates jq
|
||||
WORKDIR /
|
||||
|
||||
# Copy over binaries from the build-env
|
||||
COPY --from=build-env /go/src/github.com/cerc-io/laconicd/build/laconicd /usr/bin/laconicd
|
||||
COPY --from=build-env /go/src/github.com/tharsis/ethermint/build/ethermintd /usr/bin/ethermintd
|
||||
|
||||
WORKDIR /
|
||||
# Run laconicd by default
|
||||
CMD ["laconicd"]
|
||||
# Run ethermintd by default
|
||||
CMD ["ethermintd"]
|
||||
|
302
LICENSE
302
LICENSE
@ -1,165 +1,201 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
0. Additional Definitions.
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
4. Combined Works.
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
d) Do one of the following:
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
5. Combined Libraries.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
388
Makefile
Normal file → Executable file
388
Makefile
Normal file → Executable file
@ -7,16 +7,14 @@ TMVERSION := $(shell go list -m github.com/tendermint/tendermint | sed 's:.* ::'
|
||||
COMMIT := $(shell git log -1 --format='%H')
|
||||
LEDGER_ENABLED ?= true
|
||||
BINDIR ?= $(GOPATH)/bin
|
||||
LACONIC_BINARY = laconicd
|
||||
LACONIC_DIR = laconic
|
||||
ETHERMINT_BINARY = ethermintd
|
||||
ETHERMINT_DIR = ethermint
|
||||
BUILDDIR ?= $(CURDIR)/build
|
||||
SIMAPP = ./app
|
||||
HTTPS_GIT := https://github.com/cerc-io/laconicd.git
|
||||
PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
|
||||
HTTPS_GIT := https://github.com/tharsis/ethermint.git
|
||||
DOCKER := $(shell which docker)
|
||||
# RocksDB is a native dependency, so we don't assume the library is installed.
|
||||
# Instead, it must be explicitly enabled and we warn when it is not.
|
||||
ENABLE_ROCKSDB ?= false
|
||||
DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf
|
||||
PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
|
||||
|
||||
export GO111MODULE = on
|
||||
|
||||
@ -51,6 +49,9 @@ ifeq ($(LEDGER_ENABLED),true)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (cleveldb,$(findstring cleveldb,$(COSMOS_BUILD_OPTIONS)))
|
||||
build_tags += gcc
|
||||
endif
|
||||
build_tags += $(BUILD_TAGS)
|
||||
build_tags := $(strip $(build_tags))
|
||||
|
||||
@ -61,38 +62,30 @@ build_tags_comma_sep := $(subst $(whitespace),$(comma),$(build_tags))
|
||||
|
||||
# process linker flags
|
||||
|
||||
ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=laconic \
|
||||
-X github.com/cosmos/cosmos-sdk/version.AppName=$(LACONIC_BINARY) \
|
||||
ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=ethermint \
|
||||
-X github.com/cosmos/cosmos-sdk/version.AppName=$(ETHERMINT_BINARY) \
|
||||
-X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
|
||||
-X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \
|
||||
-X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)" \
|
||||
-X github.com/tendermint/tendermint/version.TMCoreSemVer=$(TMVERSION)
|
||||
|
||||
ifeq ($(ENABLE_ROCKSDB),true)
|
||||
BUILD_TAGS += rocksdb_build
|
||||
test_tags += rocksdb_build
|
||||
else
|
||||
$(info RocksDB support is disabled; to build and test with RocksDB support, set ENABLE_ROCKSDB=true)
|
||||
endif
|
||||
|
||||
# DB backend selection
|
||||
ifeq (cleveldb,$(findstring cleveldb,$(COSMOS_BUILD_OPTIONS)))
|
||||
BUILD_TAGS += gcc
|
||||
ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=cleveldb
|
||||
endif
|
||||
ifeq (badgerdb,$(findstring badgerdb,$(COSMOS_BUILD_OPTIONS)))
|
||||
BUILD_TAGS += badgerdb
|
||||
ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=badgerdb
|
||||
endif
|
||||
# handle rocksdb
|
||||
ifeq (rocksdb,$(findstring rocksdb,$(COSMOS_BUILD_OPTIONS)))
|
||||
ifneq ($(ENABLE_ROCKSDB),true)
|
||||
$(error Cannot use RocksDB backend unless ENABLE_ROCKSDB=true)
|
||||
endif
|
||||
CGO_ENABLED=1
|
||||
BUILD_TAGS += rocksdb
|
||||
ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=rocksdb
|
||||
endif
|
||||
# handle boltdb
|
||||
ifeq (boltdb,$(findstring boltdb,$(COSMOS_BUILD_OPTIONS)))
|
||||
BUILD_TAGS += boltdb
|
||||
ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=boltdb
|
||||
endif
|
||||
|
||||
ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS)))
|
||||
@ -101,21 +94,12 @@ endif
|
||||
ldflags += $(LDFLAGS)
|
||||
ldflags := $(strip $(ldflags))
|
||||
|
||||
build_tags += $(BUILD_TAGS)
|
||||
build_tags := $(strip $(build_tags))
|
||||
|
||||
BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
|
||||
# check for nostrip option
|
||||
ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS)))
|
||||
BUILD_FLAGS += -trimpath
|
||||
endif
|
||||
|
||||
# check if no optimization option is passed
|
||||
# used for remote debugging
|
||||
ifneq (,$(findstring nooptimization,$(COSMOS_BUILD_OPTIONS)))
|
||||
BUILD_FLAGS += -gcflags "all=-N -l"
|
||||
endif
|
||||
|
||||
# # The below include contains the tools and runsim targets.
|
||||
# include contrib/devtools/Makefile
|
||||
|
||||
@ -135,20 +119,18 @@ $(BUILD_TARGETS): go.sum $(BUILDDIR)/
|
||||
$(BUILDDIR)/:
|
||||
mkdir -p $(BUILDDIR)/
|
||||
|
||||
.PHONY: build build-linux
|
||||
|
||||
docker-build:
|
||||
# TODO replace with kaniko
|
||||
docker build -t ${DOCKER_IMAGE}:${DOCKER_TAG} .
|
||||
docker tag ${DOCKER_IMAGE}:${DOCKER_TAG} ${DOCKER_IMAGE}:latest
|
||||
# docker tag ${DOCKER_IMAGE}:${DOCKER_TAG} ${DOCKER_IMAGE}:${COMMIT_HASH}
|
||||
# update old container
|
||||
docker rm laconicd || true
|
||||
docker rm ethermint || true
|
||||
# create a new container from the latest image
|
||||
docker create --name laconic -t -i ${DOCKER_IMAGE}:${DOCKER_TAG} laconicd
|
||||
docker create --name ethermint -t -i tharsis/ethermint:latest ethermint
|
||||
# move the binaries to the ./build directory
|
||||
mkdir -p ./build/
|
||||
docker cp laconic:/usr/bin/laconicd ./build/
|
||||
docker cp ethermint:/usr/bin/ethermintd ./build/
|
||||
|
||||
$(MOCKS_DIR):
|
||||
mkdir -p $(MOCKS_DIR)
|
||||
@ -163,47 +145,10 @@ clean:
|
||||
|
||||
all: build
|
||||
|
||||
build-all: tools build lint test vulncheck
|
||||
build-all: tools build lint test
|
||||
|
||||
.PHONY: distclean clean build-all
|
||||
|
||||
###############################################################################
|
||||
### Releasing ###
|
||||
###############################################################################
|
||||
|
||||
PACKAGE_NAME:=github.com/cerc-io/laconicd
|
||||
GOLANG_CROSS_VERSION = v1.19
|
||||
GOPATH ?= '$(HOME)/go'
|
||||
release-dry-run:
|
||||
docker run \
|
||||
--rm \
|
||||
--privileged \
|
||||
-e CGO_ENABLED=1 \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v `pwd`:/go/src/$(PACKAGE_NAME) \
|
||||
-v ${GOPATH}/pkg:/go/pkg \
|
||||
-w /go/src/$(PACKAGE_NAME) \
|
||||
ghcr.io/goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \
|
||||
--rm-dist --skip-validate --skip-publish --snapshot
|
||||
|
||||
release:
|
||||
@if [ ! -f ".release-env" ]; then \
|
||||
echo "\033[91m.release-env is required for release\033[0m";\
|
||||
exit 1;\
|
||||
fi
|
||||
docker run \
|
||||
--rm \
|
||||
--privileged \
|
||||
-e CGO_ENABLED=1 \
|
||||
--env-file .release-env \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v `pwd`:/go/src/$(PACKAGE_NAME) \
|
||||
-w /go/src/$(PACKAGE_NAME) \
|
||||
ghcr.io/goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \
|
||||
release --rm-dist --skip-validate
|
||||
|
||||
.PHONY: release-dry-run release
|
||||
|
||||
###############################################################################
|
||||
### Tools & Dependencies ###
|
||||
###############################################################################
|
||||
@ -220,7 +165,7 @@ RUNSIM = $(TOOLS_DESTDIR)/runsim
|
||||
runsim: $(RUNSIM)
|
||||
$(RUNSIM):
|
||||
@echo "Installing runsim..."
|
||||
@(cd /tmp && ${GO_MOD} go install github.com/cosmos/tools/cmd/runsim@master)
|
||||
@(cd /tmp && ${GO_MOD} go get github.com/cosmos/tools/cmd/runsim@master)
|
||||
|
||||
statik: $(STATIK)
|
||||
$(STATIK):
|
||||
@ -237,7 +182,7 @@ endif
|
||||
|
||||
ifeq (, $(shell which go-bindata))
|
||||
@echo "Installing go-bindata..."
|
||||
@go get github.com/kevinburke/go-bindata/go-bindata@v3
|
||||
@go get github.com/kevinburke/go-bindata/go-bindata
|
||||
else
|
||||
@echo "go-bindata already installed; skipping..."
|
||||
endif
|
||||
@ -256,6 +201,14 @@ else
|
||||
@echo "protoc-gen-go already installed; skipping..."
|
||||
endif
|
||||
|
||||
ifeq (, $(shell which protoc))
|
||||
@echo "Please istalling protobuf according to your OS"
|
||||
@echo "macOS: brew install protobuf"
|
||||
@echo "linux: apt-get install -f -y protobuf-compiler"
|
||||
else
|
||||
@echo "protoc already installed; skipping..."
|
||||
endif
|
||||
|
||||
ifeq (, $(shell which solcjs))
|
||||
@echo "Installing solcjs..."
|
||||
@npm install -g solc@0.5.11
|
||||
@ -263,8 +216,16 @@ else
|
||||
@echo "solcjs already installed; skipping..."
|
||||
endif
|
||||
|
||||
docs-tools:
|
||||
ifeq (, $(shell which yarn))
|
||||
@echo "Installing yarn..."
|
||||
@npm install -g yarn
|
||||
else
|
||||
@echo "yarn already installed; skipping..."
|
||||
endif
|
||||
|
||||
tools: tools-stamp
|
||||
tools-stamp: contract-tools proto-tools statik runsim
|
||||
tools-stamp: contract-tools docs-tools proto-tools statik runsim
|
||||
# Create dummy file to satisfy dependency and avoid
|
||||
# rebuilding when this Makefile target is hit twice
|
||||
# in a row.
|
||||
@ -274,17 +235,19 @@ tools-clean:
|
||||
rm -f $(RUNSIM)
|
||||
rm -f tools-stamp
|
||||
|
||||
.PHONY: runsim statik tools contract-tools proto-tools tools-stamp tools-clean
|
||||
docs-tools-stamp: docs-tools
|
||||
# Create dummy file to satisfy dependency and avoid
|
||||
# rebuilding when this Makefile target is hit twice
|
||||
# in a row.
|
||||
touch $@
|
||||
|
||||
.PHONY: runsim statik tools contract-tools docs-tools proto-tools tools-stamp tools-clean docs-tools-stamp
|
||||
|
||||
go.sum: go.mod
|
||||
echo "Ensure dependencies have not been modified ..." >&2
|
||||
go mod verify
|
||||
go mod tidy
|
||||
|
||||
vulncheck: $(BUILDDIR)/
|
||||
GOBIN=$(BUILDDIR) go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
$(BUILDDIR)/govulncheck ./...
|
||||
|
||||
###############################################################################
|
||||
### Documentation ###
|
||||
###############################################################################
|
||||
@ -300,23 +263,51 @@ update-swagger-docs: statik
|
||||
.PHONY: update-swagger-docs
|
||||
|
||||
godocs:
|
||||
@echo "--> Wait a few seconds and visit http://localhost:6060/pkg/github.com/cerc-io/laconicd/types"
|
||||
@echo "--> Wait a few seconds and visit http://localhost:6060/pkg/github.com/tharsis/ethermint/types"
|
||||
godoc -http=:6060
|
||||
|
||||
# Start docs site at localhost:8080
|
||||
docs-serve:
|
||||
@cd docs && \
|
||||
yarn && \
|
||||
yarn run serve
|
||||
|
||||
# Build the site into docs/.vuepress/dist
|
||||
build-docs:
|
||||
@$(MAKE) docs-tools-stamp && \
|
||||
cd docs && \
|
||||
yarn && \
|
||||
yarn run build
|
||||
|
||||
# This builds a docs site for each branch/tag in `./docs/versions`
|
||||
# and copies each site to a version prefixed path. The last entry inside
|
||||
# the `versions` file will be the default root index.html.
|
||||
build-docs-versioned:
|
||||
@$(MAKE) docs-tools-stamp && \
|
||||
cd docs && \
|
||||
while read -r branch path_prefix; do \
|
||||
(git checkout $${branch} && npm install && VUEPRESS_BASE="/$${path_prefix}/" npm run build) ; \
|
||||
mkdir -p ~/output/$${path_prefix} ; \
|
||||
cp -r .vuepress/dist/* ~/output/$${path_prefix}/ ; \
|
||||
cp ~/output/$${path_prefix}/index.html ~/output ; \
|
||||
done < versions ;
|
||||
|
||||
.PHONY: docs-serve build-docs build-docs-versioned
|
||||
|
||||
###############################################################################
|
||||
### Tests & Simulation ###
|
||||
###############################################################################
|
||||
|
||||
test: test-unit
|
||||
test-all: test-unit test-race
|
||||
PACKAGES_UNIT=$(shell go list ./... | grep -Ev 'vendor|importer')
|
||||
PACKAGES_UNIT=$(shell go list ./...)
|
||||
TEST_PACKAGES=./...
|
||||
TEST_TARGETS := test-unit test-unit-cover test-race
|
||||
|
||||
# Test runs-specific rules. To add a new test target, just add
|
||||
# a new rule, customise ARGS or TEST_PACKAGES ad libitum, and
|
||||
# append the new rule to the TEST_TARGETS list.
|
||||
test-unit: ARGS=-timeout=10m -race -test.v -skip $(SKIP_UNIT_TESTS)
|
||||
test-unit: ARGS=-timeout=10m -race
|
||||
test-unit: TEST_PACKAGES=$(PACKAGES_UNIT)
|
||||
|
||||
test-race: ARGS=-race
|
||||
@ -334,20 +325,22 @@ else
|
||||
endif
|
||||
|
||||
test-import:
|
||||
go test -run TestImporterTestSuite -timeout=20m -v --vet=off github.com/cerc-io/laconicd/tests/importer
|
||||
@go test ./tests/importer -v --vet=off --run=TestImportBlocks --datadir tmp \
|
||||
--blockchain blockchain
|
||||
rm -rf tests/importer/tmp
|
||||
|
||||
test-rpc:
|
||||
./scripts/integration-test-all.sh -t "rpc" -q 1 -z 1 -s 10 -m "rpc" -r "true"
|
||||
|
||||
run-integration-tests:
|
||||
@nix-shell ./tests/integration_tests/shell.nix --run ./scripts/run-integration-tests.sh
|
||||
|
||||
.PHONY: run-integration-tests
|
||||
|
||||
./scripts/integration-test-all.sh -t "rpc" -q 1 -z 1 -s 2 -m "rpc" -r "true"
|
||||
|
||||
test-rpc-pending:
|
||||
./scripts/integration-test-all.sh -t "pending" -q 1 -z 1 -s 2 -m "pending" -r "true"
|
||||
|
||||
test-contract:
|
||||
@type "npm" 2> /dev/null || (echo 'Npm does not exist. Please install node.js and npm."' && exit 1)
|
||||
@type "solcjs" 2> /dev/null || (echo 'Solcjs does not exist. Please install solcjs using make contract-tools."' && exit 1)
|
||||
@type "protoc" 2> /dev/null || (echo 'Failed to install protoc. Please reinstall protoc using make contract-tools.' && exit 1)
|
||||
bash scripts/contract-test.sh
|
||||
|
||||
test-solidity:
|
||||
@echo "Beginning solidity tests..."
|
||||
./scripts/run-solidity-tests.sh
|
||||
@ -355,6 +348,53 @@ test-solidity:
|
||||
|
||||
.PHONY: run-tests test test-all test-import test-rpc test-contract test-solidity $(TEST_TARGETS)
|
||||
|
||||
test-sim-nondeterminism:
|
||||
@echo "Running non-determinism test..."
|
||||
@go test -mod=readonly $(SIMAPP) -run TestAppStateDeterminism -Enabled=true \
|
||||
-NumBlocks=100 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h
|
||||
|
||||
test-sim-custom-genesis-fast:
|
||||
@echo "Running custom genesis simulation..."
|
||||
@echo "By default, ${HOME}/.$(ETHERMINT_DIR)/config/genesis.json will be used."
|
||||
@go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation -Genesis=${HOME}/.$(ETHERMINT_DIR)/config/genesis.json \
|
||||
-Enabled=true -NumBlocks=100 -BlockSize=200 -Commit=true -Seed=99 -Period=5 -v -timeout 24h
|
||||
|
||||
test-sim-import-export: runsim
|
||||
@echo "Running application import/export simulation. This may take several minutes..."
|
||||
@$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppImportExport
|
||||
|
||||
test-sim-after-import: runsim
|
||||
@echo "Running application simulation-after-import. This may take several minutes..."
|
||||
@$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 5 TestAppSimulationAfterImport
|
||||
|
||||
test-sim-custom-genesis-multi-seed: runsim
|
||||
@echo "Running multi-seed custom genesis simulation..."
|
||||
@echo "By default, ${HOME}/.$(ETHERMINT_DIR)/config/genesis.json will be used."
|
||||
@$(BINDIR)/runsim -Genesis=${HOME}/.$(ETHERMINT_DIR)/config/genesis.json -SimAppPkg=$(SIMAPP) -ExitOnFail 400 5 TestFullAppSimulation
|
||||
|
||||
test-sim-multi-seed-long: runsim
|
||||
@echo "Running long multi-seed application simulation. This may take awhile!"
|
||||
@$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 500 50 TestFullAppSimulation
|
||||
|
||||
test-sim-multi-seed-short: runsim
|
||||
@echo "Running short multi-seed application simulation. This may take awhile!"
|
||||
@$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(SIMAPP) -ExitOnFail 50 10 TestFullAppSimulation
|
||||
|
||||
test-sim-benchmark-invariants:
|
||||
@echo "Running simulation invariant benchmarks..."
|
||||
@go test -mod=readonly $(SIMAPP) -benchmem -bench=BenchmarkInvariants -run=^$ \
|
||||
-Enabled=true -NumBlocks=1000 -BlockSize=200 \
|
||||
-Period=1 -Commit=true -Seed=57 -v -timeout 24h
|
||||
|
||||
.PHONY: \
|
||||
test-sim-nondeterminism \
|
||||
test-sim-custom-genesis-fast \
|
||||
test-sim-import-export \
|
||||
test-sim-after-import \
|
||||
test-sim-custom-genesis-multi-seed \
|
||||
test-sim-multi-seed-short \
|
||||
test-sim-multi-seed-long \
|
||||
test-sim-benchmark-invariants
|
||||
|
||||
benchmark:
|
||||
@go test -mod=readonly -bench=. $(PACKAGES_NOSIMULATION)
|
||||
@ -365,19 +405,14 @@ benchmark:
|
||||
###############################################################################
|
||||
|
||||
lint:
|
||||
@@test -n "$$golangci-lint version | awk '$4 >= 1.42')"
|
||||
golangci-lint run --out-format=tab -n
|
||||
|
||||
lint-py:
|
||||
flake8 --show-source --count --statistics \
|
||||
--format="::error file=%(path)s,line=%(row)d,col=%(col)d::%(path)s:%(row)d:%(col)d: %(code)s %(text)s" \
|
||||
golangci-lint run --out-format=tab
|
||||
|
||||
format:
|
||||
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/docs/statik/statik.go" -not -name '*.pb.go' -not -name '*.pb.gw.go' | xargs gofumpt -d -e -extra
|
||||
|
||||
lint-fix:
|
||||
golangci-lint run --fix --out-format=tab --issues-exit-code=0
|
||||
.PHONY: lint lint-fix lint-py
|
||||
.PHONY: lint lint-fix
|
||||
|
||||
format-fix:
|
||||
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/docs/statik/statik.go" -not -name '*.pb.go' -not -name '*.pb.gw.go' | xargs gofumpt -w -s
|
||||
@ -388,62 +423,80 @@ format-fix:
|
||||
### Protobuf ###
|
||||
###############################################################################
|
||||
|
||||
# ------
|
||||
# NOTE: Link to the tendermintdev/sdk-proto-gen docker images:
|
||||
# https://hub.docker.com/r/tendermintdev/sdk-proto-gen/tags
|
||||
#
|
||||
protoVer=v0.7
|
||||
protoVer=v0.2
|
||||
protoImageName=tendermintdev/sdk-proto-gen:$(protoVer)
|
||||
protoImage=$(DOCKER) run --network host --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName)
|
||||
# ------
|
||||
# NOTE: cosmos/proto-builder image is needed because clang-format is not installed
|
||||
# on the tendermintdev/sdk-proto-gen docker image.
|
||||
# Link to the cosmos/proto-builder docker images:
|
||||
# https://github.com/cosmos/cosmos-sdk/pkgs/container/proto-builder
|
||||
#
|
||||
protoCosmosVer=0.11.2
|
||||
protoCosmosName=ghcr.io/cosmos/proto-builder:$(protoCosmosVer)
|
||||
protoCosmosImage=$(DOCKER) run --network host --rm -v $(CURDIR):/workspace --workdir /workspace $(protoCosmosName)
|
||||
# ------
|
||||
# NOTE: Link to the yoheimuta/protolint docker images:
|
||||
# https://hub.docker.com/r/yoheimuta/protolint/tags
|
||||
#
|
||||
protolintVer=0.42.2
|
||||
protolintName=yoheimuta/protolint:$(protolintVer)
|
||||
protolintImage=$(DOCKER) run --network host --rm -v $(CURDIR):/workspace --workdir /workspace $(protolintName)
|
||||
containerProtoGen=$(PROJECT_NAME)-proto-gen-$(protoVer)
|
||||
containerProtoGenAny=$(PROJECT_NAME)-proto-gen-any-$(protoVer)
|
||||
containerProtoGenSwagger=$(PROJECT_NAME)-proto-gen-swagger-$(protoVer)
|
||||
containerProtoFmt=$(PROJECT_NAME)-proto-fmt-$(protoVer)
|
||||
|
||||
|
||||
# ------
|
||||
# NOTE: If you are experiencing problems running these commands, try deleting
|
||||
# the docker images and execute the desired command again.
|
||||
#
|
||||
proto-all: proto-format proto-lint proto-gen
|
||||
|
||||
proto-gen:
|
||||
@echo "Generating Protobuf files"
|
||||
$(protoImage) sh ./scripts/protocgen.sh
|
||||
@if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGen}$$"; then docker start -a $(containerProtoGen); else docker run --name $(containerProtoGen) -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) \
|
||||
sh ./scripts/protocgen.sh; fi
|
||||
|
||||
# This generates the SDK's custom wrapper for google.protobuf.Any. It should only be run manually when needed
|
||||
proto-gen-any:
|
||||
@echo "Generating Protobuf Any"
|
||||
@if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGenAny}$$"; then docker start -a $(containerProtoGenAny); else docker run --name $(containerProtoGenAny) -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) \
|
||||
sh ./scripts/protocgen-any.sh; fi
|
||||
|
||||
# TODO: Rethink API docs generation
|
||||
# proto-swagger-gen:
|
||||
# @echo "Generating Protobuf Swagger"
|
||||
# $(protoImage) sh ./scripts/protoc-swagger-gen.sh
|
||||
proto-swagger-gen:
|
||||
@echo "Generating Protobuf Swagger"
|
||||
@if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGenSwagger}$$"; then docker start -a $(containerProtoGenSwagger); else docker run --name $(containerProtoGenSwagger) -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) \
|
||||
sh ./scripts/protoc-swagger-gen.sh; fi
|
||||
|
||||
proto-format:
|
||||
@echo "Formatting Protobuf files"
|
||||
$(protoCosmosImage) find ./ -name *.proto -exec clang-format -i {} \;
|
||||
@if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoFmt}$$"; then docker start -a $(containerProtoFmt); else docker run --name $(containerProtoFmt) -v $(CURDIR):/workspace --workdir /workspace tendermintdev/docker-build-proto \
|
||||
find ./ -not -path "./third_party/*" -name "*.proto" -exec clang-format -i {} \; ; fi
|
||||
|
||||
# NOTE: The linter configuration lives in .protolint.yaml
|
||||
proto-lint:
|
||||
@echo "Linting Protobuf files"
|
||||
$(protolintImage) lint ./proto
|
||||
@$(DOCKER_BUF) lint --error-format=json
|
||||
|
||||
proto-check-breaking:
|
||||
@echo "Checking Protobuf files for breaking changes"
|
||||
$(protoImage) buf breaking --against $(HTTPS_GIT)#branch=main
|
||||
@$(DOCKER_BUF) breaking --against $(HTTPS_GIT)#branch=main
|
||||
|
||||
|
||||
.PHONY: proto-all proto-gen proto-gen-any proto-format proto-lint proto-check-breaking
|
||||
TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.12/proto/tendermint
|
||||
GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos
|
||||
COSMOS_SDK_URL = https://raw.githubusercontent.com/cosmos/cosmos-sdk/v0.43.0
|
||||
COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/master
|
||||
|
||||
TM_CRYPTO_TYPES = third_party/proto/tendermint/crypto
|
||||
TM_ABCI_TYPES = third_party/proto/tendermint/abci
|
||||
TM_TYPES = third_party/proto/tendermint/types
|
||||
|
||||
GOGO_PROTO_TYPES = third_party/proto/gogoproto
|
||||
|
||||
COSMOS_PROTO_TYPES = third_party/proto/cosmos_proto
|
||||
|
||||
proto-update-deps:
|
||||
@mkdir -p $(GOGO_PROTO_TYPES)
|
||||
@curl -sSL $(GOGO_PROTO_URL)/gogoproto/gogo.proto > $(GOGO_PROTO_TYPES)/gogo.proto
|
||||
|
||||
@mkdir -p $(COSMOS_PROTO_TYPES)
|
||||
@curl -sSL $(COSMOS_PROTO_URL)/cosmos.proto > $(COSMOS_PROTO_TYPES)/cosmos.proto
|
||||
|
||||
## Importing of tendermint protobuf definitions currently requires the
|
||||
## use of `sed` in order to build properly with cosmos-sdk's proto file layout
|
||||
## (which is the standard Buf.build FILE_LAYOUT)
|
||||
## Issue link: https://github.com/tendermint/tendermint/issues/5021
|
||||
@mkdir -p $(TM_ABCI_TYPES)
|
||||
@curl -sSL $(TM_URL)/abci/types.proto > $(TM_ABCI_TYPES)/types.proto
|
||||
|
||||
@mkdir -p $(TM_TYPES)
|
||||
@curl -sSL $(TM_URL)/types/types.proto > $(TM_TYPES)/types.proto
|
||||
|
||||
@mkdir -p $(TM_CRYPTO_TYPES)
|
||||
@curl -sSL $(TM_URL)/crypto/proof.proto > $(TM_CRYPTO_TYPES)/proof.proto
|
||||
@curl -sSL $(TM_URL)/crypto/keys.proto > $(TM_CRYPTO_TYPES)/keys.proto
|
||||
|
||||
|
||||
|
||||
.PHONY: proto-all proto-gen proto-gen-any proto-swagger-gen proto-format proto-lint proto-check-breaking proto-update-deps
|
||||
|
||||
###############################################################################
|
||||
### Localnet ###
|
||||
@ -459,13 +512,13 @@ ifeq ($(OS),Windows_NT)
|
||||
mkdir localnet-setup &
|
||||
@$(MAKE) localnet-build
|
||||
|
||||
IF not exist "build/node0/$(LACONIC_BINARY)/config/genesis.json" docker run --rm -v $(CURDIR)/build\laconicd\Z laconicd/node "./laconicd testnet --v 4 -o /laconicd --keyring-backend=test --ip-addresses laconicdnode0,laconicdnode1,laconicdnode2,laconicdnode3"
|
||||
IF not exist "build/node0/$(ETHERMINT_BINARY)/config/genesis.json" docker run --rm -v $(CURDIR)/build\ethermint\Z ethermintd/node "./ethermintd testnet --v 4 -o /ethermint --keyring-backend=test --ip-addresses ethermintdnode0,ethermintdnode1,ethermintdnode2,ethermintdnode3"
|
||||
docker-compose up -d
|
||||
else
|
||||
mkdir -p localnet-setup
|
||||
@$(MAKE) localnet-build
|
||||
|
||||
if ! [ -f localnet-setup/node0/$(LACONIC_BINARY)/config/genesis.json ]; then docker run --rm -v $(CURDIR)/localnet-setup:/localnet-setup:Z laconicd/node "./laconicd testnet --v 4 -o /laconicd --keyring-backend=test --ip-addresses laconicdnode0,laconicdnode1,laconicdnode2,laconicdnode3"; fi
|
||||
if ! [ -f localnet-setup/node0/$(ETHERMINT_BINARY)/config/genesis.json ]; then docker run --rm -v $(CURDIR)/localnet-setup:/ethermint:Z ethermintd/node "./ethermintd testnet --v 4 -o /ethermint --keyring-backend=test --ip-addresses ethermintdnode0,ethermintdnode1,ethermintdnode2,ethermintdnode3"; fi
|
||||
docker-compose up -d
|
||||
endif
|
||||
|
||||
@ -482,19 +535,56 @@ localnet-clean:
|
||||
localnet-unsafe-reset:
|
||||
docker-compose down
|
||||
ifeq ($(OS),Windows_NT)
|
||||
@docker run --rm -v $(CURDIR)\localnet-setup\node1\laconicd:laconic\Z laconicd/node "laconicd unsafe-reset-all --home=/laconic"
|
||||
@docker run --rm -v $(CURDIR)\localnet-setup\node0\laconicd:laconic\Z laconicd/node "laconicd unsafe-reset-all --home=/laconic"
|
||||
@docker run --rm -v $(CURDIR)\localnet-setup\node2\laconicd:laconic\Z laconicd/node "laconicd unsafe-reset-all --home=/laconic"
|
||||
@docker run --rm -v $(CURDIR)\localnet-setup\node3\laconicd:laconic\Z laconicd/node "laconicd unsafe-reset-all --home=/laconic"
|
||||
@docker run --rm -v $(CURDIR)\localnet-setup\node0\ethermitd:ethermint\Z ethermintd/node "./ethermintd unsafe-reset-all --home=/ethermint"
|
||||
@docker run --rm -v $(CURDIR)\localnet-setup\node1\ethermitd:ethermint\Z ethermintd/node "./ethermintd unsafe-reset-all --home=/ethermint"
|
||||
@docker run --rm -v $(CURDIR)\localnet-setup\node2\ethermitd:ethermint\Z ethermintd/node "./ethermintd unsafe-reset-all --home=/ethermint"
|
||||
@docker run --rm -v $(CURDIR)\localnet-setup\node3\ethermitd:ethermint\Z ethermintd/node "./ethermintd unsafe-reset-all --home=/ethermint"
|
||||
else
|
||||
@docker run --rm -v $(CURDIR)/localnet-setup/node0/laconicd:/laconic:Z laconicd/node "laconicd unsafe-reset-all --home=/laconic"
|
||||
@docker run --rm -v $(CURDIR)/localnet-setup/node1/laconicd:/laconic:Z laconicd/node "laconicd unsafe-reset-all --home=/laconic"
|
||||
@docker run --rm -v $(CURDIR)/localnet-setup/node2/laconicd:/laconic:Z laconicd/node "laconicd unsafe-reset-all --home=/laconic"
|
||||
@docker run --rm -v $(CURDIR)/localnet-setup/node3/laconicd:/laconic:Z laconicd/node "laconicd unsafe-reset-all --home=/laconic"
|
||||
@docker run --rm -v $(CURDIR)/localnet-setup/node0/ethermitd:/ethermint:Z ethermintd/node "./ethermintd unsafe-reset-all --home=/ethermint"
|
||||
@docker run --rm -v $(CURDIR)/localnet-setup/node1/ethermitd:/ethermint:Z ethermintd/node "./ethermintd unsafe-reset-all --home=/ethermint"
|
||||
@docker run --rm -v $(CURDIR)/localnet-setup/node2/ethermitd:/ethermint:Z ethermintd/node "./ethermintd unsafe-reset-all --home=/ethermint"
|
||||
@docker run --rm -v $(CURDIR)/localnet-setup/node3/ethermitd:/ethermint:Z ethermintd/node "./ethermintd unsafe-reset-all --home=/ethermint"
|
||||
endif
|
||||
|
||||
# Clean testnet
|
||||
localnet-show-logstream:
|
||||
docker-compose logs --tail=1000 -f
|
||||
|
||||
.PHONY: build-docker-local-laconic localnet-start localnet-stop
|
||||
.PHONY: build-docker-local-ethermint localnet-start localnet-stop
|
||||
|
||||
###############################################################################
|
||||
### Releasing ###
|
||||
###############################################################################
|
||||
|
||||
PACKAGE_NAME:=github.com/tharsis/ethermint
|
||||
GOLANG_CROSS_VERSION = v1.17
|
||||
release-dry-run:
|
||||
docker run \
|
||||
--rm \
|
||||
--privileged \
|
||||
-e CGO_ENABLED=1 \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v `pwd`:/go/src/$(PACKAGE_NAME) \
|
||||
-v ${GOPATH}/pkg:/go/pkg \
|
||||
-w /go/src/$(PACKAGE_NAME) \
|
||||
troian/golang-cross:${GOLANG_CROSS_VERSION} \
|
||||
--rm-dist --skip-validate --skip-publish
|
||||
|
||||
release:
|
||||
@if [ ! -f ".release-env" ]; then \
|
||||
echo "\033[91m.release-env is required for release\033[0m";\
|
||||
exit 1;\
|
||||
fi
|
||||
docker run \
|
||||
--rm \
|
||||
--privileged \
|
||||
-e CGO_ENABLED=1 \
|
||||
--env-file .release-env \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v `pwd`:/go/src/$(PACKAGE_NAME) \
|
||||
-w /go/src/$(PACKAGE_NAME) \
|
||||
troian/golang-cross:${GOLANG_CROSS_VERSION} \
|
||||
release --rm-dist --skip-validate
|
||||
|
||||
.PHONY: release-dry-run release
|
||||
|
||||
|
73
README.md
73
README.md
@ -1,38 +1,85 @@
|
||||
<!--
|
||||
parent:
|
||||
order: false
|
||||
-->
|
||||
|
||||
<div align="center">
|
||||
<h1> Laconic Network </h1>
|
||||
<h1> Ethermint </h1>
|
||||
</div>
|
||||
|
||||

|
||||

|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/tharsis/ethermint/releases/latest">
|
||||
<img alt="Version" src="https://img.shields.io/github/tag/tharsis/ethermint.svg" />
|
||||
</a>
|
||||
<a href="https://github.com/tharsis/ethermint/blob/main/LICENSE">
|
||||
<img alt="License: Apache-2.0" src="https://img.shields.io/github/license/tharsis/ethermint.svg" />
|
||||
</a>
|
||||
<a href="https://pkg.go.dev/github.com/tharsis/ethermint">
|
||||
<img alt="GoDoc" src="https://godoc.org/github.com/tharsis/ethermint?status.svg" />
|
||||
</a>
|
||||
<a href="https://goreportcard.com/report/github.com/tharsis/ethermint">
|
||||
<img alt="Go report card" src="https://goreportcard.com/badge/github.com/tharsis/ethermint"/>
|
||||
</a>
|
||||
<a href="https://bestpractices.coreinfrastructure.org/projects/5018">
|
||||
<img alt="Lines of code" src="https://img.shields.io/tokei/lines/github/tharsis/ethermint">
|
||||
</a>
|
||||
</div>
|
||||
<div align="center">
|
||||
<a href="https://discord.gg/trje9XuAmy">
|
||||
<img alt="Discord" src="https://img.shields.io/discord/809048090249134080.svg" />
|
||||
</a>
|
||||
<!-- <a href="https://github.com/tharsis/ethermint/actions?query=branch%3Amain+workflow%3ABuild">
|
||||
<img alt="Build Status" src="https://github.com/tharsis/ethermint/actions/workflows/build.yml/badge.svg?branch=main" />
|
||||
</a> -->
|
||||
<a href="https://github.com/tharsis/ethermint/actions?query=branch%3Amain+workflow%3ALint">
|
||||
<img alt="Lint Status" src="https://github.com/tharsis/ethermint/actions/workflows/lint.yml/badge.svg?branch=main" />
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/tharsis/ethermint">
|
||||
<img alt="Code Coverage" src="https://codecov.io/gh/tharsis/ethermint/branch/main/graph/badge.svg" />
|
||||
</a>
|
||||
<a href="https://twitter.com/ethermint">
|
||||
<img alt="Twitter Follow Ethermint" src="https://img.shields.io/twitter/follow/ethermint"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
The Source of Proof. Laconic is a next generation data availability & verifiability layer with cryptographic proofs, powering internet-scale Web3 applications, built on Proof-of-Stake with fast-finality using the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/) which runs on top of [Tendermint Core](https://github.com/tendermint/tendermint) consensus engine.
|
||||
Ethermint is a scalable, high-throughput Proof-of-Stake blockchain that is fully compatible and
|
||||
interoperable with Ethereum. It's build using the the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/) which runs on top of [Tendermint Core](https://github.com/tendermint/tendermint) consensus engine.
|
||||
|
||||
**Note**: Requires [Go 1.19+](https://golang.org/dl/)
|
||||
**Note**: Requires [Go 1.17+](https://golang.org/dl/)
|
||||
|
||||
## Installation
|
||||
|
||||
For prerequisites and detailed build instructions please read the [Installation](https://ethermint.dev/quickstart/installation.html) instructions. Once the dependencies are installed, run:
|
||||
|
||||
```bash
|
||||
make install
|
||||
```
|
||||
|
||||
## Usage
|
||||
Or check out the latest [release](https://github.com/tharsis/ethermint/releases).
|
||||
|
||||
To quickly get started with a single node fixture, run:
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
./init.sh
|
||||
```
|
||||
To learn how the Ethermint works from a high-level perspective, go to the [Introduction](https://ethermint.dev/intro/overview.html) section from the documentation. You can also check the instructions to [Run a Node](https://ethermint.dev/quickstart/run_node.html).
|
||||
|
||||
For more, please refer to the [Ethermint Docs](./docs/), which are also hosted on [ethermint.dev](https://ethermint.dev/).
|
||||
|
||||
## Community
|
||||
|
||||
The following chat channels and forums are a great spot to ask questions about Ethermint:
|
||||
|
||||
- [Laconic Twitter](https://twitter.com/laconicnetwork)
|
||||
- [Discord](https://discord.com/invite/ukhbBemyxY)
|
||||
- [Website](https://laconic.com)
|
||||
- [Ethermint Twitter](https://twitter.com/ethermint)
|
||||
- [Tharsis Twitter](https://twitter.com/ethermint)
|
||||
- [Ethermint Discord](https://discord.gg/trje9XuAmy)
|
||||
- [Ethermint Forum](https://forum.cosmos.network/c/ethermint)
|
||||
|
||||
## Contributing
|
||||
|
||||
Looking for a good place to start contributing? Check out some [`good first issues`](https://github.com/cerc-io/laconicd/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22).
|
||||
Looking for a good place to start contributing? Check out some [`good first issues`](https://github.com/tharsis/ethermint/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22).
|
||||
|
||||
For additional instructions, standards and style guides, please refer to the [Contributing](./CONTRIBUTING.md) document.
|
||||
|
||||
## Careers
|
||||
|
||||
See our open positions on [Cosmos Jobs](https://jobs.cosmos.network/project/ethermint-d0sk1uxuh-remote/), [Notion](https://tharsis.notion.site/Jobs-at-Tharsis-5a1642eb89b34747ae6f2db2d356fc0d), or feel free to [reach out](mailto:careers@thars.is) via email.
|
||||
|
127
app/ante/ante.go
127
app/ante/ante.go
@ -4,17 +4,22 @@ import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/palantir/stacktrace"
|
||||
|
||||
tmlog "github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
authante "github.com/tharsis/ethermint/x/auth/ante"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||
channelkeeper "github.com/cosmos/ibc-go/modules/core/04-channel/keeper"
|
||||
ibcante "github.com/cosmos/ibc-go/modules/core/ante"
|
||||
|
||||
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
|
||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -25,11 +30,14 @@ const (
|
||||
// Ethereum or SDK transaction to an internal ante handler for performing
|
||||
// transaction-level processing (e.g. fee payment, signature verification) before
|
||||
// being passed onto it's respective handler.
|
||||
func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
||||
if err := options.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func NewAnteHandler(
|
||||
ak evmtypes.AccountKeeper,
|
||||
bankKeeper evmtypes.BankKeeper,
|
||||
evmKeeper EVMKeeper,
|
||||
feeGrantKeeper authante.FeegrantKeeper,
|
||||
channelKeeper channelkeeper.Keeper,
|
||||
signModeHandler authsigning.SignModeHandler,
|
||||
) sdk.AnteHandler {
|
||||
return func(
|
||||
ctx sdk.Context, tx sdk.Tx, sim bool,
|
||||
) (newCtx sdk.Context, err error) {
|
||||
@ -44,17 +52,25 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
||||
switch typeURL := opts[0].GetTypeUrl(); typeURL {
|
||||
case "/ethermint.evm.v1.ExtensionOptionsEthereumTx":
|
||||
// handle as *evmtypes.MsgEthereumTx
|
||||
anteHandler = newEthAnteHandler(options)
|
||||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
||||
// Deprecated: Handle as normal Cosmos SDK tx, except signature is checked for Legacy EIP712 representation
|
||||
anteHandler = NewLegacyCosmosAnteHandlerEip712(options)
|
||||
case "/ethermint.types.v1.ExtensionOptionDynamicFeeTx":
|
||||
// cosmos-sdk tx with dynamic fee extension
|
||||
anteHandler = newCosmosAnteHandler(options)
|
||||
|
||||
anteHandler = sdk.ChainAnteDecorators(
|
||||
NewEthSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
|
||||
authante.NewMempoolFeeDecorator(),
|
||||
authante.NewTxTimeoutHeightDecorator(),
|
||||
authante.NewValidateMemoDecorator(ak),
|
||||
NewEthValidateBasicDecorator(),
|
||||
NewEthSigVerificationDecorator(evmKeeper),
|
||||
NewEthAccountVerificationDecorator(ak, bankKeeper, evmKeeper),
|
||||
NewEthNonceVerificationDecorator(ak),
|
||||
NewEthGasConsumeDecorator(ak, bankKeeper, evmKeeper),
|
||||
NewCanTransferDecorator(evmKeeper),
|
||||
NewEthIncrementSenderSequenceDecorator(ak), // innermost AnteDecorator.
|
||||
)
|
||||
|
||||
default:
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrUnknownExtensionOptions,
|
||||
"rejecting tx with unsupported extension option: %s", typeURL,
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, typeURL),
|
||||
"rejecting tx with unsupported extension option",
|
||||
)
|
||||
}
|
||||
|
||||
@ -63,20 +79,39 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
||||
}
|
||||
|
||||
// handle as totally normal Cosmos SDK tx
|
||||
|
||||
switch tx.(type) {
|
||||
case sdk.Tx:
|
||||
anteHandler = newCosmosAnteHandler(options)
|
||||
anteHandler = sdk.ChainAnteDecorators(
|
||||
authante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
|
||||
authante.NewRejectExtensionOptionsDecorator(),
|
||||
authante.NewMempoolFeeDecorator(),
|
||||
authante.NewValidateBasicDecorator(),
|
||||
authante.NewTxTimeoutHeightDecorator(),
|
||||
authante.NewValidateMemoDecorator(ak),
|
||||
ibcante.NewAnteDecorator(channelKeeper),
|
||||
authante.NewConsumeGasForTxSizeDecorator(ak),
|
||||
authante.NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators
|
||||
authante.NewValidateSigCountDecorator(ak),
|
||||
authante.NewDeductFeeDecorator(ak, bankKeeper, feeGrantKeeper),
|
||||
authante.NewSigGasConsumeDecorator(ak, DefaultSigVerificationGasConsumer),
|
||||
authante.NewSigVerificationDecorator(ak, signModeHandler),
|
||||
authante.NewIncrementSequenceDecorator(ak), // innermost AnteDecorator
|
||||
)
|
||||
default:
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid transaction type: %T", tx)
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx),
|
||||
"transaction is not an SDK tx",
|
||||
)
|
||||
}
|
||||
|
||||
return anteHandler(ctx, tx, sim)
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func Recover(logger tmlog.Logger, err *error) {
|
||||
if r := recover(); r != nil {
|
||||
*err = errorsmod.Wrapf(errortypes.ErrPanic, "%v", r)
|
||||
*err = sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r)
|
||||
|
||||
if e, ok := r.(error); ok {
|
||||
logger.Error(
|
||||
@ -101,48 +136,12 @@ var _ authante.SignatureVerificationGasConsumer = DefaultSigVerificationGasConsu
|
||||
func DefaultSigVerificationGasConsumer(
|
||||
meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params,
|
||||
) error {
|
||||
pubkey := sig.PubKey
|
||||
switch pubkey := pubkey.(type) {
|
||||
case *ethsecp256k1.PubKey:
|
||||
// support for ethereum ECDSA secp256k1 keys
|
||||
_, ok := sig.PubKey.(*ethsecp256k1.PubKey)
|
||||
if ok {
|
||||
meter.ConsumeGas(secp256k1VerifyCost, "ante verify: eth_secp256k1")
|
||||
return nil
|
||||
|
||||
case multisig.PubKey:
|
||||
// Multisig keys
|
||||
multisignature, ok := sig.Data.(*signing.MultiSignatureData)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected %T, got, %T", &signing.MultiSignatureData{}, sig.Data)
|
||||
}
|
||||
return ConsumeMultisignatureVerificationGas(meter, multisignature, pubkey, params, sig.Sequence)
|
||||
|
||||
default:
|
||||
return authante.DefaultSigVerificationGasConsumer(meter, sig, params)
|
||||
}
|
||||
}
|
||||
|
||||
// ConsumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature
|
||||
func ConsumeMultisignatureVerificationGas(
|
||||
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
|
||||
params authtypes.Params, accSeq uint64,
|
||||
) error {
|
||||
size := sig.BitArray.Count()
|
||||
sigIndex := 0
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
if !sig.BitArray.GetIndex(i) {
|
||||
continue
|
||||
}
|
||||
sigV2 := signing.SignatureV2{
|
||||
PubKey: pubkey.GetPubKeys()[i],
|
||||
Data: sig.Signatures[sigIndex],
|
||||
Sequence: accSeq,
|
||||
}
|
||||
err := DefaultSigVerificationGasConsumer(meter, sigV2, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sigIndex++
|
||||
}
|
||||
|
||||
return nil
|
||||
return authante.DefaultSigVerificationGasConsumer(meter, sig, params)
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
/*
|
||||
Package ante defines the SDK auth module's AnteHandler as well as an internal
|
||||
/*Package ante defines the SDK auth module's AnteHandler as well as an internal
|
||||
AnteHandler for an Ethereum transaction (i.e MsgEthereumTx).
|
||||
|
||||
During CheckTx, the transaction is passed through a series of
|
||||
|
@ -1,305 +0,0 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
ibcante "github.com/cosmos/ibc-go/v5/modules/core/ante"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||
"github.com/cerc-io/laconicd/ethereum/eip712"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||
)
|
||||
|
||||
var ethermintCodec codec.ProtoCodecMarshaler
|
||||
|
||||
func init() {
|
||||
registry := codectypes.NewInterfaceRegistry()
|
||||
ethermint.RegisterInterfaces(registry)
|
||||
ethermintCodec = codec.NewProtoCodec(registry)
|
||||
}
|
||||
|
||||
// Deprecated: NewLegacyCosmosAnteHandlerEip712 creates an AnteHandler to process legacy EIP-712
|
||||
// transactions, as defined by the presence of an ExtensionOptionsWeb3Tx extension.
|
||||
func NewLegacyCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler {
|
||||
return sdk.ChainAnteDecorators(
|
||||
RejectMessagesDecorator{}, // reject MsgEthereumTxs
|
||||
authante.NewSetUpContextDecorator(),
|
||||
authante.NewValidateBasicDecorator(),
|
||||
authante.NewTxTimeoutHeightDecorator(),
|
||||
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
|
||||
authante.NewValidateMemoDecorator(options.AccountKeeper),
|
||||
authante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
|
||||
authante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
|
||||
// SetPubKeyDecorator must be called before all signature verification decorators
|
||||
authante.NewSetPubKeyDecorator(options.AccountKeeper),
|
||||
authante.NewValidateSigCountDecorator(options.AccountKeeper),
|
||||
authante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer),
|
||||
// Note: signature verification uses EIP instead of the cosmos signature validator
|
||||
NewLegacyEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
|
||||
authante.NewIncrementSequenceDecorator(options.AccountKeeper),
|
||||
ibcante.NewRedundantRelayDecorator(options.IBCKeeper),
|
||||
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
|
||||
)
|
||||
}
|
||||
|
||||
// Deprecated: LegacyEip712SigVerificationDecorator Verify all signatures for a tx and return an error if any are invalid. Note,
|
||||
// the LegacyEip712SigVerificationDecorator decorator will not get executed on ReCheck.
|
||||
// NOTE: As of v0.20.0, EIP-712 signature verification is handled by the ethsecp256k1 public key (see ethsecp256k1.go)
|
||||
//
|
||||
// CONTRACT: Pubkeys are set in context for all signers before this decorator runs
|
||||
// CONTRACT: Tx must implement SigVerifiableTx interface
|
||||
type LegacyEip712SigVerificationDecorator struct {
|
||||
ak evmtypes.AccountKeeper
|
||||
signModeHandler authsigning.SignModeHandler
|
||||
}
|
||||
|
||||
// Deprecated: NewLegacyEip712SigVerificationDecorator creates a new LegacyEip712SigVerificationDecorator
|
||||
func NewLegacyEip712SigVerificationDecorator(
|
||||
ak evmtypes.AccountKeeper,
|
||||
signModeHandler authsigning.SignModeHandler,
|
||||
) LegacyEip712SigVerificationDecorator {
|
||||
return LegacyEip712SigVerificationDecorator{
|
||||
ak: ak,
|
||||
signModeHandler: signModeHandler,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle handles validation of EIP712 signed cosmos txs.
|
||||
// it is not run on RecheckTx
|
||||
func (svd LegacyEip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
|
||||
tx sdk.Tx,
|
||||
simulate bool,
|
||||
next sdk.AnteHandler,
|
||||
) (newCtx sdk.Context, err error) {
|
||||
// no need to verify signatures on recheck tx
|
||||
if ctx.IsReCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
sigTx, ok := tx.(authsigning.SigVerifiableTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "tx %T doesn't implement authsigning.SigVerifiableTx", tx)
|
||||
}
|
||||
|
||||
authSignTx, ok := tx.(authsigning.Tx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "tx %T doesn't implement the authsigning.Tx interface", tx)
|
||||
}
|
||||
|
||||
// stdSigs contains the sequence number, account number, and signatures.
|
||||
// When simulating, this would just be a 0-length slice.
|
||||
sigs, err := sigTx.GetSignaturesV2()
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
signerAddrs := sigTx.GetSigners()
|
||||
|
||||
// EIP712 allows just one signature
|
||||
if len(sigs) != 1 {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrTooManySignatures,
|
||||
"invalid number of signers (%d); EIP712 signatures allows just one signature",
|
||||
len(sigs),
|
||||
)
|
||||
}
|
||||
|
||||
// check that signer length and signature length are the same
|
||||
if len(sigs) != len(signerAddrs) {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrorInvalidSigner, "invalid number of signers; expected: %d, got %d", len(signerAddrs), len(sigs))
|
||||
}
|
||||
|
||||
// EIP712 has just one signature, avoid looping here and only read index 0
|
||||
i := 0
|
||||
sig := sigs[i]
|
||||
|
||||
acc, err := authante.GetSignerAcc(ctx, svd.ak, signerAddrs[i])
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
// retrieve pubkey
|
||||
pubKey := acc.GetPubKey()
|
||||
if !simulate && pubKey == nil {
|
||||
return ctx, errorsmod.Wrap(errortypes.ErrInvalidPubKey, "pubkey on account is not set")
|
||||
}
|
||||
|
||||
// Check account sequence number.
|
||||
if sig.Sequence != acc.GetSequence() {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrWrongSequence,
|
||||
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
|
||||
)
|
||||
}
|
||||
|
||||
// retrieve signer data
|
||||
genesis := ctx.BlockHeight() == 0
|
||||
chainID := ctx.ChainID()
|
||||
|
||||
var accNum uint64
|
||||
if !genesis {
|
||||
accNum = acc.GetAccountNumber()
|
||||
}
|
||||
|
||||
signerData := authsigning.SignerData{
|
||||
ChainID: chainID,
|
||||
AccountNumber: accNum,
|
||||
Sequence: acc.GetSequence(),
|
||||
}
|
||||
|
||||
if simulate {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
if err := VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, authSignTx); err != nil {
|
||||
errMsg := fmt.Errorf("signature verification failed; please verify account number (%d) and chain-id (%s): %w", accNum, chainID, err)
|
||||
return ctx, errorsmod.Wrap(errortypes.ErrUnauthorized, errMsg.Error())
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// VerifySignature verifies a transaction signature contained in SignatureData abstracting over different signing modes
|
||||
// and single vs multi-signatures.
|
||||
func VerifySignature(
|
||||
pubKey cryptotypes.PubKey,
|
||||
signerData authsigning.SignerData,
|
||||
sigData signing.SignatureData,
|
||||
_ authsigning.SignModeHandler,
|
||||
tx authsigning.Tx,
|
||||
) error {
|
||||
switch data := sigData.(type) {
|
||||
case *signing.SingleSignatureData:
|
||||
if data.SignMode != signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON {
|
||||
return errorsmod.Wrapf(errortypes.ErrNotSupported, "unexpected SignatureData %T: wrong SignMode", sigData)
|
||||
}
|
||||
|
||||
// Note: this prevents the user from sending trash data in the signature field
|
||||
if len(data.Signature) != 0 {
|
||||
return errorsmod.Wrap(errortypes.ErrTooManySignatures, "invalid signature value; EIP712 must have the cosmos transaction signature empty")
|
||||
}
|
||||
|
||||
// @contract: this code is reached only when Msg has Web3Tx extension (so this custom Ante handler flow),
|
||||
// and the signature is SIGN_MODE_LEGACY_AMINO_JSON which is supported for EIP712 for now
|
||||
|
||||
msgs := tx.GetMsgs()
|
||||
if len(msgs) == 0 {
|
||||
return errorsmod.Wrap(errortypes.ErrNoSignatures, "tx doesn't contain any msgs to verify signature")
|
||||
}
|
||||
|
||||
txBytes := legacytx.StdSignBytes(
|
||||
signerData.ChainID,
|
||||
signerData.AccountNumber,
|
||||
signerData.Sequence,
|
||||
tx.GetTimeoutHeight(),
|
||||
legacytx.StdFee{
|
||||
Amount: tx.GetFee(),
|
||||
Gas: tx.GetGas(),
|
||||
},
|
||||
msgs, tx.GetMemo(), tx.GetTip(),
|
||||
)
|
||||
|
||||
signerChainID, err := ethermint.ParseChainID(signerData.ChainID)
|
||||
if err != nil {
|
||||
return errorsmod.Wrapf(err, "failed to parse chain-id: %s", signerData.ChainID)
|
||||
}
|
||||
|
||||
txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx)
|
||||
if !ok {
|
||||
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "tx doesnt contain any extensions")
|
||||
}
|
||||
opts := txWithExtensions.GetExtensionOptions()
|
||||
if len(opts) != 1 {
|
||||
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "tx doesnt contain expected amount of extension options")
|
||||
}
|
||||
|
||||
extOpt, ok := opts[0].GetCachedValue().(*ethermint.ExtensionOptionsWeb3Tx)
|
||||
if !ok {
|
||||
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "unknown extension option")
|
||||
}
|
||||
|
||||
if extOpt.TypedDataChainID != signerChainID.Uint64() {
|
||||
return errorsmod.Wrap(errortypes.ErrInvalidChainID, "invalid chain-id")
|
||||
}
|
||||
|
||||
if len(extOpt.FeePayer) == 0 {
|
||||
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "no feePayer on ExtensionOptionsWeb3Tx")
|
||||
}
|
||||
feePayer, err := sdk.AccAddressFromBech32(extOpt.FeePayer)
|
||||
if err != nil {
|
||||
return errorsmod.Wrap(err, "failed to parse feePayer from ExtensionOptionsWeb3Tx")
|
||||
}
|
||||
|
||||
feeDelegation := &eip712.FeeDelegationOptions{
|
||||
FeePayer: feePayer,
|
||||
}
|
||||
|
||||
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
|
||||
if err != nil {
|
||||
return errorsmod.Wrap(err, "failed to create EIP-712 typed data from tx")
|
||||
}
|
||||
|
||||
sigHash, _, err := apitypes.TypedDataAndHash(typedData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
feePayerSig := extOpt.FeePayerSig
|
||||
if len(feePayerSig) != ethcrypto.SignatureLength {
|
||||
return errorsmod.Wrap(errortypes.ErrorInvalidSigner, "signature length doesn't match typical [R||S||V] signature 65 bytes")
|
||||
}
|
||||
|
||||
// Remove the recovery offset if needed (ie. Metamask eip712 signature)
|
||||
if feePayerSig[ethcrypto.RecoveryIDOffset] == 27 || feePayerSig[ethcrypto.RecoveryIDOffset] == 28 {
|
||||
feePayerSig[ethcrypto.RecoveryIDOffset] -= 27
|
||||
}
|
||||
|
||||
feePayerPubkey, err := secp256k1.RecoverPubkey(sigHash, feePayerSig)
|
||||
if err != nil {
|
||||
return errorsmod.Wrap(err, "failed to recover delegated fee payer from sig")
|
||||
}
|
||||
|
||||
ecPubKey, err := ethcrypto.UnmarshalPubkey(feePayerPubkey)
|
||||
if err != nil {
|
||||
return errorsmod.Wrap(err, "failed to unmarshal recovered fee payer pubkey")
|
||||
}
|
||||
|
||||
pk := ðsecp256k1.PubKey{
|
||||
Key: ethcrypto.CompressPubkey(ecPubKey),
|
||||
}
|
||||
|
||||
if !pubKey.Equals(pk) {
|
||||
return errorsmod.Wrapf(errortypes.ErrInvalidPubKey, "feePayer pubkey %s is different from transaction pubkey %s", pubKey, pk)
|
||||
}
|
||||
|
||||
recoveredFeePayerAcc := sdk.AccAddress(pk.Address().Bytes())
|
||||
|
||||
if !recoveredFeePayerAcc.Equals(feePayer) {
|
||||
return errorsmod.Wrapf(errortypes.ErrorInvalidSigner, "failed to verify delegated fee payer %s signature", recoveredFeePayerAcc)
|
||||
}
|
||||
|
||||
// VerifySignature of ethsecp256k1 accepts 64 byte signature [R||S]
|
||||
// WARNING! Under NO CIRCUMSTANCES try to use pubKey.VerifySignature there
|
||||
if !secp256k1.VerifySignature(pubKey.Bytes(), sigHash, feePayerSig[:len(feePayerSig)-1]) {
|
||||
return errorsmod.Wrap(errortypes.ErrorInvalidSigner, "unable to verify signer signature of EIP712 typed data")
|
||||
}
|
||||
|
||||
return nil
|
||||
default:
|
||||
return errorsmod.Wrapf(errortypes.ErrTooManySignatures, "unexpected SignatureData %T", sigData)
|
||||
}
|
||||
}
|
593
app/ante/eth.go
593
app/ante/eth.go
@ -1,121 +1,244 @@
|
||||
// Copyright 2021 Evmos Foundation
|
||||
// This file is part of Evmos' Ethermint library.
|
||||
//
|
||||
// The Ethermint library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The Ethermint library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE
|
||||
package ante
|
||||
|
||||
import (
|
||||
"math"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdkmath "cosmossdk.io/math"
|
||||
authante "github.com/tharsis/ethermint/x/auth/ante"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/palantir/stacktrace"
|
||||
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
"github.com/cerc-io/laconicd/x/evm/keeper"
|
||||
"github.com/cerc-io/laconicd/x/evm/statedb"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
ethermint "github.com/tharsis/ethermint/types"
|
||||
evmkeeper "github.com/tharsis/ethermint/x/evm/keeper"
|
||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// EthAccountVerificationDecorator validates an account balance checks
|
||||
type EthAccountVerificationDecorator struct {
|
||||
ak evmtypes.AccountKeeper
|
||||
// EVMKeeper defines the expected keeper interface used on the Eth AnteHandler
|
||||
type EVMKeeper interface {
|
||||
vm.StateDB
|
||||
|
||||
ChainID() *big.Int
|
||||
GetParams(ctx sdk.Context) evmtypes.Params
|
||||
WithContext(ctx sdk.Context)
|
||||
ResetRefundTransient(ctx sdk.Context)
|
||||
NewEVM(msg core.Message, config *params.ChainConfig, params evmtypes.Params, coinbase common.Address, tracer vm.EVMLogger) *vm.EVM
|
||||
GetCodeHash(addr common.Address) common.Hash
|
||||
}
|
||||
|
||||
// EthSigVerificationDecorator validates an ethereum signatures
|
||||
type EthSigVerificationDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewEthAccountVerificationDecorator creates a new EthAccountVerificationDecorator
|
||||
func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, ek EVMKeeper) EthAccountVerificationDecorator {
|
||||
return EthAccountVerificationDecorator{
|
||||
ak: ak,
|
||||
// NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator
|
||||
func NewEthSigVerificationDecorator(ek EVMKeeper) EthSigVerificationDecorator {
|
||||
return EthSigVerificationDecorator{
|
||||
evmKeeper: ek,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle validates checks that the registered chain id is the same as the one on the message, and
|
||||
// that the signer address matches the one defined on the message.
|
||||
// It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work.
|
||||
// Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user
|
||||
// won't see the error message.
|
||||
func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
if tx == nil || len(tx.GetMsgs()) != 1 {
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx"),
|
||||
"",
|
||||
)
|
||||
}
|
||||
|
||||
chainID := esvd.evmKeeper.ChainID()
|
||||
|
||||
params := esvd.evmKeeper.GetParams(ctx)
|
||||
|
||||
ethCfg := params.ChainConfig.EthereumConfig(chainID)
|
||||
blockNum := big.NewInt(ctx.BlockHeight())
|
||||
signer := ethtypes.MakeSigner(ethCfg, blockNum)
|
||||
|
||||
msg := tx.GetMsgs()[0]
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction",
|
||||
)
|
||||
}
|
||||
|
||||
sender, err := signer.Sender(msgEthTx.AsTransaction())
|
||||
if err != nil {
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, err.Error()),
|
||||
"couldn't retrieve sender address ('%s') from the ethereum transaction",
|
||||
msgEthTx.From,
|
||||
)
|
||||
}
|
||||
|
||||
// set up the sender to the transaction field if not already
|
||||
msgEthTx.From = sender.Hex()
|
||||
|
||||
return next(ctx, msgEthTx, simulate)
|
||||
}
|
||||
|
||||
// EthAccountVerificationDecorator validates an account balance checks
|
||||
type EthAccountVerificationDecorator struct {
|
||||
ak evmtypes.AccountKeeper
|
||||
bankKeeper evmtypes.BankKeeper
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewEthAccountVerificationDecorator creates a new EthAccountVerificationDecorator
|
||||
func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, bankKeeper evmtypes.BankKeeper, ek EVMKeeper) EthAccountVerificationDecorator {
|
||||
return EthAccountVerificationDecorator{
|
||||
ak: ak,
|
||||
bankKeeper: bankKeeper,
|
||||
evmKeeper: ek,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle validates checks that the sender balance is greater than the total transaction cost.
|
||||
// The account will be set to store if it doesn't exis, i.e cannot be found on store.
|
||||
// This AnteHandler decorator will fail if:
|
||||
// - any of the msgs is not a MsgEthereumTx
|
||||
// - from address is empty
|
||||
// - account balance is lower than the transaction cost
|
||||
func (avd EthAccountVerificationDecorator) AnteHandle(
|
||||
ctx sdk.Context,
|
||||
tx sdk.Tx,
|
||||
simulate bool,
|
||||
next sdk.AnteHandler,
|
||||
) (newCtx sdk.Context, err error) {
|
||||
func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
if !ctx.IsCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
avd.evmKeeper.WithContext(ctx)
|
||||
evmDenom := avd.evmKeeper.GetParams(ctx).EvmDenom
|
||||
|
||||
for i, msg := range tx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||
if err != nil {
|
||||
return ctx, stacktrace.Propagate(err, "failed to unpack tx data any for tx %d", i)
|
||||
}
|
||||
|
||||
// sender address should be in the tx cache from the previous AnteHandle call
|
||||
from := msgEthTx.GetFrom()
|
||||
if from.Empty() {
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "from address cannot be empty"),
|
||||
"sender address should have been in the tx field from the previous AnteHandle call",
|
||||
)
|
||||
}
|
||||
|
||||
// check whether the sender address is EOA
|
||||
fromAddr := common.BytesToAddress(from)
|
||||
codeHash := avd.evmKeeper.GetCodeHash(fromAddr)
|
||||
if codeHash != common.BytesToHash(evmtypes.EmptyCodeHash) {
|
||||
return ctx, stacktrace.Propagate(sdkerrors.Wrapf(sdkerrors.ErrInvalidType,
|
||||
"the sender is not EOA: address <%v>, codeHash <%s>", fromAddr, codeHash), "")
|
||||
}
|
||||
|
||||
acc := avd.ak.GetAccount(ctx, from)
|
||||
if acc == nil {
|
||||
acc = avd.ak.NewAccountWithAddress(ctx, from)
|
||||
avd.ak.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
if err := evmkeeper.CheckSenderBalance(ctx, avd.bankKeeper, from, txData, evmDenom); err != nil {
|
||||
return ctx, stacktrace.Propagate(err, "failed to check sender balance")
|
||||
}
|
||||
|
||||
}
|
||||
// recover the original gas meter
|
||||
avd.evmKeeper.WithContext(ctx)
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthNonceVerificationDecorator checks that the account nonce from the transaction matches
|
||||
// the sender account sequence.
|
||||
type EthNonceVerificationDecorator struct {
|
||||
ak evmtypes.AccountKeeper
|
||||
}
|
||||
|
||||
// NewEthNonceVerificationDecorator creates a new EthNonceVerificationDecorator
|
||||
func NewEthNonceVerificationDecorator(ak evmtypes.AccountKeeper) EthNonceVerificationDecorator {
|
||||
return EthNonceVerificationDecorator{
|
||||
ak: ak,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle validates that the transaction nonces are valid and equivalent to the sender account’s
|
||||
// current nonce.
|
||||
func (nvd EthNonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
// no need to check the nonce on ReCheckTx
|
||||
if ctx.IsReCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
for i, msg := range tx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
// sender address should be in the tx cache from the previous AnteHandle call
|
||||
seq, err := nvd.ak.GetSequence(ctx, msgEthTx.GetFrom())
|
||||
if err != nil {
|
||||
return ctx, stacktrace.Propagate(err, "sequence not found for address %s", msgEthTx.From)
|
||||
}
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||
if err != nil {
|
||||
return ctx, errorsmod.Wrapf(err, "failed to unpack tx data any for tx %d", i)
|
||||
return ctx, stacktrace.Propagate(err, "failed to unpack tx data")
|
||||
}
|
||||
|
||||
// sender address should be in the tx cache from the previous AnteHandle call
|
||||
from := msgEthTx.GetFrom()
|
||||
if from.Empty() {
|
||||
return ctx, errorsmod.Wrap(errortypes.ErrInvalidAddress, "from address cannot be empty")
|
||||
}
|
||||
|
||||
// check whether the sender address is EOA
|
||||
fromAddr := common.BytesToAddress(from)
|
||||
acct := avd.evmKeeper.GetAccount(ctx, fromAddr)
|
||||
|
||||
if acct == nil {
|
||||
acc := avd.ak.NewAccountWithAddress(ctx, from)
|
||||
avd.ak.SetAccount(ctx, acc)
|
||||
acct = statedb.NewEmptyAccount()
|
||||
} else if acct.IsContract() {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType,
|
||||
"the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash)
|
||||
}
|
||||
|
||||
if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil {
|
||||
return ctx, errorsmod.Wrap(err, "failed to check sender balance")
|
||||
// if multiple transactions are submitted in succession with increasing nonces,
|
||||
// all will be rejected except the first, since the first needs to be included in a block
|
||||
// before the sequence increments
|
||||
if txData.GetNonce() != seq {
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(
|
||||
sdkerrors.ErrInvalidSequence,
|
||||
"invalid nonce; got %d, expected %d", txData.GetNonce(), seq,
|
||||
),
|
||||
"",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthGasConsumeDecorator validates enough intrinsic gas for the transaction and
|
||||
// gas consumption.
|
||||
type EthGasConsumeDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
maxGasWanted uint64
|
||||
ak evmtypes.AccountKeeper
|
||||
bankKeeper evmtypes.BankKeeper
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewEthGasConsumeDecorator creates a new EthGasConsumeDecorator
|
||||
func NewEthGasConsumeDecorator(
|
||||
evmKeeper EVMKeeper,
|
||||
maxGasWanted uint64,
|
||||
) EthGasConsumeDecorator {
|
||||
func NewEthGasConsumeDecorator(ak evmtypes.AccountKeeper, bankKeeper evmtypes.BankKeeper, ek EVMKeeper) EthGasConsumeDecorator {
|
||||
return EthGasConsumeDecorator{
|
||||
evmKeeper,
|
||||
maxGasWanted,
|
||||
ak: ak,
|
||||
bankKeeper: bankKeeper,
|
||||
evmKeeper: ek,
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,122 +246,80 @@ func NewEthGasConsumeDecorator(
|
||||
// (during CheckTx only) and that the sender has enough balance to pay for the gas cost.
|
||||
//
|
||||
// Intrinsic gas for a transaction is the amount of gas that the transaction uses before the
|
||||
// transaction is executed. The gas is a constant value plus any cost incurred by additional bytes
|
||||
// transaction is executed. The gas is a constant value plus any cost inccured by additional bytes
|
||||
// of data supplied with the transaction.
|
||||
//
|
||||
// This AnteHandler decorator will fail if:
|
||||
// - the transaction contains more than one message
|
||||
// - the message is not a MsgEthereumTx
|
||||
// - sender account cannot be found
|
||||
// - transaction's gas limit is lower than the intrinsic gas
|
||||
// - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
|
||||
// - transaction or block gas meter runs out of gas
|
||||
// - sets the gas meter limit
|
||||
// - gas limit is greater than the block gas meter limit
|
||||
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
gasWanted := uint64(0)
|
||||
// gas consumption limit already checked during CheckTx so there's no need to
|
||||
// verify it again during ReCheckTx
|
||||
if ctx.IsReCheckTx() {
|
||||
// Use new context with gasWanted = 0
|
||||
// Otherwise, there's an error on txmempool.postCheck (tendermint)
|
||||
// that is not bubbled up. Thus, the Tx never runs on DeliverMode
|
||||
// Error: "gas wanted -1 is negative"
|
||||
// For more information, see issue #1554
|
||||
// https://github.com/cerc-io/laconicd/issues/1554
|
||||
newCtx := ctx.WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted))
|
||||
return next(newCtx, tx, simulate)
|
||||
}
|
||||
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
// reset the refund gas value in the keeper for the current transaction
|
||||
egcd.evmKeeper.ResetRefundTransient(ctx)
|
||||
|
||||
chainCfg := egcd.evmKeeper.GetChainConfig(ctx)
|
||||
ethCfg := chainCfg.EthereumConfig(egcd.evmKeeper.ChainID())
|
||||
params := egcd.evmKeeper.GetParams(ctx)
|
||||
|
||||
ethCfg := params.ChainConfig.EthereumConfig(egcd.evmKeeper.ChainID())
|
||||
|
||||
blockHeight := big.NewInt(ctx.BlockHeight())
|
||||
homestead := ethCfg.IsHomestead(blockHeight)
|
||||
istanbul := ethCfg.IsIstanbul(blockHeight)
|
||||
evmDenom := params.EvmDenom
|
||||
|
||||
var events sdk.Events
|
||||
|
||||
// Use the lowest priority of all the messages as the final one.
|
||||
minPriority := int64(math.MaxInt64)
|
||||
baseFee := egcd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
for i, msg := range tx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||
if err != nil {
|
||||
return ctx, errorsmod.Wrap(err, "failed to unpack tx data")
|
||||
return ctx, stacktrace.Propagate(err, "failed to unpack tx data")
|
||||
}
|
||||
|
||||
if ctx.IsCheckTx() && egcd.maxGasWanted != 0 {
|
||||
// We can't trust the tx gas limit, because we'll refund the unused gas.
|
||||
if txData.GetGas() > egcd.maxGasWanted {
|
||||
gasWanted += egcd.maxGasWanted
|
||||
} else {
|
||||
gasWanted += txData.GetGas()
|
||||
}
|
||||
} else {
|
||||
gasWanted += txData.GetGas()
|
||||
}
|
||||
|
||||
evmDenom := egcd.evmKeeper.GetEVMDenom(ctx)
|
||||
|
||||
fees, err := keeper.VerifyFee(txData, evmDenom, baseFee, homestead, istanbul, ctx.IsCheckTx())
|
||||
if err != nil {
|
||||
return ctx, errorsmod.Wrapf(err, "failed to verify the fees")
|
||||
}
|
||||
|
||||
err = egcd.evmKeeper.DeductTxCostsFromUserBalance(ctx, fees, common.HexToAddress(msgEthTx.From))
|
||||
if err != nil {
|
||||
return ctx, errorsmod.Wrapf(err, "failed to deduct transaction costs from user balance")
|
||||
}
|
||||
|
||||
events = append(events,
|
||||
sdk.NewEvent(
|
||||
sdk.EventTypeTx,
|
||||
sdk.NewAttribute(sdk.AttributeKeyFee, fees.String()),
|
||||
),
|
||||
fees, err := evmkeeper.DeductTxCostsFromUserBalance(
|
||||
ctx,
|
||||
egcd.bankKeeper,
|
||||
egcd.ak,
|
||||
*msgEthTx,
|
||||
txData,
|
||||
evmDenom,
|
||||
homestead,
|
||||
istanbul,
|
||||
)
|
||||
|
||||
priority := evmtypes.GetTxPriority(txData, baseFee)
|
||||
|
||||
if priority < minPriority {
|
||||
minPriority = priority
|
||||
if err != nil {
|
||||
return ctx, stacktrace.Propagate(err, "failed to deduct transaction costs from user balance")
|
||||
}
|
||||
|
||||
events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String())))
|
||||
}
|
||||
|
||||
// TODO: change to typed events
|
||||
ctx.EventManager().EmitEvents(events)
|
||||
|
||||
// TODO: deprecate after https://github.com/cosmos/cosmos-sdk/issues/9514 is fixed on SDK
|
||||
blockGasLimit := ethermint.BlockGasLimit(ctx)
|
||||
|
||||
// return error if the tx gas is greater than the block limit (max gas)
|
||||
|
||||
// NOTE: it's important here to use the gas wanted instead of the gas consumed
|
||||
// from the tx gas pool. The later only has the value so far since the
|
||||
// EthSetupContextDecorator so it will never exceed the block gas limit.
|
||||
if gasWanted > blockGasLimit {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrOutOfGas,
|
||||
"tx gas (%d) exceeds block gas limit (%d)",
|
||||
gasWanted,
|
||||
blockGasLimit,
|
||||
)
|
||||
// NOTE: safety check
|
||||
if blockGasLimit > 0 {
|
||||
// generate a copy of the gas pool (i.e block gas meter) to see if we've run out of gas for this block
|
||||
// if current gas consumed is greater than the limit, this funcion panics and the error is recovered on the Baseapp
|
||||
gasPool := sdk.NewGasMeter(blockGasLimit)
|
||||
gasPool.ConsumeGas(ctx.GasMeter().GasConsumedToLimit(), "gas pool check")
|
||||
}
|
||||
|
||||
// Set tx GasMeter with a limit of GasWanted (i.e gas limit from the Ethereum tx).
|
||||
// The gas consumed will be then reset to the gas used by the state transition
|
||||
// in the EVM.
|
||||
|
||||
// FIXME: use a custom gas configuration that doesn't add any additional gas and only
|
||||
// takes into account the gas consumed at the end of the EVM transaction.
|
||||
newCtx := ctx.
|
||||
WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted)).
|
||||
WithPriority(minPriority)
|
||||
|
||||
// we know that we have enough gas on the pool to cover the intrinsic gas
|
||||
return next(newCtx, tx, simulate)
|
||||
// set up the updated context to the evm Keeper
|
||||
egcd.evmKeeper.WithContext(ctx)
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// CanTransferDecorator checks if the sender is allowed to transfer funds according to the EVM block
|
||||
@ -257,65 +338,106 @@ func NewCanTransferDecorator(evmKeeper EVMKeeper) CanTransferDecorator {
|
||||
// AnteHandle creates an EVM from the message and calls the BlockContext CanTransfer function to
|
||||
// see if the address can execute the transaction.
|
||||
func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
ctd.evmKeeper.WithContext(ctx)
|
||||
|
||||
params := ctd.evmKeeper.GetParams(ctx)
|
||||
|
||||
ethCfg := params.ChainConfig.EthereumConfig(ctd.evmKeeper.ChainID())
|
||||
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight()))
|
||||
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
for i, msg := range tx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
baseFee := ctd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||
|
||||
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
|
||||
coreMsg, err := msgEthTx.AsMessage(signer)
|
||||
if err != nil {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
return ctx, stacktrace.Propagate(
|
||||
err,
|
||||
"failed to create an ethereum core.Message from signer %T", signer,
|
||||
)
|
||||
}
|
||||
|
||||
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) {
|
||||
if baseFee == nil {
|
||||
return ctx, errorsmod.Wrap(
|
||||
evmtypes.ErrInvalidBaseFee,
|
||||
"base fee is supported but evm block context value is nil",
|
||||
)
|
||||
}
|
||||
if coreMsg.GasFeeCap().Cmp(baseFee) < 0 {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrInsufficientFee,
|
||||
"max fee per gas less than block base fee (%s < %s)",
|
||||
coreMsg.GasFeeCap(), baseFee,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below
|
||||
cfg := &evmtypes.EVMConfig{
|
||||
ChainConfig: ethCfg,
|
||||
Params: params,
|
||||
CoinBase: common.Address{},
|
||||
BaseFee: baseFee,
|
||||
}
|
||||
|
||||
stateDB := statedb.New(ctx, ctd.evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())))
|
||||
evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB)
|
||||
evm := ctd.evmKeeper.NewEVM(coreMsg, ethCfg, params, common.Address{}, nil)
|
||||
|
||||
// check that caller has enough balance to cover asset transfer for **topmost** call
|
||||
// NOTE: here the gas consumed is from the context with the infinite gas meter
|
||||
if coreMsg.Value().Sign() > 0 && !evm.Context().CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrInsufficientFunds,
|
||||
"failed to transfer %s from address %s using the EVM block context transfer function",
|
||||
coreMsg.Value(),
|
||||
coreMsg.From(),
|
||||
if coreMsg.Value().Sign() > 0 && !evm.Context.CanTransfer(ctd.evmKeeper, coreMsg.From(), coreMsg.Value()) {
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "address %s", coreMsg.From()),
|
||||
"failed to transfer %s using the EVM block context transfer function", coreMsg.Value(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ctd.evmKeeper.WithContext(ctx)
|
||||
|
||||
// set the original gas meter
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// AccessListDecorator prepare an access list for the sender if Yolov3/Berlin/EIPs 2929 and 2930 are
|
||||
// applicable at the current block number.
|
||||
type AccessListDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewAccessListDecorator creates a new AccessListDecorator.
|
||||
func NewAccessListDecorator(evmKeeper EVMKeeper) AccessListDecorator {
|
||||
return AccessListDecorator{
|
||||
evmKeeper: evmKeeper,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle handles the preparatory steps for executing an EVM state transition with
|
||||
// regards to both EIP-2929 and EIP-2930:
|
||||
//
|
||||
// - Add sender to access list (2929)
|
||||
// - Add destination to access list (2929)
|
||||
// - Add precompiles to access list (2929)
|
||||
// - Add the contents of the optional tx access list (2930)
|
||||
//
|
||||
// The AnteHandler will only prepare the access list if Yolov3/Berlin/EIPs 2929 and 2930 are applicable at the current number.
|
||||
func (ald AccessListDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
params := ald.evmKeeper.GetParams(ctx)
|
||||
ethCfg := params.ChainConfig.EthereumConfig(ald.evmKeeper.ChainID())
|
||||
|
||||
rules := ethCfg.Rules(big.NewInt(ctx.BlockHeight()))
|
||||
|
||||
// we don't need to prepare the access list if the chain is not currently on the Berlin upgrade
|
||||
if !rules.IsBerlin {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// setup the keeper context before setting the access list
|
||||
ald.evmKeeper.WithContext(ctx)
|
||||
|
||||
for i, msg := range tx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
sender := common.BytesToAddress(msgEthTx.GetFrom())
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||
if err != nil {
|
||||
return ctx, stacktrace.Propagate(err, "failed to unpack tx data")
|
||||
}
|
||||
|
||||
ald.evmKeeper.PrepareAccessList(sender, txData.GetTo(), vm.ActivePrecompiles(rules), txData.GetAccessList())
|
||||
}
|
||||
|
||||
// set the original gas meter
|
||||
ald.evmKeeper.WithContext(ctx)
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
@ -335,42 +457,93 @@ func NewEthIncrementSenderSequenceDecorator(ak evmtypes.AccountKeeper) EthIncrem
|
||||
// contract creation, the nonce will be incremented during the transaction execution and not within
|
||||
// this AnteHandler decorator.
|
||||
func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
for i, msg := range tx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||
if err != nil {
|
||||
return ctx, errorsmod.Wrap(err, "failed to unpack tx data")
|
||||
return ctx, stacktrace.Propagate(err, "failed to unpack tx data")
|
||||
}
|
||||
|
||||
// increase sequence of sender
|
||||
acc := issd.ak.GetAccount(ctx, msgEthTx.GetFrom())
|
||||
if acc == nil {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrUnknownAddress,
|
||||
"account %s is nil", common.BytesToAddress(msgEthTx.GetFrom().Bytes()),
|
||||
)
|
||||
}
|
||||
nonce := acc.GetSequence()
|
||||
|
||||
// we merged the nonce verification to nonce increment, so when tx includes multiple messages
|
||||
// with same sender, they'll be accepted.
|
||||
if txData.GetNonce() != nonce {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrInvalidSequence,
|
||||
"invalid nonce; got %d, expected %d", txData.GetNonce(), nonce,
|
||||
)
|
||||
// NOTE: on contract creation, the nonce is incremented within the EVM Create function during tx execution
|
||||
// and not previous to the state transition ¯\_(ツ)_/¯
|
||||
if txData.GetTo() == nil {
|
||||
// contract creation, don't increment sequence on AnteHandler but on tx execution
|
||||
// continue to the next item
|
||||
continue
|
||||
}
|
||||
|
||||
if err := acc.SetSequence(nonce + 1); err != nil {
|
||||
return ctx, errorsmod.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1)
|
||||
}
|
||||
// increment sequence of all signers
|
||||
for _, addr := range msg.GetSigners() {
|
||||
acc := issd.ak.GetAccount(ctx, addr)
|
||||
|
||||
issd.ak.SetAccount(ctx, acc)
|
||||
if acc == nil {
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(
|
||||
sdkerrors.ErrUnknownAddress,
|
||||
"account %s (%s) is nil", common.BytesToAddress(addr.Bytes()), addr,
|
||||
),
|
||||
"signer account not found",
|
||||
)
|
||||
}
|
||||
|
||||
if err := acc.SetSequence(acc.GetSequence() + 1); err != nil {
|
||||
return ctx, stacktrace.Propagate(err, "failed to set sequence to %d", acc.GetSequence()+1)
|
||||
}
|
||||
|
||||
issd.ak.SetAccount(ctx, acc)
|
||||
}
|
||||
}
|
||||
|
||||
// set the original gas meter
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures
|
||||
type EthValidateBasicDecorator struct{}
|
||||
|
||||
// NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator
|
||||
func NewEthValidateBasicDecorator() EthValidateBasicDecorator {
|
||||
return EthValidateBasicDecorator{}
|
||||
}
|
||||
|
||||
// AnteHandle handles basic validation of tx
|
||||
func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
// no need to validate basic on recheck tx, call next antehandler
|
||||
if ctx.IsReCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
err := tx.ValidateBasic()
|
||||
// ErrNoSignatures is fine with eth tx
|
||||
if err != nil && !errors.Is(err, sdkerrors.ErrNoSignatures) {
|
||||
return ctx, stacktrace.Propagate(err, "tx basic validation failed")
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption
|
||||
// by setting the gas meter to infinite
|
||||
type EthSetupContextDecorator struct{}
|
||||
|
||||
func NewEthSetUpContextDecorator() EthSetupContextDecorator {
|
||||
return EthSetupContextDecorator{}
|
||||
}
|
||||
|
||||
func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
// all transactions must implement GasTx
|
||||
_, ok := tx.(authante.GasTx)
|
||||
if !ok {
|
||||
return newCtx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
|
||||
}
|
||||
|
||||
newCtx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
return next(newCtx, tx, simulate)
|
||||
}
|
||||
|
@ -1,33 +1,71 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
"github.com/cerc-io/laconicd/server/config"
|
||||
"github.com/cerc-io/laconicd/tests"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
"github.com/cerc-io/laconicd/x/evm/statedb"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
"github.com/tharsis/ethermint/app/ante"
|
||||
"github.com/tharsis/ethermint/tests"
|
||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
func nextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
|
||||
dec := ante.NewEthSigVerificationDecorator(suite.app.EvmKeeper)
|
||||
addr, privKey := tests.NewAddrKey()
|
||||
|
||||
signedTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil)
|
||||
signedTx.From = addr.Hex()
|
||||
err := signedTx.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
reCheckTx bool
|
||||
expPass bool
|
||||
}{
|
||||
{"ReCheckTx", nil, true, false},
|
||||
{"invalid transaction type", &invalidTx{}, false, false},
|
||||
{
|
||||
"invalid sender",
|
||||
evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &addr, big.NewInt(10), 1000, big.NewInt(1), nil, nil),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{"successful signature verification", signedTx, false, true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||
dec := ante.NewEthAccountVerificationDecorator(
|
||||
suite.app.AccountKeeper, suite.app.EvmKeeper,
|
||||
suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.EvmKeeper,
|
||||
)
|
||||
|
||||
addr := tests.GenerateAddress()
|
||||
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil)
|
||||
tx.From = addr.Hex()
|
||||
|
||||
var vmdb *statedb.StateDB
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
@ -39,7 +77,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||
{"invalid transaction type", &invalidTx{}, func() {}, true, false},
|
||||
{
|
||||
"sender not set to msg",
|
||||
evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
|
||||
evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil),
|
||||
func() {},
|
||||
true,
|
||||
false,
|
||||
@ -49,7 +87,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||
tx,
|
||||
func() {
|
||||
// set not as an EOA
|
||||
vmdb.SetCode(addr, []byte("1"))
|
||||
suite.app.EvmKeeper.SetCode(addr, []byte("1"))
|
||||
},
|
||||
true,
|
||||
false,
|
||||
@ -59,7 +97,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||
tx,
|
||||
func() {
|
||||
// reset back to EOA
|
||||
vmdb.SetCode(addr, nil)
|
||||
suite.app.EvmKeeper.SetCode(addr, nil)
|
||||
},
|
||||
true,
|
||||
false,
|
||||
@ -68,7 +106,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||
"success new account",
|
||||
tx,
|
||||
func() {
|
||||
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
|
||||
},
|
||||
true,
|
||||
true,
|
||||
@ -80,7 +118,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
|
||||
},
|
||||
true,
|
||||
true,
|
||||
@ -89,11 +127,8 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
vmdb = suite.StateDB()
|
||||
tc.malleate()
|
||||
suite.Require().NoError(vmdb.Commit())
|
||||
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, NextFn)
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, nextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
@ -105,12 +140,11 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
|
||||
suite.SetupTest()
|
||||
dec := ante.NewEthIncrementSenderSequenceDecorator(suite.app.AccountKeeper)
|
||||
dec := ante.NewEthNonceVerificationDecorator(suite.app.AccountKeeper)
|
||||
|
||||
addr := tests.GenerateAddress()
|
||||
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil)
|
||||
tx.From = addr.Hex()
|
||||
|
||||
testCases := []struct {
|
||||
@ -120,7 +154,7 @@ func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
|
||||
reCheckTx bool
|
||||
expPass bool
|
||||
}{
|
||||
{"ReCheckTx", &invalidTx{}, func() {}, true, false},
|
||||
{"ReCheckTx", nil, func() {}, true, true},
|
||||
{"invalid transaction type", &invalidTx{}, func() {}, false, false},
|
||||
{"sender account not found", tx, func() {}, false, false},
|
||||
{
|
||||
@ -149,7 +183,7 @@ func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate()
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, NextFn)
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
@ -161,158 +195,106 @@ func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
||||
dec := ante.NewEthGasConsumeDecorator(suite.app.EvmKeeper, config.DefaultMaxTxGasWanted)
|
||||
dec := ante.NewEthGasConsumeDecorator(
|
||||
suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.EvmKeeper,
|
||||
)
|
||||
|
||||
addr := tests.GenerateAddress()
|
||||
|
||||
txGasLimit := uint64(1000)
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), txGasLimit, big.NewInt(1), nil, nil, nil, nil)
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil)
|
||||
tx.From = addr.Hex()
|
||||
|
||||
ethCfg := suite.app.EvmKeeper.GetParams(suite.ctx).
|
||||
ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
|
||||
baseFee := suite.app.EvmKeeper.GetBaseFee(suite.ctx, ethCfg)
|
||||
suite.Require().Equal(int64(1000000000), baseFee.Int64())
|
||||
|
||||
gasPrice := new(big.Int).Add(baseFee, evmtypes.DefaultPriorityReduction.BigInt())
|
||||
|
||||
tx2GasLimit := uint64(1000000)
|
||||
tx2 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit, gasPrice, nil, nil, nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}})
|
||||
tx2 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000000, big.NewInt(1), nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}})
|
||||
tx2.From = addr.Hex()
|
||||
tx2Priority := int64(1)
|
||||
|
||||
tx3GasLimit := ethermint.BlockGasLimit(suite.ctx) + uint64(1)
|
||||
tx3 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx3GasLimit, gasPrice, nil, nil, nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}})
|
||||
|
||||
dynamicFeeTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit,
|
||||
nil, // gasPrice
|
||||
new(big.Int).Add(baseFee, big.NewInt(evmtypes.DefaultPriorityReduction.Int64()*2)), // gasFeeCap
|
||||
evmtypes.DefaultPriorityReduction.BigInt(), // gasTipCap
|
||||
nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}})
|
||||
dynamicFeeTx.From = addr.Hex()
|
||||
dynamicFeeTxPriority := int64(1)
|
||||
|
||||
var vmdb *statedb.StateDB
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
gasLimit uint64
|
||||
malleate func()
|
||||
expPass bool
|
||||
expPanic bool
|
||||
expPriority int64
|
||||
name string
|
||||
tx sdk.Tx
|
||||
malleate func()
|
||||
expPass bool
|
||||
expPanic bool
|
||||
}{
|
||||
{"invalid transaction type", &invalidTx{}, math.MaxUint64, func() {}, false, false, 0},
|
||||
{"invalid transaction type", &invalidTx{}, func() {}, false, false},
|
||||
{
|
||||
"sender not found",
|
||||
evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
|
||||
math.MaxUint64,
|
||||
evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil),
|
||||
func() {},
|
||||
false, false,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"gas limit too low",
|
||||
tx,
|
||||
math.MaxUint64,
|
||||
func() {},
|
||||
func() {
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
},
|
||||
false, false,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"gas limit above block gas limit",
|
||||
tx3,
|
||||
math.MaxUint64,
|
||||
func() {},
|
||||
false, false,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"not enough balance for fees",
|
||||
tx2,
|
||||
math.MaxUint64,
|
||||
func() {},
|
||||
func() {
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
},
|
||||
false, false,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"not enough tx gas",
|
||||
tx2,
|
||||
0,
|
||||
func() {
|
||||
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
|
||||
},
|
||||
false, true,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"not enough block gas",
|
||||
tx2,
|
||||
0,
|
||||
func() {
|
||||
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
|
||||
|
||||
suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(1))
|
||||
},
|
||||
false, true,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"success - legacy tx",
|
||||
"success",
|
||||
tx2,
|
||||
tx2GasLimit, // it's capped
|
||||
func() {
|
||||
vmdb.AddBalance(addr, big.NewInt(1001000000000000))
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
|
||||
|
||||
suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(10000000000000000000))
|
||||
},
|
||||
true, false,
|
||||
tx2Priority,
|
||||
},
|
||||
{
|
||||
"success - dynamic fee tx",
|
||||
dynamicFeeTx,
|
||||
tx2GasLimit, // it's capped
|
||||
func() {
|
||||
vmdb.AddBalance(addr, big.NewInt(1001000000000000))
|
||||
suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(10000000000000000000))
|
||||
},
|
||||
true, false,
|
||||
dynamicFeeTxPriority,
|
||||
},
|
||||
{
|
||||
"success - gas limit on gasMeter is set on ReCheckTx mode",
|
||||
dynamicFeeTx,
|
||||
0, // for reCheckTX mode, gas limit should be set to 0
|
||||
func() {
|
||||
vmdb.AddBalance(addr, big.NewInt(1001000000000000))
|
||||
suite.ctx = suite.ctx.WithIsReCheckTx(true)
|
||||
},
|
||||
true, false,
|
||||
0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
vmdb = suite.StateDB()
|
||||
tc.malleate()
|
||||
suite.Require().NoError(vmdb.Commit())
|
||||
|
||||
if tc.expPanic {
|
||||
suite.Require().Panics(func() {
|
||||
_, _ = dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewGasMeter(1)), tc.tx, false, NextFn)
|
||||
_, _ = dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewGasMeter(1)), tc.tx, false, nextFn)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewInfiniteGasMeter()), tc.tx, false, NextFn)
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expPriority, ctx.Priority())
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
suite.Require().Equal(tc.gasLimit, ctx.GasMeter().Limit())
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -322,38 +304,14 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
|
||||
|
||||
addr, privKey := tests.NewAddrKey()
|
||||
|
||||
suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, big.NewInt(100))
|
||||
|
||||
tx := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
1000,
|
||||
big.NewInt(150),
|
||||
big.NewInt(200),
|
||||
nil,
|
||||
nil,
|
||||
ðtypes.AccessList{},
|
||||
)
|
||||
tx2 := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
1000,
|
||||
big.NewInt(150),
|
||||
big.NewInt(200),
|
||||
nil,
|
||||
nil,
|
||||
ðtypes.AccessList{},
|
||||
)
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, ðtypes.AccessList{})
|
||||
tx2 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, ðtypes.AccessList{})
|
||||
|
||||
tx.From = addr.Hex()
|
||||
|
||||
err := tx.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
var vmdb *statedb.StateDB
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
@ -378,7 +336,7 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
|
||||
},
|
||||
true,
|
||||
},
|
||||
@ -386,11 +344,68 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
vmdb = suite.StateDB()
|
||||
tc.malleate()
|
||||
suite.Require().NoError(vmdb.Commit())
|
||||
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, NextFn)
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestAccessListDecorator() {
|
||||
dec := ante.NewAccessListDecorator(suite.app.EvmKeeper)
|
||||
|
||||
addr := tests.GenerateAddress()
|
||||
al := ðtypes.AccessList{
|
||||
{Address: addr, StorageKeys: []common.Hash{{}}},
|
||||
}
|
||||
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil)
|
||||
tx2 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, al)
|
||||
|
||||
tx.From = addr.Hex()
|
||||
tx2.From = addr.Hex()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
malleate func()
|
||||
expPass bool
|
||||
}{
|
||||
{"invalid transaction type", &invalidTx{}, func() {}, false},
|
||||
{
|
||||
"success - no access list",
|
||||
tx,
|
||||
func() {
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"success - with access list",
|
||||
tx2,
|
||||
func() {
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt(1000000))
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate()
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
@ -405,22 +420,19 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
|
||||
dec := ante.NewEthIncrementSenderSequenceDecorator(suite.app.AccountKeeper)
|
||||
addr, privKey := tests.NewAddrKey()
|
||||
|
||||
contract := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 0, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||
contract := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 0, big.NewInt(10), 1000, big.NewInt(1), nil, nil)
|
||||
contract.From = addr.Hex()
|
||||
|
||||
to := tests.GenerateAddress()
|
||||
tx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 0, &to, big.NewInt(10), 1000, big.NewInt(1), nil, nil)
|
||||
tx.From = addr.Hex()
|
||||
|
||||
err := contract.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
to := tests.GenerateAddress()
|
||||
tx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 0, &to, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||
tx.From = addr.Hex()
|
||||
err = tx.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
tx2 := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||
tx2.From = addr.Hex()
|
||||
err = tx2.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
@ -436,9 +448,9 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
|
||||
},
|
||||
{
|
||||
"no signers",
|
||||
evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
|
||||
evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 1000, big.NewInt(1), nil, nil),
|
||||
func() {},
|
||||
false, false,
|
||||
false, true,
|
||||
},
|
||||
{
|
||||
"account not set to store",
|
||||
@ -457,7 +469,7 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
|
||||
},
|
||||
{
|
||||
"success - call",
|
||||
tx2,
|
||||
tx,
|
||||
func() {},
|
||||
true, false,
|
||||
},
|
||||
@ -469,12 +481,12 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
|
||||
|
||||
if tc.expPanic {
|
||||
suite.Require().Panics(func() {
|
||||
_, _ = dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)
|
||||
_, _ = dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)
|
||||
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
@ -483,8 +495,42 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
|
||||
txData, err := evmtypes.UnpackTxData(msg.Data)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
nonce := suite.app.EvmKeeper.GetNonce(suite.ctx, addr)
|
||||
suite.Require().Equal(txData.GetNonce()+1, nonce)
|
||||
nonce := suite.app.EvmKeeper.GetNonce(addr)
|
||||
if txData.GetTo() == nil {
|
||||
suite.Require().Equal(txData.GetNonce(), nonce)
|
||||
} else {
|
||||
suite.Require().Equal(txData.GetNonce()+1, nonce)
|
||||
}
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestEthSetupContextDecorator() {
|
||||
dec := ante.NewEthSetUpContextDecorator()
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
expPass bool
|
||||
}{
|
||||
{"invalid transaction type - does not implement GasTx", &invalidTx{}, false},
|
||||
{
|
||||
"success - transaction implement GasTx",
|
||||
tx,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
|
@ -1,144 +0,0 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdkmath "cosmossdk.io/math"
|
||||
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
"github.com/cerc-io/laconicd/x/evm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
)
|
||||
|
||||
// NewDynamicFeeChecker returns a `TxFeeChecker` that applies a dynamic fee to
|
||||
// Cosmos txs using the EIP-1559 fee market logic.
|
||||
// This can be called in both CheckTx and deliverTx modes.
|
||||
// a) feeCap = tx.fees / tx.gas
|
||||
// b) tipFeeCap = tx.MaxPriorityPrice (default) or MaxInt64
|
||||
// - when `ExtensionOptionDynamicFeeTx` is omitted, `tipFeeCap` defaults to `MaxInt64`.
|
||||
// - when london hardfork is not enabled, it fallbacks to SDK default behavior (validator min-gas-prices).
|
||||
// - Tx priority is set to `effectiveGasPrice / DefaultPriorityReduction`.
|
||||
func NewDynamicFeeChecker(k DynamicFeeEVMKeeper) authante.TxFeeChecker {
|
||||
return func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) {
|
||||
feeTx, ok := tx.(sdk.FeeTx)
|
||||
if !ok {
|
||||
return nil, 0, fmt.Errorf("tx must be a FeeTx")
|
||||
}
|
||||
|
||||
if ctx.BlockHeight() == 0 {
|
||||
// genesis transactions: fallback to min-gas-price logic
|
||||
return checkTxFeeWithValidatorMinGasPrices(ctx, feeTx)
|
||||
}
|
||||
|
||||
params := k.GetParams(ctx)
|
||||
denom := params.EvmDenom
|
||||
ethCfg := params.ChainConfig.EthereumConfig(k.ChainID())
|
||||
|
||||
baseFee := k.GetBaseFee(ctx, ethCfg)
|
||||
if baseFee == nil {
|
||||
// london hardfork is not enabled: fallback to min-gas-prices logic
|
||||
return checkTxFeeWithValidatorMinGasPrices(ctx, feeTx)
|
||||
}
|
||||
|
||||
// default to `MaxInt64` when there's no extension option.
|
||||
maxPriorityPrice := sdkmath.NewInt(math.MaxInt64)
|
||||
|
||||
// get the priority tip cap from the extension option.
|
||||
if hasExtOptsTx, ok := tx.(authante.HasExtensionOptionsTx); ok {
|
||||
for _, opt := range hasExtOptsTx.GetExtensionOptions() {
|
||||
if extOpt, ok := opt.GetCachedValue().(*ethermint.ExtensionOptionDynamicFeeTx); ok {
|
||||
maxPriorityPrice = extOpt.MaxPriorityPrice
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gas := feeTx.GetGas()
|
||||
feeCoins := feeTx.GetFee()
|
||||
fee := feeCoins.AmountOfNoDenomValidation(denom)
|
||||
|
||||
feeCap := fee.Quo(sdkmath.NewIntFromUint64(gas))
|
||||
baseFeeInt := sdkmath.NewIntFromBigInt(baseFee)
|
||||
|
||||
if feeCap.LT(baseFeeInt) {
|
||||
return nil, 0, errorsmod.Wrapf(errortypes.ErrInsufficientFee, "insufficient gas prices; got: %s required: %s", feeCap, baseFeeInt)
|
||||
}
|
||||
|
||||
// calculate the effective gas price using the EIP-1559 logic.
|
||||
effectivePrice := sdkmath.NewIntFromBigInt(types.EffectiveGasPrice(baseFeeInt.BigInt(), feeCap.BigInt(), maxPriorityPrice.BigInt()))
|
||||
|
||||
// NOTE: create a new coins slice without having to validate the denom
|
||||
effectiveFee := sdk.Coins{
|
||||
{
|
||||
Denom: denom,
|
||||
Amount: effectivePrice.Mul(sdkmath.NewIntFromUint64(gas)),
|
||||
},
|
||||
}
|
||||
|
||||
bigPriority := effectivePrice.Sub(baseFeeInt).Quo(types.DefaultPriorityReduction)
|
||||
priority := int64(math.MaxInt64)
|
||||
|
||||
if bigPriority.IsInt64() {
|
||||
priority = bigPriority.Int64()
|
||||
}
|
||||
|
||||
return effectiveFee, priority, nil
|
||||
}
|
||||
}
|
||||
|
||||
// checkTxFeeWithValidatorMinGasPrices implements the default fee logic, where the minimum price per
|
||||
// unit of gas is fixed and set by each validator, and the tx priority is computed from the gas price.
|
||||
func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.FeeTx) (sdk.Coins, int64, error) {
|
||||
feeCoins := tx.GetFee()
|
||||
gas := tx.GetGas()
|
||||
minGasPrices := ctx.MinGasPrices()
|
||||
|
||||
// Ensure that the provided fees meet a minimum threshold for the validator,
|
||||
// if this is a CheckTx. This is only for local mempool purposes, and thus
|
||||
// is only ran on check tx.
|
||||
if ctx.IsCheckTx() && !minGasPrices.IsZero() {
|
||||
requiredFees := make(sdk.Coins, len(minGasPrices))
|
||||
|
||||
// Determine the required fees by multiplying each required minimum gas
|
||||
// price by the gas limit, where fee = ceil(minGasPrice * gasLimit).
|
||||
glDec := sdk.NewDec(int64(gas))
|
||||
|
||||
for i, gp := range minGasPrices {
|
||||
fee := gp.Amount.Mul(glDec)
|
||||
requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
|
||||
}
|
||||
|
||||
if !feeCoins.IsAnyGTE(requiredFees) {
|
||||
return nil, 0, errorsmod.Wrapf(errortypes.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees)
|
||||
}
|
||||
}
|
||||
|
||||
priority := getTxPriority(feeCoins, int64(gas))
|
||||
return feeCoins, priority, nil
|
||||
}
|
||||
|
||||
// getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price
|
||||
// provided in a transaction.
|
||||
func getTxPriority(fees sdk.Coins, gas int64) int64 {
|
||||
var priority int64
|
||||
|
||||
for _, fee := range fees {
|
||||
gasPrice := fee.Amount.QuoRaw(gas)
|
||||
amt := gasPrice.Quo(types.DefaultPriorityReduction)
|
||||
p := int64(math.MaxInt64)
|
||||
|
||||
if amt.IsInt64() {
|
||||
p = amt.Int64()
|
||||
}
|
||||
|
||||
if priority == 0 || p < priority {
|
||||
priority = p
|
||||
}
|
||||
}
|
||||
|
||||
return priority
|
||||
}
|
@ -1,219 +0,0 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
"github.com/cerc-io/laconicd/x/evm/types"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
)
|
||||
|
||||
var _ DynamicFeeEVMKeeper = MockEVMKeeper{}
|
||||
|
||||
type MockEVMKeeper struct {
|
||||
BaseFee *big.Int
|
||||
EnableLondonHF bool
|
||||
}
|
||||
|
||||
func (m MockEVMKeeper) GetBaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int {
|
||||
if m.EnableLondonHF {
|
||||
return m.BaseFee
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m MockEVMKeeper) GetParams(ctx sdk.Context) evmtypes.Params {
|
||||
return evmtypes.DefaultParams()
|
||||
}
|
||||
|
||||
func (m MockEVMKeeper) ChainID() *big.Int {
|
||||
return big.NewInt(9000)
|
||||
}
|
||||
|
||||
func TestSDKTxFeeChecker(t *testing.T) {
|
||||
// testCases:
|
||||
// fallback
|
||||
// genesis tx
|
||||
// checkTx, validate with min-gas-prices
|
||||
// deliverTx, no validation
|
||||
// dynamic fee
|
||||
// with extension option
|
||||
// without extension option
|
||||
// london hardfork enableness
|
||||
encodingConfig := encoding.MakeConfig(module.NewBasicManager())
|
||||
minGasPrices := sdk.NewDecCoins(sdk.NewDecCoin("aphoton", sdk.NewInt(10)))
|
||||
|
||||
genesisCtx := sdk.NewContext(nil, tmproto.Header{}, false, log.NewNopLogger())
|
||||
checkTxCtx := sdk.NewContext(nil, tmproto.Header{Height: 1}, true, log.NewNopLogger()).WithMinGasPrices(minGasPrices)
|
||||
deliverTxCtx := sdk.NewContext(nil, tmproto.Header{Height: 1}, false, log.NewNopLogger())
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
ctx sdk.Context
|
||||
keeper DynamicFeeEVMKeeper
|
||||
buildTx func() sdk.Tx
|
||||
expFees string
|
||||
expPriority int64
|
||||
expSuccess bool
|
||||
}{
|
||||
{
|
||||
"success, genesis tx",
|
||||
genesisCtx,
|
||||
MockEVMKeeper{},
|
||||
func() sdk.Tx {
|
||||
return encodingConfig.TxConfig.NewTxBuilder().GetTx()
|
||||
},
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"fail, min-gas-prices",
|
||||
checkTxCtx,
|
||||
MockEVMKeeper{},
|
||||
func() sdk.Tx {
|
||||
return encodingConfig.TxConfig.NewTxBuilder().GetTx()
|
||||
},
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"success, min-gas-prices",
|
||||
checkTxCtx,
|
||||
MockEVMKeeper{},
|
||||
func() sdk.Tx {
|
||||
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
|
||||
txBuilder.SetGasLimit(1)
|
||||
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(10))))
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
"10aphoton",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"success, min-gas-prices deliverTx",
|
||||
deliverTxCtx,
|
||||
MockEVMKeeper{},
|
||||
func() sdk.Tx {
|
||||
return encodingConfig.TxConfig.NewTxBuilder().GetTx()
|
||||
},
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"fail, dynamic fee",
|
||||
deliverTxCtx,
|
||||
MockEVMKeeper{
|
||||
EnableLondonHF: true, BaseFee: big.NewInt(1),
|
||||
},
|
||||
func() sdk.Tx {
|
||||
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
|
||||
txBuilder.SetGasLimit(1)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"success, dynamic fee",
|
||||
deliverTxCtx,
|
||||
MockEVMKeeper{
|
||||
EnableLondonHF: true, BaseFee: big.NewInt(10),
|
||||
},
|
||||
func() sdk.Tx {
|
||||
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
|
||||
txBuilder.SetGasLimit(1)
|
||||
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(10))))
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
"10aphoton",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"success, dynamic fee priority",
|
||||
deliverTxCtx,
|
||||
MockEVMKeeper{
|
||||
EnableLondonHF: true, BaseFee: big.NewInt(10),
|
||||
},
|
||||
func() sdk.Tx {
|
||||
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
|
||||
txBuilder.SetGasLimit(1)
|
||||
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(10).Mul(types.DefaultPriorityReduction).Add(sdk.NewInt(10)))))
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
"10000010aphoton",
|
||||
10,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"success, dynamic fee empty tipFeeCap",
|
||||
deliverTxCtx,
|
||||
MockEVMKeeper{
|
||||
EnableLondonHF: true, BaseFee: big.NewInt(10),
|
||||
},
|
||||
func() sdk.Tx {
|
||||
txBuilder := encodingConfig.TxConfig.NewTxBuilder().(authtx.ExtensionOptionsTxBuilder)
|
||||
txBuilder.SetGasLimit(1)
|
||||
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(10).Mul(types.DefaultPriorityReduction))))
|
||||
|
||||
option, err := codectypes.NewAnyWithValue(ðermint.ExtensionOptionDynamicFeeTx{})
|
||||
require.NoError(t, err)
|
||||
txBuilder.SetExtensionOptions(option)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
"10aphoton",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"success, dynamic fee tipFeeCap",
|
||||
deliverTxCtx,
|
||||
MockEVMKeeper{
|
||||
EnableLondonHF: true, BaseFee: big.NewInt(10),
|
||||
},
|
||||
func() sdk.Tx {
|
||||
txBuilder := encodingConfig.TxConfig.NewTxBuilder().(authtx.ExtensionOptionsTxBuilder)
|
||||
txBuilder.SetGasLimit(1)
|
||||
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(10).Mul(types.DefaultPriorityReduction).Add(sdk.NewInt(10)))))
|
||||
|
||||
option, err := codectypes.NewAnyWithValue(ðermint.ExtensionOptionDynamicFeeTx{
|
||||
MaxPriorityPrice: sdk.NewInt(5).Mul(types.DefaultPriorityReduction),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
txBuilder.SetExtensionOptions(option)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
"5000010aphoton",
|
||||
5,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
fees, priority, err := NewDynamicFeeChecker(tc.keeper)(tc.ctx, tc.buildTx())
|
||||
if tc.expSuccess {
|
||||
require.Equal(t, tc.expFees, fees.String())
|
||||
require.Equal(t, tc.expPriority, priority)
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// GasWantedDecorator keeps track of the gasWanted amount on the current block in transient store
|
||||
// for BaseFee calculation.
|
||||
// NOTE: This decorator does not perform any validation
|
||||
type GasWantedDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
feeMarketKeeper FeeMarketKeeper
|
||||
}
|
||||
|
||||
// NewGasWantedDecorator creates a new NewGasWantedDecorator
|
||||
func NewGasWantedDecorator(
|
||||
evmKeeper EVMKeeper,
|
||||
feeMarketKeeper FeeMarketKeeper,
|
||||
) GasWantedDecorator {
|
||||
return GasWantedDecorator{
|
||||
evmKeeper,
|
||||
feeMarketKeeper,
|
||||
}
|
||||
}
|
||||
|
||||
func (gwd GasWantedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
chainCfg := gwd.evmKeeper.GetChainConfig(ctx)
|
||||
ethCfg := chainCfg.EthereumConfig(gwd.evmKeeper.ChainID())
|
||||
|
||||
blockHeight := big.NewInt(ctx.BlockHeight())
|
||||
isLondon := ethCfg.IsLondon(blockHeight)
|
||||
|
||||
feeTx, ok := tx.(sdk.FeeTx)
|
||||
if !ok || !isLondon {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
gasWanted := feeTx.GetGas()
|
||||
isBaseFeeEnabled := gwd.feeMarketKeeper.GetBaseFeeEnabled(ctx)
|
||||
|
||||
// Add total gasWanted to cumulative in block transientStore in FeeMarket module
|
||||
if isBaseFeeEnabled {
|
||||
if _, err := gwd.feeMarketKeeper.AddTransientGasWanted(ctx, gasWanted); err != nil {
|
||||
return ctx, errorsmod.Wrapf(err, "failed to add gas wanted to transient store")
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
"github.com/cerc-io/laconicd/tests"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
func (suite AnteTestSuite) TestGasWantedDecorator() {
|
||||
suite.enableFeemarket = true
|
||||
suite.SetupTest()
|
||||
dec := ante.NewGasWantedDecorator(suite.app.EvmKeeper, suite.app.FeeMarketKeeper)
|
||||
from, fromPrivKey := tests.NewAddrKey()
|
||||
to := tests.GenerateAddress()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectedGasWanted uint64
|
||||
malleate func() sdk.Tx
|
||||
}{
|
||||
{
|
||||
"Cosmos Tx",
|
||||
TestGasLimit,
|
||||
func() sdk.Tx {
|
||||
denom := evmtypes.DefaultEVMDenom
|
||||
testMsg := banktypes.MsgSend{
|
||||
FromAddress: "evmos1x8fhpj9nmhqk8z9kpgjt95ck2xwyue0ptzkucp",
|
||||
ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn",
|
||||
Amount: sdk.Coins{sdk.Coin{Amount: sdkmath.NewInt(10), Denom: denom}},
|
||||
}
|
||||
txBuilder := suite.CreateTestCosmosTxBuilder(sdkmath.NewInt(10), "stake", &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
},
|
||||
{
|
||||
"Ethereum Legacy Tx",
|
||||
TestGasLimit,
|
||||
func() sdk.Tx {
|
||||
msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, nil)
|
||||
return suite.CreateTestTx(msg, fromPrivKey, 1, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
"Ethereum Access List Tx",
|
||||
TestGasLimit,
|
||||
func() sdk.Tx {
|
||||
emptyAccessList := ethtypes.AccessList{}
|
||||
msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, &emptyAccessList)
|
||||
return suite.CreateTestTx(msg, fromPrivKey, 1, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
"Ethereum Dynamic Fee Tx (EIP1559)",
|
||||
TestGasLimit,
|
||||
func() sdk.Tx {
|
||||
emptyAccessList := ethtypes.AccessList{}
|
||||
msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), big.NewInt(100), big.NewInt(50), &emptyAccessList)
|
||||
return suite.CreateTestTx(msg, fromPrivKey, 1, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
"EIP712 message",
|
||||
200000,
|
||||
func() sdk.Tx {
|
||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
||||
gas := uint64(200000)
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, from.Bytes())
|
||||
suite.Require().NoError(acc.SetSequence(1))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
tx := suite.CreateTestEIP712TxBuilderMsgSend(acc.GetAddress(), fromPrivKey, suite.ctx.ChainID(), gas, amount)
|
||||
return tx.GetTx()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// cumulative gas wanted from all test transactions in the same block
|
||||
var expectedGasWanted uint64
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
_, err := dec.AnteHandle(suite.ctx, tc.malleate(), false, NextFn)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
gasWanted := suite.app.FeeMarketKeeper.GetTransientGasWanted(suite.ctx)
|
||||
expectedGasWanted += tc.expectedGasWanted
|
||||
suite.Require().Equal(expectedGasWanted, gasWanted)
|
||||
})
|
||||
}
|
||||
}
|
211
app/ante/fees.go
211
app/ante/fees.go
@ -1,211 +0,0 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// MinGasPriceDecorator will check if the transaction's fee is at least as large
|
||||
// as the MinGasPrices param. If fee is too low, decorator returns error and tx
|
||||
// is rejected. This applies for both CheckTx and DeliverTx
|
||||
// If fee is high enough, then call next AnteHandler
|
||||
// CONTRACT: Tx must implement FeeTx to use MinGasPriceDecorator
|
||||
type MinGasPriceDecorator struct {
|
||||
feesKeeper FeeMarketKeeper
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// EthMinGasPriceDecorator will check if the transaction's fee is at least as large
|
||||
// as the MinGasPrices param. If fee is too low, decorator returns error and tx
|
||||
// is rejected. This applies to both CheckTx and DeliverTx and regardless
|
||||
// if London hard fork or fee market params (EIP-1559) are enabled.
|
||||
// If fee is high enough, then call next AnteHandler
|
||||
type EthMinGasPriceDecorator struct {
|
||||
feesKeeper FeeMarketKeeper
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// EthMempoolFeeDecorator will check if the transaction's effective fee is at least as large
|
||||
// as the local validator's minimum gasFee (defined in validator config).
|
||||
// If fee is too low, decorator returns error and tx is rejected from mempool.
|
||||
// Note this only applies when ctx.CheckTx = true
|
||||
// If fee is high enough or not CheckTx, then call next AnteHandler
|
||||
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator
|
||||
type EthMempoolFeeDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewMinGasPriceDecorator creates a new MinGasPriceDecorator instance used only for
|
||||
// Cosmos transactions.
|
||||
func NewMinGasPriceDecorator(fk FeeMarketKeeper, ek EVMKeeper) MinGasPriceDecorator {
|
||||
return MinGasPriceDecorator{feesKeeper: fk, evmKeeper: ek}
|
||||
}
|
||||
|
||||
// NewEthMinGasPriceDecorator creates a new MinGasPriceDecorator instance used only for
|
||||
// Ethereum transactions.
|
||||
func NewEthMinGasPriceDecorator(fk FeeMarketKeeper, ek EVMKeeper) EthMinGasPriceDecorator {
|
||||
return EthMinGasPriceDecorator{feesKeeper: fk, evmKeeper: ek}
|
||||
}
|
||||
|
||||
// NewEthMempoolFeeDecorator creates a new NewEthMempoolFeeDecorator instance used only for
|
||||
// Ethereum transactions.
|
||||
func NewEthMempoolFeeDecorator(ek EVMKeeper) EthMempoolFeeDecorator {
|
||||
return EthMempoolFeeDecorator{
|
||||
evmKeeper: ek,
|
||||
}
|
||||
}
|
||||
|
||||
func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
feeTx, ok := tx.(sdk.FeeTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "invalid transaction type %T, expected sdk.FeeTx", tx)
|
||||
}
|
||||
|
||||
minGasPrice := mpd.feesKeeper.GetParams(ctx).MinGasPrice
|
||||
|
||||
// Short-circuit if min gas price is 0 or if simulating
|
||||
if minGasPrice.IsZero() || simulate {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
evmDenom := mpd.evmKeeper.GetEVMDenom(ctx)
|
||||
minGasPrices := sdk.DecCoins{
|
||||
{
|
||||
Denom: evmDenom,
|
||||
Amount: minGasPrice,
|
||||
},
|
||||
}
|
||||
|
||||
feeCoins := feeTx.GetFee()
|
||||
gas := feeTx.GetGas()
|
||||
|
||||
requiredFees := make(sdk.Coins, 0)
|
||||
|
||||
// Determine the required fees by multiplying each required minimum gas
|
||||
// price by the gas limit, where fee = ceil(minGasPrice * gasLimit).
|
||||
gasLimit := sdk.NewDecFromBigInt(new(big.Int).SetUint64(gas))
|
||||
|
||||
for _, gp := range minGasPrices {
|
||||
fee := gp.Amount.Mul(gasLimit).Ceil().RoundInt()
|
||||
if fee.IsPositive() {
|
||||
requiredFees = requiredFees.Add(sdk.Coin{Denom: gp.Denom, Amount: fee})
|
||||
}
|
||||
}
|
||||
|
||||
if !feeCoins.IsAnyGTE(requiredFees) {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrInsufficientFee,
|
||||
"provided fee < minimum global fee (%s < %s). Please increase the gas price.",
|
||||
feeCoins,
|
||||
requiredFees)
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// AnteHandle ensures that the that the effective fee from the transaction is greater than the
|
||||
// minimum global fee, which is defined by the MinGasPrice (parameter) * GasLimit (tx argument).
|
||||
func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
minGasPrice := empd.feesKeeper.GetParams(ctx).MinGasPrice
|
||||
|
||||
// short-circuit if min gas price is 0
|
||||
if minGasPrice.IsZero() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
chainCfg := empd.evmKeeper.GetChainConfig(ctx)
|
||||
ethCfg := chainCfg.EthereumConfig(empd.evmKeeper.ChainID())
|
||||
baseFee := empd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrUnknownRequest,
|
||||
"invalid message type %T, expected %T",
|
||||
msg, (*evmtypes.MsgEthereumTx)(nil),
|
||||
)
|
||||
}
|
||||
|
||||
feeAmt := ethMsg.GetFee()
|
||||
|
||||
// For dynamic transactions, GetFee() uses the GasFeeCap value, which
|
||||
// is the maximum gas price that the signer can pay. In practice, the
|
||||
// signer can pay less, if the block's BaseFee is lower. So, in this case,
|
||||
// we use the EffectiveFee. If the feemarket formula results in a BaseFee
|
||||
// that lowers EffectivePrice until it is < MinGasPrices, the users must
|
||||
// increase the GasTipCap (priority fee) until EffectivePrice > MinGasPrices.
|
||||
// Transactions with MinGasPrices * gasUsed < tx fees < EffectiveFee are rejected
|
||||
// by the feemarket AnteHandle
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(ethMsg.Data)
|
||||
if err != nil {
|
||||
return ctx, errorsmod.Wrapf(err, "failed to unpack tx data %s", ethMsg.Hash)
|
||||
}
|
||||
|
||||
if txData.TxType() != ethtypes.LegacyTxType {
|
||||
feeAmt = ethMsg.GetEffectiveFee(baseFee)
|
||||
}
|
||||
|
||||
gasLimit := sdk.NewDecFromBigInt(new(big.Int).SetUint64(ethMsg.GetGas()))
|
||||
|
||||
requiredFee := minGasPrice.Mul(gasLimit)
|
||||
fee := sdk.NewDecFromBigInt(feeAmt)
|
||||
|
||||
if fee.LT(requiredFee) {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrInsufficientFee,
|
||||
"provided fee < minimum global fee (%d < %d). Please increase the priority tip (for EIP-1559 txs) or the gas prices (for access list or legacy txs)", //nolint:lll
|
||||
fee.TruncateInt().Int64(), requiredFee.TruncateInt().Int64(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// AnteHandle ensures that the provided fees meet a minimum threshold for the validator.
|
||||
// This check only for local mempool purposes, and thus it is only run on (Re)CheckTx.
|
||||
// The logic is also skipped if the London hard fork and EIP-1559 are enabled.
|
||||
func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
if !ctx.IsCheckTx() || simulate {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
chainCfg := mfd.evmKeeper.GetChainConfig(ctx)
|
||||
ethCfg := chainCfg.EthereumConfig(mfd.evmKeeper.ChainID())
|
||||
|
||||
baseFee := mfd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||
// skip check as the London hard fork and EIP-1559 are enabled
|
||||
if baseFee != nil {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
evmDenom := mfd.evmKeeper.GetEVMDenom(ctx)
|
||||
minGasPrice := ctx.MinGasPrices().AmountOf(evmDenom)
|
||||
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
}
|
||||
|
||||
fee := sdk.NewDecFromBigInt(ethMsg.GetFee())
|
||||
gasLimit := sdk.NewDecFromBigInt(new(big.Int).SetUint64(ethMsg.GetGas()))
|
||||
requiredFee := minGasPrice.Mul(gasLimit)
|
||||
|
||||
if fee.LT(requiredFee) {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrInsufficientFee,
|
||||
"insufficient fee; got: %s required: %s",
|
||||
fee, requiredFee,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
@ -1,351 +0,0 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
"github.com/cerc-io/laconicd/tests"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
var execTypes = []struct {
|
||||
name string
|
||||
isCheckTx bool
|
||||
simulate bool
|
||||
}{
|
||||
{"deliverTx", false, false},
|
||||
{"deliverTxSimulate", false, true},
|
||||
}
|
||||
|
||||
func (s AnteTestSuite) TestMinGasPriceDecorator() {
|
||||
denom := evmtypes.DefaultEVMDenom
|
||||
testMsg := banktypes.MsgSend{
|
||||
FromAddress: "evmos1x8fhpj9nmhqk8z9kpgjt95ck2xwyue0ptzkucp",
|
||||
ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn",
|
||||
Amount: sdk.Coins{sdk.Coin{Amount: sdkmath.NewInt(10), Denom: denom}},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
malleate func() sdk.Tx
|
||||
expPass bool
|
||||
errMsg string
|
||||
allowPassOnSimulate bool
|
||||
}{
|
||||
{
|
||||
"invalid cosmos tx type",
|
||||
func() sdk.Tx {
|
||||
return &invalidTx{}
|
||||
},
|
||||
false,
|
||||
"invalid transaction type",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid cosmos tx with MinGasPrices = 0, gasPrice = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(0), denom, &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
true,
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid cosmos tx with MinGasPrices = 0, gasPrice > 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(10), denom, &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
true,
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid cosmos tx with MinGasPrices = 10, gasPrice = 10",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(10), denom, &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
true,
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid cosmos tx with MinGasPrices = 10, gasPrice = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(0), denom, &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
false,
|
||||
"provided fee < minimum global fee",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid cosmos tx with wrong denom",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(10), "stake", &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
false,
|
||||
"provided fee < minimum global fee",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, et := range execTypes {
|
||||
for _, tc := range testCases {
|
||||
s.Run(et.name+"_"+tc.name, func() {
|
||||
// s.SetupTest(et.isCheckTx)
|
||||
ctx := s.ctx.WithIsReCheckTx(et.isCheckTx)
|
||||
dec := ante.NewMinGasPriceDecorator(s.app.FeeMarketKeeper, s.app.EvmKeeper)
|
||||
_, err := dec.AnteHandle(ctx, tc.malleate(), et.simulate, NextFn)
|
||||
|
||||
if tc.expPass || (et.simulate && tc.allowPassOnSimulate) {
|
||||
s.Require().NoError(err, tc.name)
|
||||
} else {
|
||||
s.Require().Error(err, tc.name)
|
||||
s.Require().Contains(err.Error(), tc.errMsg, tc.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s AnteTestSuite) TestEthMinGasPriceDecorator() {
|
||||
denom := evmtypes.DefaultEVMDenom
|
||||
from, privKey := tests.NewAddrKey()
|
||||
to := tests.GenerateAddress()
|
||||
emptyAccessList := ethtypes.AccessList{}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
malleate func() sdk.Tx
|
||||
expPass bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
"invalid tx type",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
return &invalidTx{}
|
||||
},
|
||||
false,
|
||||
"invalid message type",
|
||||
},
|
||||
{
|
||||
"wrong tx type",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
testMsg := banktypes.MsgSend{
|
||||
FromAddress: "evmos1x8fhpj9nmhqk8z9kpgjt95ck2xwyue0ptzkucp",
|
||||
ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn",
|
||||
Amount: sdk.Coins{sdk.Coin{Amount: sdkmath.NewInt(10), Denom: denom}},
|
||||
}
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(0), denom, &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
false,
|
||||
"invalid message type",
|
||||
},
|
||||
{
|
||||
"valid: invalid tx type with MinGasPrices = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
return &invalidTx{}
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid legacy tx with MinGasPrices = 0, gasPrice = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, nil)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid legacy tx with MinGasPrices = 0, gasPrice > 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(10), nil, nil, nil)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid legacy tx with MinGasPrices = 10, gasPrice = 10",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(10), nil, nil, nil)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"invalid legacy tx with MinGasPrices = 10, gasPrice = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, nil)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
false,
|
||||
"provided fee < minimum global fee",
|
||||
},
|
||||
{
|
||||
"valid dynamic tx with MinGasPrices = 0, EffectivePrice = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(0), big.NewInt(0), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid dynamic tx with MinGasPrices = 0, EffectivePrice > 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(100), big.NewInt(50), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid dynamic tx with MinGasPrices < EffectivePrice",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(100), big.NewInt(100), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"invalid dynamic tx with MinGasPrices > EffectivePrice",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(0), big.NewInt(0), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
false,
|
||||
"provided fee < minimum global fee",
|
||||
},
|
||||
{
|
||||
"invalid dynamic tx with MinGasPrices > BaseFee, MinGasPrices > EffectivePrice",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(100)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
feemarketParams := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
feemarketParams.BaseFee = sdkmath.NewInt(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, feemarketParams)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(1000), big.NewInt(0), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
false,
|
||||
"provided fee < minimum global fee",
|
||||
},
|
||||
{
|
||||
"valid dynamic tx with MinGasPrices > BaseFee, MinGasPrices < EffectivePrice (big GasTipCap)",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(100)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
feemarketParams := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
feemarketParams.BaseFee = sdkmath.NewInt(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, feemarketParams)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(1000), big.NewInt(101), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, et := range execTypes {
|
||||
for _, tc := range testCases {
|
||||
s.Run(et.name+"_"+tc.name, func() {
|
||||
// s.SetupTest(et.isCheckTx)
|
||||
s.SetupTest()
|
||||
dec := ante.NewEthMinGasPriceDecorator(s.app.FeeMarketKeeper, s.app.EvmKeeper)
|
||||
_, err := dec.AnteHandle(s.ctx, tc.malleate(), et.simulate, NextFn)
|
||||
|
||||
if tc.expPass {
|
||||
s.Require().NoError(err, tc.name)
|
||||
} else {
|
||||
s.Require().Error(err, tc.name)
|
||||
s.Require().Contains(err.Error(), tc.errMsg, tc.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestEthMempoolFeeDecorator() {
|
||||
// TODO: add test
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
ibcante "github.com/cosmos/ibc-go/v5/modules/core/ante"
|
||||
ibckeeper "github.com/cosmos/ibc-go/v5/modules/core/keeper"
|
||||
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
)
|
||||
|
||||
// HandlerOptions extend the SDK's AnteHandler options by requiring the IBC
|
||||
// channel keeper, EVM Keeper and Fee Market Keeper.
|
||||
type HandlerOptions struct {
|
||||
AccountKeeper evmtypes.AccountKeeper
|
||||
BankKeeper evmtypes.BankKeeper
|
||||
IBCKeeper *ibckeeper.Keeper
|
||||
FeeMarketKeeper FeeMarketKeeper
|
||||
EvmKeeper EVMKeeper
|
||||
FeegrantKeeper ante.FeegrantKeeper
|
||||
SignModeHandler authsigning.SignModeHandler
|
||||
SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params) error
|
||||
MaxTxGasWanted uint64
|
||||
ExtensionOptionChecker ante.ExtensionOptionChecker
|
||||
TxFeeChecker ante.TxFeeChecker
|
||||
}
|
||||
|
||||
func (options HandlerOptions) validate() error {
|
||||
if options.AccountKeeper == nil {
|
||||
return errorsmod.Wrap(errortypes.ErrLogic, "account keeper is required for AnteHandler")
|
||||
}
|
||||
if options.BankKeeper == nil {
|
||||
return errorsmod.Wrap(errortypes.ErrLogic, "bank keeper is required for AnteHandler")
|
||||
}
|
||||
if options.SignModeHandler == nil {
|
||||
return errorsmod.Wrap(errortypes.ErrLogic, "sign mode handler is required for ante builder")
|
||||
}
|
||||
if options.FeeMarketKeeper == nil {
|
||||
return errorsmod.Wrap(errortypes.ErrLogic, "fee market keeper is required for AnteHandler")
|
||||
}
|
||||
if options.EvmKeeper == nil {
|
||||
return errorsmod.Wrap(errortypes.ErrLogic, "evm keeper is required for AnteHandler")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler {
|
||||
return sdk.ChainAnteDecorators(
|
||||
NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first
|
||||
NewEthMempoolFeeDecorator(options.EvmKeeper), // Check eth effective gas price against minimal-gas-prices
|
||||
NewEthMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), // Check eth effective gas price against the global MinGasPrice
|
||||
NewEthValidateBasicDecorator(options.EvmKeeper),
|
||||
NewEthSigVerificationDecorator(options.EvmKeeper),
|
||||
NewEthAccountVerificationDecorator(options.AccountKeeper, options.EvmKeeper),
|
||||
NewCanTransferDecorator(options.EvmKeeper),
|
||||
NewEthGasConsumeDecorator(options.EvmKeeper, options.MaxTxGasWanted),
|
||||
NewEthIncrementSenderSequenceDecorator(options.AccountKeeper), // innermost AnteDecorator.
|
||||
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
|
||||
NewEthEmitEventDecorator(options.EvmKeeper), // emit eth tx hash and index at the very last ante handler.
|
||||
)
|
||||
}
|
||||
|
||||
func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler {
|
||||
return sdk.ChainAnteDecorators(
|
||||
RejectMessagesDecorator{}, // reject MsgEthereumTxs
|
||||
ante.NewSetUpContextDecorator(),
|
||||
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
|
||||
ante.NewValidateBasicDecorator(),
|
||||
ante.NewTxTimeoutHeightDecorator(),
|
||||
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
|
||||
ante.NewValidateMemoDecorator(options.AccountKeeper),
|
||||
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
|
||||
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
|
||||
// SetPubKeyDecorator must be called before all signature verification decorators
|
||||
ante.NewSetPubKeyDecorator(options.AccountKeeper),
|
||||
ante.NewValidateSigCountDecorator(options.AccountKeeper),
|
||||
ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer),
|
||||
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
|
||||
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
|
||||
ibcante.NewRedundantRelayDecorator(options.IBCKeeper),
|
||||
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
|
||||
)
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/evm/statedb"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
evm "github.com/cerc-io/laconicd/x/evm/vm"
|
||||
feemarkettypes "github.com/cerc-io/laconicd/x/feemarket/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
tx "github.com/cosmos/cosmos-sdk/types/tx"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// DynamicFeeEVMKeeper is a subset of EVMKeeper interface that supports dynamic fee checker
|
||||
type DynamicFeeEVMKeeper interface {
|
||||
ChainID() *big.Int
|
||||
GetParams(ctx sdk.Context) evmtypes.Params
|
||||
GetBaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int
|
||||
}
|
||||
|
||||
// EVMKeeper defines the expected keeper interface used on the Eth AnteHandler
|
||||
type EVMKeeper interface {
|
||||
statedb.Keeper
|
||||
DynamicFeeEVMKeeper
|
||||
|
||||
NewEVM(ctx sdk.Context, msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM
|
||||
DeductTxCostsFromUserBalance(ctx sdk.Context, fees sdk.Coins, from common.Address) error
|
||||
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
|
||||
ResetTransientGasUsed(ctx sdk.Context)
|
||||
GetTxIndexTransient(ctx sdk.Context) uint64
|
||||
GetChainConfig(ctx sdk.Context) evmtypes.ChainConfig
|
||||
GetEVMDenom(ctx sdk.Context) string
|
||||
GetEnableCreate(ctx sdk.Context) bool
|
||||
GetEnableCall(ctx sdk.Context) bool
|
||||
GetAllowUnprotectedTxs(ctx sdk.Context) bool
|
||||
}
|
||||
|
||||
type protoTxProvider interface {
|
||||
GetProtoTx() *tx.Tx
|
||||
}
|
||||
|
||||
// FeeMarketKeeper defines the expected keeper interface used on the AnteHandler
|
||||
type FeeMarketKeeper interface {
|
||||
GetParams(ctx sdk.Context) (params feemarkettypes.Params)
|
||||
AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error)
|
||||
GetBaseFeeEnabled(ctx sdk.Context) bool
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// RejectMessagesDecorator prevents invalid msg types from being executed
|
||||
type RejectMessagesDecorator struct{}
|
||||
|
||||
// AnteHandle rejects messages that requires ethereum-specific authentication.
|
||||
// For example `MsgEthereumTx` requires fee to be deducted in the antehandler in
|
||||
// order to perform the refund.
|
||||
func (rmd RejectMessagesDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
if _, ok := msg.(*evmtypes.MsgEthereumTx); ok {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrInvalidType,
|
||||
"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
|
||||
)
|
||||
}
|
||||
}
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
sdkmath "cosmossdk.io/math"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption
|
||||
// by setting the gas meter to infinite
|
||||
type EthSetupContextDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
func NewEthSetUpContextDecorator(evmKeeper EVMKeeper) EthSetupContextDecorator {
|
||||
return EthSetupContextDecorator{
|
||||
evmKeeper: evmKeeper,
|
||||
}
|
||||
}
|
||||
|
||||
func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
// all transactions must implement GasTx
|
||||
_, ok := tx.(authante.GasTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "invalid transaction type %T, expected GasTx", tx)
|
||||
}
|
||||
|
||||
// We need to setup an empty gas config so that the gas is consistent with Ethereum.
|
||||
newCtx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()).
|
||||
WithKVGasConfig(storetypes.GasConfig{}).
|
||||
WithTransientKVGasConfig(storetypes.GasConfig{})
|
||||
|
||||
// Reset transient gas used to prepare the execution of current cosmos tx.
|
||||
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
|
||||
esc.evmKeeper.ResetTransientGasUsed(ctx)
|
||||
return next(newCtx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthEmitEventDecorator emit events in ante handler in case of tx execution failed (out of block gas limit).
|
||||
type EthEmitEventDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewEthEmitEventDecorator creates a new EthEmitEventDecorator
|
||||
func NewEthEmitEventDecorator(evmKeeper EVMKeeper) EthEmitEventDecorator {
|
||||
return EthEmitEventDecorator{evmKeeper}
|
||||
}
|
||||
|
||||
// AnteHandle emits some basic events for the eth messages
|
||||
func (eeed EthEmitEventDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
// After eth tx passed ante handler, the fee is deducted and nonce increased, it shouldn't be ignored by json-rpc,
|
||||
// we need to emit some basic events at the very end of ante handler to be indexed by tendermint.
|
||||
txIndex := eeed.evmKeeper.GetTxIndexTransient(ctx)
|
||||
for i, msg := range tx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
}
|
||||
|
||||
// emit ethereum tx hash as an event so that it can be indexed by Tendermint for query purposes
|
||||
// it's emitted in ante handler, so we can query failed transaction (out of block gas limit).
|
||||
ctx.EventManager().EmitEvent(sdk.NewEvent(
|
||||
evmtypes.EventTypeEthereumTx,
|
||||
sdk.NewAttribute(evmtypes.AttributeKeyEthereumTxHash, msgEthTx.Hash),
|
||||
sdk.NewAttribute(evmtypes.AttributeKeyTxIndex, strconv.FormatUint(txIndex+uint64(i), 10)),
|
||||
))
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures
|
||||
type EthValidateBasicDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator
|
||||
func NewEthValidateBasicDecorator(ek EVMKeeper) EthValidateBasicDecorator {
|
||||
return EthValidateBasicDecorator{
|
||||
evmKeeper: ek,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle handles basic validation of tx
|
||||
func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
// no need to validate basic on recheck tx, call next antehandler
|
||||
if ctx.IsReCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
err := tx.ValidateBasic()
|
||||
// ErrNoSignatures is fine with eth tx
|
||||
if err != nil && !errors.Is(err, errortypes.ErrNoSignatures) {
|
||||
return ctx, errorsmod.Wrap(err, "tx basic validation failed")
|
||||
}
|
||||
|
||||
// For eth type cosmos tx, some fields should be verified as zero values,
|
||||
// since we will only verify the signature against the hash of the MsgEthereumTx.Data
|
||||
wrapperTx, ok := tx.(protoTxProvider)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid tx type %T, didn't implement interface protoTxProvider", tx)
|
||||
}
|
||||
|
||||
protoTx := wrapperTx.GetProtoTx()
|
||||
body := protoTx.Body
|
||||
if body.Memo != "" || body.TimeoutHeight != uint64(0) || len(body.NonCriticalExtensionOptions) > 0 {
|
||||
return ctx, errorsmod.Wrap(errortypes.ErrInvalidRequest,
|
||||
"for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty")
|
||||
}
|
||||
|
||||
if len(body.ExtensionOptions) != 1 {
|
||||
return ctx, errorsmod.Wrap(errortypes.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1")
|
||||
}
|
||||
|
||||
authInfo := protoTx.AuthInfo
|
||||
if len(authInfo.SignerInfos) > 0 {
|
||||
return ctx, errorsmod.Wrap(errortypes.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty")
|
||||
}
|
||||
|
||||
if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" {
|
||||
return ctx, errorsmod.Wrap(errortypes.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty")
|
||||
}
|
||||
|
||||
sigs := protoTx.Signatures
|
||||
if len(sigs) > 0 {
|
||||
return ctx, errorsmod.Wrap(errortypes.ErrInvalidRequest, "for eth tx Signatures should be empty")
|
||||
}
|
||||
|
||||
txFee := sdk.Coins{}
|
||||
txGasLimit := uint64(0)
|
||||
|
||||
chainCfg := vbd.evmKeeper.GetChainConfig(ctx)
|
||||
chainID := vbd.evmKeeper.ChainID()
|
||||
ethCfg := chainCfg.EthereumConfig(chainID)
|
||||
baseFee := vbd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||
enableCreate := vbd.evmKeeper.GetEnableCreate(ctx)
|
||||
enableCall := vbd.evmKeeper.GetEnableCall(ctx)
|
||||
evmDenom := vbd.evmKeeper.GetEVMDenom(ctx)
|
||||
|
||||
for _, msg := range protoTx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
}
|
||||
|
||||
// Validate `From` field
|
||||
if msgEthTx.From != "" {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidRequest, "invalid From %s, expect empty string", msgEthTx.From)
|
||||
}
|
||||
|
||||
txGasLimit += msgEthTx.GetGas()
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||
if err != nil {
|
||||
return ctx, errorsmod.Wrap(err, "failed to unpack MsgEthereumTx Data")
|
||||
}
|
||||
|
||||
// return error if contract creation or call are disabled through governance
|
||||
if !enableCreate && txData.GetTo() == nil {
|
||||
return ctx, errorsmod.Wrap(evmtypes.ErrCreateDisabled, "failed to create new contract")
|
||||
} else if !enableCall && txData.GetTo() != nil {
|
||||
return ctx, errorsmod.Wrap(evmtypes.ErrCallDisabled, "failed to call contract")
|
||||
}
|
||||
|
||||
if baseFee == nil && txData.TxType() == ethtypes.DynamicFeeTxType {
|
||||
return ctx, errorsmod.Wrap(ethtypes.ErrTxTypeNotSupported, "dynamic fee tx not supported")
|
||||
}
|
||||
|
||||
txFee = txFee.Add(sdk.Coin{Denom: evmDenom, Amount: sdkmath.NewIntFromBigInt(txData.Fee())})
|
||||
}
|
||||
|
||||
if !authInfo.Fee.Amount.IsEqual(txFee) {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidRequest, "invalid AuthInfo Fee Amount (%s != %s)", authInfo.Fee.Amount, txFee)
|
||||
}
|
||||
|
||||
if authInfo.Fee.GasLimit != txGasLimit {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidRequest, "invalid AuthInfo Fee GasLimit (%d != %d)", authInfo.Fee.GasLimit, txGasLimit)
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func (suite AnteTestSuite) TestEthSetupContextDecorator() {
|
||||
dec := ante.NewEthSetUpContextDecorator(suite.app.EvmKeeper)
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
expPass bool
|
||||
}{
|
||||
{"invalid transaction type - does not implement GasTx", &invalidTx{}, false},
|
||||
{
|
||||
"success - transaction implement GasTx",
|
||||
tx,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
ctx, err := dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Equal(storetypes.GasConfig{}, ctx.KVGasConfig())
|
||||
suite.Equal(storetypes.GasConfig{}, ctx.TransientKVGasConfig())
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
"github.com/cerc-io/laconicd/tests"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
|
||||
addr, privKey := tests.NewAddrKey()
|
||||
|
||||
signedTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||
signedTx.From = addr.Hex()
|
||||
err := signedTx.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
unprotectedTx := evmtypes.NewTxContract(nil, 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||
unprotectedTx.From = addr.Hex()
|
||||
err = unprotectedTx.Sign(ethtypes.HomesteadSigner{}, tests.NewSigner(privKey))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
allowUnprotectedTxs bool
|
||||
reCheckTx bool
|
||||
expPass bool
|
||||
}{
|
||||
{"ReCheckTx", &invalidTx{}, false, true, false},
|
||||
{"invalid transaction type", &invalidTx{}, false, false, false},
|
||||
{
|
||||
"invalid sender",
|
||||
evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &addr, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{"successful signature verification", signedTx, false, false, true},
|
||||
{"invalid, reject unprotected txs", unprotectedTx, false, false, false},
|
||||
{"successful, allow unprotected txs", unprotectedTx, true, false, true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.evmParamsOption = func(params *evmtypes.Params) {
|
||||
params.AllowUnprotectedTxs = tc.allowUnprotectedTxs
|
||||
}
|
||||
suite.SetupTest()
|
||||
dec := ante.NewEthSigVerificationDecorator(suite.app.EvmKeeper)
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, NextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
suite.evmParamsOption = nil
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/cerc-io/laconicd/tests"
|
||||
"github.com/cerc-io/laconicd/x/evm/statedb"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
)
|
||||
|
||||
func (suite AnteTestSuite) TestSignatures() {
|
||||
suite.enableFeemarket = false
|
||||
suite.SetupTest() // reset
|
||||
|
||||
addr, privKey := tests.NewAddrKey()
|
||||
to := tests.GenerateAddress()
|
||||
|
||||
acc := statedb.NewEmptyAccount()
|
||||
acc.Nonce = 1
|
||||
acc.Balance = big.NewInt(10000000000)
|
||||
|
||||
suite.app.EvmKeeper.SetAccount(suite.ctx, addr, *acc)
|
||||
msgEthereumTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||
msgEthereumTx.From = addr.Hex()
|
||||
|
||||
// CreateTestTx will sign the msgEthereumTx but not sign the cosmos tx since we have signCosmosTx as false
|
||||
tx := suite.CreateTestTx(msgEthereumTx, privKey, 1, false)
|
||||
sigs, err := tx.GetSignaturesV2()
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// signatures of cosmos tx should be empty
|
||||
suite.Require().Equal(len(sigs), 0)
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msgEthereumTx.Data)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
msgV, msgR, msgS := txData.GetRawSignatureValues()
|
||||
|
||||
ethTx := msgEthereumTx.AsTransaction()
|
||||
ethV, ethR, ethS := ethTx.RawSignatureValues()
|
||||
|
||||
// The signatures of MsgehtereumTx should be the same with the corresponding eth tx
|
||||
suite.Require().Equal(msgV, ethV)
|
||||
suite.Require().Equal(msgR, ethR)
|
||||
suite.Require().Equal(msgS, ethS)
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// EthSigVerificationDecorator validates an ethereum signatures
|
||||
type EthSigVerificationDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator
|
||||
func NewEthSigVerificationDecorator(ek EVMKeeper) EthSigVerificationDecorator {
|
||||
return EthSigVerificationDecorator{
|
||||
evmKeeper: ek,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle validates checks that the registered chain id is the same as the one on the message, and
|
||||
// that the signer address matches the one defined on the message.
|
||||
// It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work.
|
||||
// Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user
|
||||
// won't see the error message.
|
||||
func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
chainID := esvd.evmKeeper.ChainID()
|
||||
chainCfg := esvd.evmKeeper.GetChainConfig(ctx)
|
||||
ethCfg := chainCfg.EthereumConfig(chainID)
|
||||
blockNum := big.NewInt(ctx.BlockHeight())
|
||||
signer := ethtypes.MakeSigner(ethCfg, blockNum)
|
||||
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
}
|
||||
|
||||
allowUnprotectedTxs := esvd.evmKeeper.GetAllowUnprotectedTxs(ctx)
|
||||
ethTx := msgEthTx.AsTransaction()
|
||||
if !allowUnprotectedTxs && !ethTx.Protected() {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrNotSupported,
|
||||
"rejected unprotected Ethereum transaction. Please EIP155 sign your transaction to protect it against replay-attacks")
|
||||
}
|
||||
|
||||
sender, err := signer.Sender(ethTx)
|
||||
if err != nil {
|
||||
return ctx, errorsmod.Wrapf(
|
||||
errortypes.ErrorInvalidSigner,
|
||||
"couldn't retrieve sender address from the ethereum transaction: %s",
|
||||
err.Error(),
|
||||
)
|
||||
}
|
||||
|
||||
// set up the sender to the transaction field if not already
|
||||
msgEthTx.From = sender.Hex()
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
@ -1,59 +1,29 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/cerc-io/laconicd/ethereum/eip712"
|
||||
"github.com/cerc-io/laconicd/types"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
cryptocodec "github.com/cerc-io/laconicd/crypto/codec"
|
||||
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
sdkante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
authz "github.com/cosmos/cosmos-sdk/x/authz"
|
||||
|
||||
"github.com/cerc-io/laconicd/app"
|
||||
ante "github.com/cerc-io/laconicd/app/ante"
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
"github.com/cerc-io/laconicd/tests"
|
||||
"github.com/cerc-io/laconicd/x/evm/statedb"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
feemarkettypes "github.com/cerc-io/laconicd/x/feemarket/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
evtypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/feegrant"
|
||||
govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
|
||||
"github.com/tharsis/ethermint/app"
|
||||
ante "github.com/tharsis/ethermint/app/ante"
|
||||
"github.com/tharsis/ethermint/encoding"
|
||||
"github.com/tharsis/ethermint/tests"
|
||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
)
|
||||
@ -61,54 +31,16 @@ import (
|
||||
type AnteTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
ctx sdk.Context
|
||||
app *app.EthermintApp
|
||||
clientCtx client.Context
|
||||
anteHandler sdk.AnteHandler
|
||||
ethSigner ethtypes.Signer
|
||||
enableFeemarket bool
|
||||
enableLondonHF bool
|
||||
evmParamsOption func(*evmtypes.Params)
|
||||
}
|
||||
|
||||
const TestGasLimit uint64 = 100000
|
||||
|
||||
func (suite *AnteTestSuite) StateDB() *statedb.StateDB {
|
||||
return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes())))
|
||||
ctx sdk.Context
|
||||
app *app.EthermintApp
|
||||
clientCtx client.Context
|
||||
anteHandler sdk.AnteHandler
|
||||
ethSigner ethtypes.Signer
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) SetupTest() {
|
||||
checkTx := false
|
||||
|
||||
suite.app = app.Setup(checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
|
||||
if suite.enableFeemarket {
|
||||
// setup feemarketGenesis params
|
||||
feemarketGenesis := feemarkettypes.DefaultGenesisState()
|
||||
feemarketGenesis.Params.EnableHeight = 1
|
||||
feemarketGenesis.Params.NoBaseFee = false
|
||||
// Verify feeMarket genesis
|
||||
err := feemarketGenesis.Validate()
|
||||
suite.Require().NoError(err)
|
||||
genesis[feemarkettypes.ModuleName] = app.AppCodec().MustMarshalJSON(feemarketGenesis)
|
||||
}
|
||||
evmGenesis := evmtypes.DefaultGenesisState()
|
||||
evmGenesis.Params.AllowUnprotectedTxs = false
|
||||
if !suite.enableLondonHF {
|
||||
maxInt := sdkmath.NewInt(math.MaxInt64)
|
||||
evmGenesis.Params.ChainConfig.LondonBlock = &maxInt
|
||||
evmGenesis.Params.ChainConfig.ArrowGlacierBlock = &maxInt
|
||||
evmGenesis.Params.ChainConfig.GrayGlacierBlock = &maxInt
|
||||
evmGenesis.Params.ChainConfig.MergeNetsplitBlock = &maxInt
|
||||
evmGenesis.Params.ChainConfig.ShanghaiBlock = &maxInt
|
||||
evmGenesis.Params.ChainConfig.CancunBlock = &maxInt
|
||||
}
|
||||
if suite.evmParamsOption != nil {
|
||||
suite.evmParamsOption(&evmGenesis.Params)
|
||||
}
|
||||
genesis[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(evmGenesis)
|
||||
return genesis
|
||||
})
|
||||
|
||||
suite.app = app.Setup(checkTx)
|
||||
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 2, ChainID: "ethermint_9000-1", Time: time.Now().UTC()})
|
||||
suite.ctx = suite.ctx.WithMinGasPrices(sdk.NewDecCoins(sdk.NewDecCoin(evmtypes.DefaultEVMDenom, sdk.OneInt())))
|
||||
suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(1000000000000000000))
|
||||
@ -116,72 +48,25 @@ func (suite *AnteTestSuite) SetupTest() {
|
||||
|
||||
infCtx := suite.ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
suite.app.AccountKeeper.SetParams(infCtx, authtypes.DefaultParams())
|
||||
suite.app.EvmKeeper.SetParams(infCtx, evmtypes.DefaultParams())
|
||||
|
||||
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
|
||||
// We're using TestMsg amino encoding in some tests, so register it here.
|
||||
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
|
||||
eip712.SetEncodingConfig(encodingConfig)
|
||||
|
||||
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
|
||||
|
||||
anteHandler, err := ante.NewAnteHandler(ante.HandlerOptions{
|
||||
AccountKeeper: suite.app.AccountKeeper,
|
||||
BankKeeper: suite.app.BankKeeper,
|
||||
EvmKeeper: suite.app.EvmKeeper,
|
||||
FeegrantKeeper: suite.app.FeeGrantKeeper,
|
||||
IBCKeeper: suite.app.IBCKeeper,
|
||||
FeeMarketKeeper: suite.app.FeeMarketKeeper,
|
||||
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
|
||||
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.anteHandler = anteHandler
|
||||
suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.EvmKeeper, suite.app.FeeGrantKeeper, suite.app.IBCKeeper.ChannelKeeper, encodingConfig.TxConfig.SignModeHandler())
|
||||
suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
|
||||
}
|
||||
|
||||
func TestAnteTestSuite(t *testing.T) {
|
||||
suite.Run(t, &AnteTestSuite{
|
||||
enableLondonHF: true,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *AnteTestSuite) BuildTestEthTx(
|
||||
from common.Address,
|
||||
to common.Address,
|
||||
amount *big.Int,
|
||||
input []byte,
|
||||
gasPrice *big.Int,
|
||||
gasFeeCap *big.Int,
|
||||
gasTipCap *big.Int,
|
||||
accesses *ethtypes.AccessList,
|
||||
) *evmtypes.MsgEthereumTx {
|
||||
chainID := s.app.EvmKeeper.ChainID()
|
||||
nonce := s.app.EvmKeeper.GetNonce(
|
||||
s.ctx,
|
||||
common.BytesToAddress(from.Bytes()),
|
||||
)
|
||||
|
||||
msgEthereumTx := evmtypes.NewTx(
|
||||
chainID,
|
||||
nonce,
|
||||
&to,
|
||||
amount,
|
||||
TestGasLimit,
|
||||
gasPrice,
|
||||
gasFeeCap,
|
||||
gasTipCap,
|
||||
input,
|
||||
accesses,
|
||||
)
|
||||
msgEthereumTx.From = from.String()
|
||||
return msgEthereumTx
|
||||
suite.Run(t, new(AnteTestSuite))
|
||||
}
|
||||
|
||||
// CreateTestTx is a helper function to create a tx given multiple inputs.
|
||||
func (suite *AnteTestSuite) CreateTestTx(
|
||||
msg *evmtypes.MsgEthereumTx, priv cryptotypes.PrivKey, accNum uint64, signCosmosTx bool,
|
||||
unsetExtensionOptions ...bool,
|
||||
) authsigning.Tx {
|
||||
return suite.CreateTestTxBuilder(msg, priv, accNum, signCosmosTx).GetTx()
|
||||
}
|
||||
@ -189,34 +74,26 @@ func (suite *AnteTestSuite) CreateTestTx(
|
||||
// CreateTestTxBuilder is a helper function to create a tx builder given multiple inputs.
|
||||
func (suite *AnteTestSuite) CreateTestTxBuilder(
|
||||
msg *evmtypes.MsgEthereumTx, priv cryptotypes.PrivKey, accNum uint64, signCosmosTx bool,
|
||||
unsetExtensionOptions ...bool,
|
||||
) client.TxBuilder {
|
||||
var option *codectypes.Any
|
||||
var err error
|
||||
if len(unsetExtensionOptions) == 0 {
|
||||
option, err = codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
option, err := codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
|
||||
suite.Require().True(ok)
|
||||
|
||||
if len(unsetExtensionOptions) == 0 {
|
||||
builder.SetExtensionOptions(option)
|
||||
}
|
||||
builder.SetExtensionOptions(option)
|
||||
|
||||
err = msg.Sign(suite.ethSigner, tests.NewSigner(priv))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
msg.From = ""
|
||||
err = builder.SetMsgs(msg)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msg.Data)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
fees := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewIntFromBigInt(txData.Fee())))
|
||||
fees := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewIntFromBigInt(txData.Fee())))
|
||||
builder.SetFeeAmount(fees)
|
||||
builder.SetGasLimit(msg.GetGas())
|
||||
|
||||
@ -259,473 +136,6 @@ func (suite *AnteTestSuite) CreateTestTxBuilder(
|
||||
return txBuilder
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestCosmosTxBuilder(gasPrice sdkmath.Int, denom string, msgs ...sdk.Msg) client.TxBuilder {
|
||||
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
txBuilder.SetGasLimit(TestGasLimit)
|
||||
fees := &sdk.Coins{{Denom: denom, Amount: gasPrice.MulRaw(int64(TestGasLimit))}}
|
||||
txBuilder.SetFeeAmount(*fees)
|
||||
err := txBuilder.SetMsgs(msgs...)
|
||||
suite.Require().NoError(err)
|
||||
return txBuilder
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgSend(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
// Build MsgSend
|
||||
recipient := sdk.AccAddress(common.Address{}.Bytes())
|
||||
msgSend := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgDelegate(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
// Build MsgSend
|
||||
valEthAddr := tests.GenerateAddress()
|
||||
valAddr := sdk.ValAddress(valEthAddr.Bytes())
|
||||
msgSend := stakingtypes.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MsgCreateValidator(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
// Build MsgCreateValidator
|
||||
valAddr := sdk.ValAddress(from.Bytes())
|
||||
privEd := ed25519.GenPrivKey()
|
||||
msgCreate, err := stakingtypes.NewMsgCreateValidator(
|
||||
valAddr,
|
||||
privEd.PubKey(),
|
||||
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)),
|
||||
stakingtypes.NewDescription("moniker", "indentity", "website", "security_contract", "details"),
|
||||
stakingtypes.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
|
||||
sdk.OneInt(),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgCreate)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MsgCreateValidator2(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
// Build MsgCreateValidator
|
||||
valAddr := sdk.ValAddress(from.Bytes())
|
||||
privEd := ed25519.GenPrivKey()
|
||||
msgCreate, err := stakingtypes.NewMsgCreateValidator(
|
||||
valAddr,
|
||||
privEd.PubKey(),
|
||||
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)),
|
||||
// Ensure optional fields can be left blank
|
||||
stakingtypes.NewDescription("moniker", "indentity", "", "", ""),
|
||||
stakingtypes.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
|
||||
sdk.OneInt(),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgCreate)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712SubmitProposal(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, deposit sdk.Coins) client.TxBuilder {
|
||||
proposal, ok := govtypes.ContentFromProposalType("My proposal", "My description", govtypes.ProposalTypeText)
|
||||
suite.Require().True(ok)
|
||||
msgSubmit, err := govtypes.NewMsgSubmitProposal(proposal, deposit, from)
|
||||
suite.Require().NoError(err)
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgSubmit)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712GrantAllowance(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
spendLimit := sdk.NewCoins(sdk.NewInt64Coin(evmtypes.DefaultEVMDenom, 10))
|
||||
threeHours := time.Now().Add(3 * time.Hour)
|
||||
basic := &feegrant.BasicAllowance{
|
||||
SpendLimit: spendLimit,
|
||||
Expiration: &threeHours,
|
||||
}
|
||||
granted := tests.GenerateAddress()
|
||||
grantedAddr := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, granted.Bytes())
|
||||
msgGrant, err := feegrant.NewMsgGrantAllowance(basic, from, grantedAddr.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgGrant)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MsgEditValidator(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
valAddr := sdk.ValAddress(from.Bytes())
|
||||
msgEdit := stakingtypes.NewMsgEditValidator(
|
||||
valAddr,
|
||||
stakingtypes.NewDescription("moniker", "identity", "website", "security_contract", "details"),
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgEdit)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MsgSubmitEvidence(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
pk := ed25519.GenPrivKey()
|
||||
msgEvidence, err := evtypes.NewMsgSubmitEvidence(from, &evtypes.Equivocation{
|
||||
Height: 11,
|
||||
Time: time.Now().UTC(),
|
||||
Power: 100,
|
||||
ConsensusAddress: pk.PubKey().Address().String(),
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgEvidence)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MsgVoteV1(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
msgVote := govtypesv1.NewMsgVote(from, 1, govtypesv1.VoteOption_VOTE_OPTION_YES, "")
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgVote)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712SubmitProposalV1(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
// Build V1 proposal messages. Must all be same-type, since EIP-712
|
||||
// does not support arrays of variable type.
|
||||
authAcc := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx)
|
||||
|
||||
proposal1, ok := govtypes.ContentFromProposalType("My proposal 1", "My description 1", govtypes.ProposalTypeText)
|
||||
suite.Require().True(ok)
|
||||
content1, err := govtypesv1.NewLegacyContent(
|
||||
proposal1,
|
||||
sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), authAcc.GetAddress().Bytes()),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
proposal2, ok := govtypes.ContentFromProposalType("My proposal 2", "My description 2", govtypes.ProposalTypeText)
|
||||
suite.Require().True(ok)
|
||||
content2, err := govtypesv1.NewLegacyContent(
|
||||
proposal2,
|
||||
sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), authAcc.GetAddress().Bytes()),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
proposalMsgs := []sdk.Msg{
|
||||
content1,
|
||||
content2,
|
||||
}
|
||||
|
||||
// Build V1 proposal
|
||||
msgProposal, err := govtypesv1.NewMsgSubmitProposal(
|
||||
proposalMsgs,
|
||||
sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100))),
|
||||
sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), from.Bytes()),
|
||||
"Metadata",
|
||||
)
|
||||
|
||||
suite.Require().NoError(err)
|
||||
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgProposal)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MsgExec(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
recipient := sdk.AccAddress(common.Address{}.Bytes())
|
||||
msgSend := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
|
||||
msgExec := authz.NewMsgExec(from, []sdk.Msg{msgSend})
|
||||
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, &msgExec)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MultipleMsgSend(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
recipient := sdk.AccAddress(common.Address{}.Bytes())
|
||||
msgSend := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msgSend, msgSend, msgSend})
|
||||
}
|
||||
|
||||
// Fails
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MultipleSignerMsgs(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
recipient := sdk.AccAddress(common.Address{}.Bytes())
|
||||
msgSend1 := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
|
||||
msgSend2 := banktypes.NewMsgSend(recipient, from, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msgSend1, msgSend2})
|
||||
}
|
||||
|
||||
// StdSignBytes returns the bytes to sign for a transaction.
|
||||
func StdSignBytes(cdc *codec.LegacyAmino, chainID string, accnum uint64, sequence uint64, timeout uint64, fee legacytx.StdFee, msgs []sdk.Msg, memo string, tip *txtypes.Tip) []byte {
|
||||
msgsBytes := make([]json.RawMessage, 0, len(msgs))
|
||||
for _, msg := range msgs {
|
||||
legacyMsg, ok := msg.(legacytx.LegacyMsg)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("expected %T when using amino JSON", (*legacytx.LegacyMsg)(nil)))
|
||||
}
|
||||
|
||||
msgsBytes = append(msgsBytes, json.RawMessage(legacyMsg.GetSignBytes()))
|
||||
}
|
||||
|
||||
var stdTip *legacytx.StdTip
|
||||
if tip != nil {
|
||||
if tip.Tipper == "" {
|
||||
panic(fmt.Errorf("tipper cannot be empty"))
|
||||
}
|
||||
|
||||
stdTip = &legacytx.StdTip{Amount: tip.Amount, Tipper: tip.Tipper}
|
||||
}
|
||||
|
||||
bz, err := cdc.MarshalJSON(legacytx.StdSignDoc{
|
||||
AccountNumber: accnum,
|
||||
ChainID: chainID,
|
||||
Fee: json.RawMessage(fee.Bytes()),
|
||||
Memo: memo,
|
||||
Msgs: msgsBytes,
|
||||
Sequence: sequence,
|
||||
TimeoutHeight: timeout,
|
||||
Tip: stdTip,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return sdk.MustSortJSON(bz)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712SingleMessageTxBuilder(
|
||||
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msg sdk.Msg,
|
||||
) client.TxBuilder {
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msg})
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
|
||||
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msgs []sdk.Msg,
|
||||
) client.TxBuilder {
|
||||
var err error
|
||||
|
||||
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, from)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
pc, err := types.ParseChainID(chainId)
|
||||
suite.Require().NoError(err)
|
||||
ethChainId := pc.Uint64()
|
||||
|
||||
// GenerateTypedData TypedData
|
||||
var ethermintCodec codec.ProtoCodecMarshaler
|
||||
registry := codectypes.NewInterfaceRegistry()
|
||||
types.RegisterInterfaces(registry)
|
||||
ethermintCodec = codec.NewProtoCodec(registry)
|
||||
cryptocodec.RegisterInterfaces(registry)
|
||||
|
||||
fee := legacytx.NewStdFee(gas, gasAmount)
|
||||
accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber()
|
||||
|
||||
data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, msgs, "", nil)
|
||||
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msgs[0], data, &eip712.FeeDelegationOptions{
|
||||
FeePayer: from,
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
sigHash, _, err := apitypes.TypedDataAndHash(typedData)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// Sign typedData
|
||||
keyringSigner := tests.NewSigner(priv)
|
||||
signature, pubKey, err := keyringSigner.SignByAddress(from, sigHash)
|
||||
suite.Require().NoError(err)
|
||||
signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
|
||||
|
||||
// Add ExtensionOptionsWeb3Tx extension
|
||||
var option *codectypes.Any
|
||||
option, err = codectypes.NewAnyWithValue(&types.ExtensionOptionsWeb3Tx{
|
||||
FeePayer: from.String(),
|
||||
TypedDataChainID: ethChainId,
|
||||
FeePayerSig: signature,
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.clientCtx.TxConfig.SignModeHandler()
|
||||
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
|
||||
suite.Require().True(ok)
|
||||
|
||||
builder.SetExtensionOptions(option)
|
||||
builder.SetFeeAmount(gasAmount)
|
||||
builder.SetGasLimit(gas)
|
||||
|
||||
sigsV2 := signing.SignatureV2{
|
||||
PubKey: pubKey,
|
||||
Data: &signing.SingleSignatureData{
|
||||
SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
|
||||
},
|
||||
Sequence: nonce,
|
||||
}
|
||||
|
||||
err = builder.SetSignatures(sigsV2)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
err = builder.SetMsgs(msgs...)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
// Generate a set of pub/priv keys to be used in creating multi-keys
|
||||
func (suite *AnteTestSuite) GenerateMultipleKeys(n int) ([]cryptotypes.PrivKey, []cryptotypes.PubKey) {
|
||||
privKeys := make([]cryptotypes.PrivKey, n)
|
||||
pubKeys := make([]cryptotypes.PubKey, n)
|
||||
for i := 0; i < n; i++ {
|
||||
privKey, err := ethsecp256k1.GenerateKey()
|
||||
suite.Require().NoError(err)
|
||||
privKeys[i] = privKey
|
||||
pubKeys[i] = privKey.PubKey()
|
||||
}
|
||||
return privKeys, pubKeys
|
||||
}
|
||||
|
||||
// generateSingleSignature signs the given sign doc bytes using the given signType (EIP-712 or Standard)
|
||||
func (suite *AnteTestSuite) generateSingleSignature(signMode signing.SignMode, privKey cryptotypes.PrivKey, signDocBytes []byte, signType string) (signature signing.SignatureV2) {
|
||||
var (
|
||||
msg []byte
|
||||
err error
|
||||
)
|
||||
|
||||
msg = signDocBytes
|
||||
|
||||
if signType == "EIP-712" {
|
||||
msg, err = eip712.GetEIP712BytesForMsg(signDocBytes)
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
|
||||
sigBytes, _ := privKey.Sign(msg)
|
||||
sigData := &signing.SingleSignatureData{
|
||||
SignMode: signMode,
|
||||
Signature: sigBytes,
|
||||
}
|
||||
|
||||
return signing.SignatureV2{
|
||||
PubKey: privKey.PubKey(),
|
||||
Data: sigData,
|
||||
}
|
||||
}
|
||||
|
||||
// generateMultikeySignatures signs a set of messages using each private key within a given multi-key
|
||||
func (suite *AnteTestSuite) generateMultikeySignatures(signMode signing.SignMode, privKeys []cryptotypes.PrivKey, signDocBytes []byte, signType string) (signatures []signing.SignatureV2) {
|
||||
n := len(privKeys)
|
||||
signatures = make([]signing.SignatureV2, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
privKey := privKeys[i]
|
||||
currentType := signType
|
||||
|
||||
// If mixed type, alternate signing type on each iteration
|
||||
if signType == "mixed" {
|
||||
if i%2 == 0 {
|
||||
currentType = "EIP-712"
|
||||
} else {
|
||||
currentType = "Standard"
|
||||
}
|
||||
}
|
||||
|
||||
signatures[i] = suite.generateSingleSignature(
|
||||
signMode,
|
||||
privKey,
|
||||
signDocBytes,
|
||||
currentType,
|
||||
)
|
||||
}
|
||||
|
||||
return signatures
|
||||
}
|
||||
|
||||
// RegisterAccount creates an account with the keeper and populates the initial balance
|
||||
func (suite *AnteTestSuite) RegisterAccount(pubKey cryptotypes.PubKey, balance *big.Int) {
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, sdk.AccAddress(pubKey.Address()))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
suite.app.EvmKeeper.SetBalance(suite.ctx, common.BytesToAddress(pubKey.Address()), balance)
|
||||
}
|
||||
|
||||
// createSignerBytes generates sign doc bytes using the given parameters
|
||||
func (suite *AnteTestSuite) createSignerBytes(chainId string, signMode signing.SignMode, pubKey cryptotypes.PubKey, txBuilder client.TxBuilder) []byte {
|
||||
acc, err := sdkante.GetSignerAcc(suite.ctx, suite.app.AccountKeeper, sdk.AccAddress(pubKey.Address()))
|
||||
suite.Require().NoError(err)
|
||||
signerInfo := authsigning.SignerData{
|
||||
Address: sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), acc.GetAddress().Bytes()),
|
||||
ChainID: chainId,
|
||||
AccountNumber: acc.GetAccountNumber(),
|
||||
Sequence: acc.GetSequence(),
|
||||
PubKey: pubKey,
|
||||
}
|
||||
|
||||
signerBytes, err := suite.clientCtx.TxConfig.SignModeHandler().GetSignBytes(
|
||||
signMode,
|
||||
signerInfo,
|
||||
txBuilder.GetTx(),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
return signerBytes
|
||||
}
|
||||
|
||||
// createBaseTxBuilder creates a TxBuilder to be used for Single- or Multi-signing
|
||||
func (suite *AnteTestSuite) createBaseTxBuilder(msg sdk.Msg, gas uint64) client.TxBuilder {
|
||||
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
txBuilder.SetGasLimit(gas)
|
||||
txBuilder.SetFeeAmount(sdk.NewCoins(
|
||||
sdk.NewCoin("aphoton", sdk.NewInt(10000)),
|
||||
))
|
||||
|
||||
err := txBuilder.SetMsgs(msg)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
txBuilder.SetMemo("")
|
||||
|
||||
return txBuilder
|
||||
}
|
||||
|
||||
// CreateTestSignedMultisigTx creates and sign a multi-signed tx for the given message. `signType` indicates whether to use standard signing ("Standard"),
|
||||
// EIP-712 signing ("EIP-712"), or a mix of the two ("mixed").
|
||||
func (suite *AnteTestSuite) CreateTestSignedMultisigTx(privKeys []cryptotypes.PrivKey, signMode signing.SignMode, msg sdk.Msg, chainId string, gas uint64, signType string) client.TxBuilder {
|
||||
pubKeys := make([]cryptotypes.PubKey, len(privKeys))
|
||||
for i, privKey := range privKeys {
|
||||
pubKeys[i] = privKey.PubKey()
|
||||
}
|
||||
|
||||
// Re-derive multikey
|
||||
numKeys := len(privKeys)
|
||||
multiKey := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
|
||||
|
||||
suite.RegisterAccount(multiKey, big.NewInt(10000000000))
|
||||
|
||||
txBuilder := suite.createBaseTxBuilder(msg, gas)
|
||||
|
||||
// Prepare signature field
|
||||
sig := multisig.NewMultisig(len(pubKeys))
|
||||
txBuilder.SetSignatures(signing.SignatureV2{
|
||||
PubKey: multiKey,
|
||||
Data: sig,
|
||||
})
|
||||
|
||||
signerBytes := suite.createSignerBytes(chainId, signMode, multiKey, txBuilder)
|
||||
|
||||
// Sign for each key and update signature field
|
||||
sigs := suite.generateMultikeySignatures(signMode, privKeys, signerBytes, signType)
|
||||
for _, pkSig := range sigs {
|
||||
err := multisig.AddSignatureV2(sig, pkSig, pubKeys)
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
|
||||
txBuilder.SetSignatures(signing.SignatureV2{
|
||||
PubKey: multiKey,
|
||||
Data: sig,
|
||||
})
|
||||
|
||||
return txBuilder
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestSingleSignedTx(privKey cryptotypes.PrivKey, signMode signing.SignMode, msg sdk.Msg, chainId string, gas uint64, signType string) client.TxBuilder {
|
||||
pubKey := privKey.PubKey()
|
||||
|
||||
suite.RegisterAccount(pubKey, big.NewInt(10000000000))
|
||||
|
||||
txBuilder := suite.createBaseTxBuilder(msg, gas)
|
||||
|
||||
// Prepare signature field
|
||||
sig := signing.SingleSignatureData{}
|
||||
txBuilder.SetSignatures(signing.SignatureV2{
|
||||
PubKey: pubKey,
|
||||
Data: &sig,
|
||||
})
|
||||
|
||||
signerBytes := suite.createSignerBytes(chainId, signMode, pubKey, txBuilder)
|
||||
|
||||
sigData := suite.generateSingleSignature(signMode, privKey, signerBytes, signType)
|
||||
txBuilder.SetSignatures(sigData)
|
||||
|
||||
return txBuilder
|
||||
}
|
||||
|
||||
func NextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
var _ sdk.Tx = &invalidTx{}
|
||||
|
||||
type invalidTx struct{}
|
||||
|
585
app/app.go
585
app/app.go
@ -2,7 +2,16 @@ package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/db"
|
||||
types2 "github.com/cosmos/cosmos-sdk/store/types"
|
||||
types3 "github.com/cosmos/cosmos-sdk/store/v2"
|
||||
"github.com/cosmos/cosmos-sdk/store/v2/multi"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/middleware"
|
||||
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -14,12 +23,9 @@ import (
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/grpc/node"
|
||||
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
@ -28,19 +34,15 @@ import (
|
||||
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
|
||||
"github.com/cosmos/cosmos-sdk/store/streaming"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/posthandler"
|
||||
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
|
||||
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/authz"
|
||||
authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
|
||||
authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module"
|
||||
@ -66,11 +68,10 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
|
||||
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
|
||||
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
|
||||
govv1beta2 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper"
|
||||
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||
@ -90,44 +91,39 @@ import (
|
||||
upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
|
||||
"github.com/cosmos/ibc-go/v5/modules/apps/transfer"
|
||||
ibctransferkeeper "github.com/cosmos/ibc-go/v5/modules/apps/transfer/keeper"
|
||||
ibctransfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types"
|
||||
ibc "github.com/cosmos/ibc-go/v5/modules/core"
|
||||
ibcclient "github.com/cosmos/ibc-go/v5/modules/core/02-client"
|
||||
ibcclientclient "github.com/cosmos/ibc-go/v5/modules/core/02-client/client"
|
||||
porttypes "github.com/cosmos/ibc-go/v5/modules/core/05-port/types"
|
||||
ibchost "github.com/cosmos/ibc-go/v5/modules/core/24-host"
|
||||
ibckeeper "github.com/cosmos/ibc-go/v5/modules/core/keeper"
|
||||
"github.com/cosmos/ibc-go/modules/apps/transfer"
|
||||
ibctransferkeeper "github.com/cosmos/ibc-go/modules/apps/transfer/keeper"
|
||||
ibctransfertypes "github.com/cosmos/ibc-go/modules/apps/transfer/types"
|
||||
ibc "github.com/cosmos/ibc-go/modules/core"
|
||||
ibcclientclient "github.com/cosmos/ibc-go/modules/core/02-client/client"
|
||||
porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types"
|
||||
ibchost "github.com/cosmos/ibc-go/modules/core/24-host"
|
||||
ibckeeper "github.com/cosmos/ibc-go/modules/core/keeper"
|
||||
|
||||
// unnamed import of statik for swagger UI support
|
||||
_ "github.com/cerc-io/laconicd/client/docs/statik"
|
||||
_ "github.com/tharsis/ethermint/client/docs/statik"
|
||||
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
"github.com/cerc-io/laconicd/ethereum/eip712"
|
||||
srvflags "github.com/cerc-io/laconicd/server/flags"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
"github.com/cerc-io/laconicd/x/evm"
|
||||
evmkeeper "github.com/cerc-io/laconicd/x/evm/keeper"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
"github.com/cerc-io/laconicd/x/evm/vm/geth"
|
||||
"github.com/cerc-io/laconicd/x/feemarket"
|
||||
feemarketkeeper "github.com/cerc-io/laconicd/x/feemarket/keeper"
|
||||
feemarkettypes "github.com/cerc-io/laconicd/x/feemarket/types"
|
||||
srvflags "github.com/tharsis/ethermint/server/flags"
|
||||
ethermint "github.com/tharsis/ethermint/types"
|
||||
|
||||
// Force-load the tracer engines to trigger registration due to Go-Ethereum v1.10.15 changes
|
||||
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
|
||||
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
|
||||
"github.com/tharsis/ethermint/x/auction"
|
||||
auctionkeeper "github.com/tharsis/ethermint/x/auction/keeper"
|
||||
auctiontypes "github.com/tharsis/ethermint/x/auction/types"
|
||||
"github.com/tharsis/ethermint/x/bond"
|
||||
bondkeeper "github.com/tharsis/ethermint/x/bond/keeper"
|
||||
bondtypes "github.com/tharsis/ethermint/x/bond/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/auction"
|
||||
auctionkeeper "github.com/cerc-io/laconicd/x/auction/keeper"
|
||||
auctiontypes "github.com/cerc-io/laconicd/x/auction/types"
|
||||
"github.com/cerc-io/laconicd/x/bond"
|
||||
bondkeeper "github.com/cerc-io/laconicd/x/bond/keeper"
|
||||
bondtypes "github.com/cerc-io/laconicd/x/bond/types"
|
||||
registry "github.com/cerc-io/laconicd/x/registry"
|
||||
registrykeeper "github.com/cerc-io/laconicd/x/registry/keeper"
|
||||
registrytypes "github.com/cerc-io/laconicd/x/registry/types"
|
||||
"github.com/tharsis/ethermint/x/evm"
|
||||
evmrest "github.com/tharsis/ethermint/x/evm/client/rest"
|
||||
evmkeeper "github.com/tharsis/ethermint/x/evm/keeper"
|
||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||
"github.com/tharsis/ethermint/x/feemarket"
|
||||
feemarketkeeper "github.com/tharsis/ethermint/x/feemarket/keeper"
|
||||
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
|
||||
|
||||
"github.com/tharsis/ethermint/x/nameservice"
|
||||
nameservicekeeper "github.com/tharsis/ethermint/x/nameservice/keeper"
|
||||
nameservicetypes "github.com/tharsis/ethermint/x/nameservice/types"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -136,10 +132,10 @@ func init() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
DefaultNodeHome = filepath.Join(userHomeDir, ".laconicd")
|
||||
DefaultNodeHome = filepath.Join(userHomeDir, ".ethermintd")
|
||||
}
|
||||
|
||||
const appName = "laconicd"
|
||||
const appName = "ethermintd"
|
||||
|
||||
var (
|
||||
// DefaultNodeHome default home directories for the application daemon
|
||||
@ -156,10 +152,10 @@ var (
|
||||
staking.AppModuleBasic{},
|
||||
mint.AppModuleBasic{},
|
||||
distr.AppModuleBasic{},
|
||||
gov.NewAppModuleBasic([]govclient.ProposalHandler{
|
||||
paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.LegacyProposalHandler, upgradeclient.LegacyCancelProposalHandler,
|
||||
gov.NewAppModuleBasic(
|
||||
paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler,
|
||||
ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler,
|
||||
}),
|
||||
),
|
||||
params.AppModuleBasic{},
|
||||
crisis.AppModuleBasic{},
|
||||
slashing.AppModuleBasic{},
|
||||
@ -173,28 +169,29 @@ var (
|
||||
// Ethermint modules
|
||||
evm.AppModuleBasic{},
|
||||
feemarket.AppModuleBasic{},
|
||||
// Laconic modules
|
||||
// Vulcanize DXNS modules
|
||||
auction.AppModuleBasic{},
|
||||
bond.AppModuleBasic{},
|
||||
registry.AppModuleBasic{},
|
||||
nameservice.AppModuleBasic{},
|
||||
)
|
||||
|
||||
// module account permissions
|
||||
maccPerms = map[string][]string{
|
||||
authtypes.FeeCollectorName: nil,
|
||||
distrtypes.ModuleName: nil,
|
||||
minttypes.ModuleName: {authtypes.Minter},
|
||||
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||
govtypes.ModuleName: {authtypes.Burner},
|
||||
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
|
||||
evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, //nolint:lll // used for secure addition and subtraction of balance using module account
|
||||
auctiontypes.ModuleName: nil,
|
||||
auctiontypes.AuctionBurnModuleAccountName: nil,
|
||||
registrytypes.ModuleName: nil,
|
||||
registrytypes.RecordRentModuleAccountName: nil,
|
||||
registrytypes.AuthorityRentModuleAccountName: nil,
|
||||
bondtypes.ModuleName: nil,
|
||||
authtypes.FeeCollectorName: nil,
|
||||
distrtypes.ModuleName: nil,
|
||||
minttypes.ModuleName: {authtypes.Minter},
|
||||
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||
govtypes.ModuleName: {authtypes.Burner},
|
||||
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
|
||||
evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, // used for secure addition and subtraction of balance using module account
|
||||
|
||||
auctiontypes.ModuleName: nil,
|
||||
auctiontypes.AuctionBurnModuleAccountName: nil,
|
||||
nameservicetypes.ModuleName: nil,
|
||||
nameservicetypes.RecordRentModuleAccountName: nil,
|
||||
nameservicetypes.AuthorityRentModuleAccountName: nil,
|
||||
bondtypes.ModuleName: nil,
|
||||
}
|
||||
|
||||
// module accounts that are allowed to receive tokens
|
||||
@ -203,6 +200,8 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
var _ simapp.App = (*EthermintApp)(nil)
|
||||
|
||||
// var _ server.Application (*EthermintApp)(nil)
|
||||
|
||||
// EthermintApp implements an extended ABCI application. It is an application
|
||||
@ -215,13 +214,15 @@ type EthermintApp struct {
|
||||
cdc *codec.LegacyAmino
|
||||
appCodec codec.Codec
|
||||
interfaceRegistry types.InterfaceRegistry
|
||||
legacyRouter *middleware.LegacyRouter
|
||||
msgSvcRouter *middleware.MsgServiceRouter
|
||||
|
||||
invCheckPeriod uint
|
||||
|
||||
// keys to access the substores
|
||||
keys map[string]*storetypes.KVStoreKey
|
||||
tkeys map[string]*storetypes.TransientStoreKey
|
||||
memKeys map[string]*storetypes.MemoryStoreKey
|
||||
keys map[string]*types2.KVStoreKey
|
||||
tkeys map[string]*types2.TransientStoreKey
|
||||
memKeys map[string]*types2.MemoryStoreKey
|
||||
|
||||
// keepers
|
||||
AccountKeeper authkeeper.AccountKeeper
|
||||
@ -249,15 +250,18 @@ type EthermintApp struct {
|
||||
EvmKeeper *evmkeeper.Keeper
|
||||
FeeMarketKeeper feemarketkeeper.Keeper
|
||||
|
||||
// laconic keepers
|
||||
AuctionKeeper auctionkeeper.Keeper
|
||||
BondKeeper bondkeeper.Keeper
|
||||
RegistryKeeper registrykeeper.Keeper
|
||||
RegistryRecordKeeper registrykeeper.RecordKeeper
|
||||
// DXNS keepers
|
||||
AuctionKeeper auctionkeeper.Keeper
|
||||
BondKeeper bondkeeper.Keeper
|
||||
NameServiceKeeper nameservicekeeper.Keeper
|
||||
NameServiceRecordKeeper nameservicekeeper.RecordKeeper
|
||||
|
||||
// the module manager
|
||||
mm *module.Manager
|
||||
|
||||
// simulation manager
|
||||
sm *module.SimulationManager
|
||||
|
||||
// the configurator
|
||||
configurator module.Configurator
|
||||
}
|
||||
@ -265,34 +269,19 @@ type EthermintApp struct {
|
||||
// NewEthermintApp returns a reference to a new initialized Ethermint application.
|
||||
func NewEthermintApp(
|
||||
logger log.Logger,
|
||||
db dbm.DB,
|
||||
db db.DBConnection,
|
||||
traceStore io.Writer,
|
||||
loadLatest bool,
|
||||
skipUpgradeHeights map[int64]bool,
|
||||
homePath string,
|
||||
invCheckPeriod uint,
|
||||
encodingConfig simappparams.EncodingConfig,
|
||||
appOpts servertypes.AppOptions,
|
||||
baseAppOptions ...func(*baseapp.BaseApp),
|
||||
baseAppOptions ...baseapp.AppOption,
|
||||
) *EthermintApp {
|
||||
appCodec := encodingConfig.Codec
|
||||
cdc := encodingConfig.Amino
|
||||
interfaceRegistry := encodingConfig.InterfaceRegistry
|
||||
|
||||
eip712.SetEncodingConfig(encodingConfig)
|
||||
|
||||
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
|
||||
bApp := baseapp.NewBaseApp(
|
||||
appName,
|
||||
logger,
|
||||
db,
|
||||
encodingConfig.TxConfig.TxDecoder(),
|
||||
baseAppOptions...,
|
||||
)
|
||||
bApp.SetCommitMultiStoreTracer(traceStore)
|
||||
bApp.SetVersion(version.Version)
|
||||
bApp.SetInterfaceRegistry(interfaceRegistry)
|
||||
|
||||
keys := sdk.NewKVStoreKeys(
|
||||
// SDK keys
|
||||
authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey,
|
||||
@ -304,27 +293,67 @@ func NewEthermintApp(
|
||||
ibchost.StoreKey, ibctransfertypes.StoreKey,
|
||||
// ethermint keys
|
||||
evmtypes.StoreKey, feemarkettypes.StoreKey,
|
||||
// laconic keys
|
||||
// dxns keys
|
||||
auctiontypes.StoreKey,
|
||||
bondtypes.StoreKey,
|
||||
registrytypes.StoreKey,
|
||||
nameservicetypes.StoreKey,
|
||||
)
|
||||
|
||||
// Add the EVM transient store key
|
||||
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey)
|
||||
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey)
|
||||
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
|
||||
|
||||
// load state streaming if enabled
|
||||
if _, _, err := streaming.LoadStreamingServices(bApp, appOpts, appCodec, keys); err != nil {
|
||||
fmt.Printf("failed to load state streaming: %s", err)
|
||||
os.Exit(1)
|
||||
// initialize stores
|
||||
setNamespaces := func(config *multi.StoreParams, ver uint64) error {
|
||||
for _, key := range keys {
|
||||
typ, err := types3.StoreKeyToType(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = config.RegisterSubstore(key, typ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, key := range memKeys {
|
||||
typ, err := types3.StoreKeyToType(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = config.RegisterSubstore(key, typ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, key := range tkeys {
|
||||
typ, err := types3.StoreKeyToType(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = config.RegisterSubstore(key, typ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
baseAppOptions = append(baseAppOptions, baseapp.StoreOption(setNamespaces))
|
||||
|
||||
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
|
||||
bApp := baseapp.NewBaseApp(
|
||||
appName,
|
||||
logger,
|
||||
db,
|
||||
baseAppOptions...,
|
||||
)
|
||||
bApp.SetCommitMultiStoreTracer(traceStore)
|
||||
bApp.SetVersion(version.Version)
|
||||
bApp.SetInterfaceRegistry(interfaceRegistry)
|
||||
|
||||
app := &EthermintApp{
|
||||
BaseApp: bApp,
|
||||
cdc: cdc,
|
||||
appCodec: appCodec,
|
||||
interfaceRegistry: interfaceRegistry,
|
||||
legacyRouter: middleware.NewLegacyRouter(),
|
||||
msgSvcRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
|
||||
invCheckPeriod: invCheckPeriod,
|
||||
keys: keys,
|
||||
tkeys: tkeys,
|
||||
@ -348,114 +377,74 @@ func NewEthermintApp(
|
||||
|
||||
// use custom Ethermint account for contracts
|
||||
app.AccountKeeper = authkeeper.NewAccountKeeper(
|
||||
appCodec, keys[authtypes.StoreKey],
|
||||
app.GetSubspace(authtypes.ModuleName),
|
||||
ethermint.ProtoAccount,
|
||||
maccPerms,
|
||||
sdk.GetConfig().GetBech32AccountAddrPrefix(),
|
||||
appCodec, keys[authtypes.StoreKey], app.GetSubspace(authtypes.ModuleName), ethermint.ProtoAccount, maccPerms,
|
||||
sdk.Bech32MainPrefix,
|
||||
)
|
||||
app.BankKeeper = bankkeeper.NewBaseKeeper(
|
||||
appCodec,
|
||||
keys[banktypes.StoreKey],
|
||||
app.AccountKeeper,
|
||||
app.GetSubspace(banktypes.ModuleName),
|
||||
app.BlockedAddrs(),
|
||||
appCodec, keys[banktypes.StoreKey], app.AccountKeeper, app.GetSubspace(banktypes.ModuleName), app.BlockedAddrs(),
|
||||
)
|
||||
stakingKeeper := stakingkeeper.NewKeeper(
|
||||
appCodec, keys[stakingtypes.StoreKey],
|
||||
app.AccountKeeper,
|
||||
app.BankKeeper,
|
||||
app.GetSubspace(stakingtypes.ModuleName),
|
||||
appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName),
|
||||
)
|
||||
app.MintKeeper = mintkeeper.NewKeeper(
|
||||
appCodec,
|
||||
keys[minttypes.StoreKey],
|
||||
app.GetSubspace(minttypes.ModuleName),
|
||||
&stakingKeeper,
|
||||
app.AccountKeeper,
|
||||
app.BankKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
appCodec, keys[minttypes.StoreKey], app.GetSubspace(minttypes.ModuleName), &stakingKeeper,
|
||||
app.AccountKeeper, app.BankKeeper, authtypes.FeeCollectorName,
|
||||
)
|
||||
app.DistrKeeper = distrkeeper.NewKeeper(
|
||||
appCodec,
|
||||
keys[distrtypes.StoreKey],
|
||||
app.GetSubspace(distrtypes.ModuleName),
|
||||
app.AccountKeeper,
|
||||
app.BankKeeper,
|
||||
&stakingKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
appCodec, keys[distrtypes.StoreKey], app.GetSubspace(distrtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
|
||||
&stakingKeeper, authtypes.FeeCollectorName,
|
||||
)
|
||||
app.SlashingKeeper = slashingkeeper.NewKeeper(
|
||||
appCodec,
|
||||
keys[slashingtypes.StoreKey],
|
||||
&stakingKeeper,
|
||||
app.GetSubspace(slashingtypes.ModuleName),
|
||||
appCodec, keys[slashingtypes.StoreKey], &stakingKeeper, app.GetSubspace(slashingtypes.ModuleName),
|
||||
)
|
||||
app.CrisisKeeper = crisiskeeper.NewKeeper(
|
||||
app.GetSubspace(crisistypes.ModuleName),
|
||||
invCheckPeriod,
|
||||
app.BankKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
app.GetSubspace(crisistypes.ModuleName), invCheckPeriod, app.BankKeeper, authtypes.FeeCollectorName,
|
||||
)
|
||||
app.FeeGrantKeeper = feegrantkeeper.NewKeeper(
|
||||
appCodec,
|
||||
keys[feegrant.StoreKey],
|
||||
app.AccountKeeper)
|
||||
|
||||
// set the governance module account as the authority for conducting upgrades
|
||||
app.UpgradeKeeper = upgradekeeper.NewKeeper(
|
||||
skipUpgradeHeights,
|
||||
keys[upgradetypes.StoreKey],
|
||||
appCodec,
|
||||
homePath,
|
||||
app.BaseApp,
|
||||
authtypes.NewModuleAddress(govtypes.ModuleName).String())
|
||||
app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegrant.StoreKey], app.AccountKeeper)
|
||||
app.UpgradeKeeper = upgradekeeper.NewKeeper(skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp)
|
||||
|
||||
// register the staking hooks
|
||||
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
|
||||
app.StakingKeeper = *stakingKeeper.SetHooks(
|
||||
stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(),
|
||||
app.SlashingKeeper.Hooks()),
|
||||
stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()),
|
||||
)
|
||||
|
||||
app.AuthzKeeper = authzkeeper.NewKeeper(
|
||||
keys[authzkeeper.StoreKey],
|
||||
appCodec,
|
||||
app.MsgServiceRouter(),
|
||||
app.AccountKeeper)
|
||||
app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec,
|
||||
app.msgSvcRouter, app.AccountKeeper)
|
||||
|
||||
tracer := cast.ToString(appOpts.Get(srvflags.EVMTracer))
|
||||
|
||||
// Create Ethermint keepers
|
||||
app.FeeMarketKeeper = feemarketkeeper.NewKeeper(
|
||||
appCodec, app.GetSubspace(feemarkettypes.ModuleName), keys[feemarkettypes.StoreKey], tkeys[feemarkettypes.TransientKey],
|
||||
)
|
||||
|
||||
app.EvmKeeper = evmkeeper.NewKeeper(
|
||||
appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName),
|
||||
app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper,
|
||||
nil, geth.NewEVM, tracer,
|
||||
app.AccountKeeper, app.BankKeeper, app.StakingKeeper,
|
||||
tracer, bApp.Trace(), // debug EVM based on Baseapp options
|
||||
)
|
||||
|
||||
// Create laconic keepers
|
||||
app.FeeMarketKeeper = feemarketkeeper.NewKeeper(
|
||||
appCodec, keys[feemarkettypes.StoreKey], app.GetSubspace(feemarkettypes.ModuleName),
|
||||
)
|
||||
|
||||
// Create Vulcanize dxns keepers
|
||||
|
||||
app.AuctionKeeper = auctionkeeper.NewKeeper(
|
||||
app.AccountKeeper, app.BankKeeper, keys[auctiontypes.StoreKey],
|
||||
appCodec, app.GetSubspace(auctiontypes.ModuleName),
|
||||
)
|
||||
|
||||
app.RegistryRecordKeeper = registrykeeper.NewRecordKeeper(app.AuctionKeeper, keys[registrytypes.StoreKey], appCodec)
|
||||
app.NameServiceRecordKeeper = nameservicekeeper.NewRecordKeeper(app.AuctionKeeper, keys[nameservicetypes.StoreKey], appCodec)
|
||||
|
||||
app.AuctionKeeper.SetUsageKeepers([]auctiontypes.AuctionUsageKeeper{app.RegistryRecordKeeper})
|
||||
app.AuctionKeeper.SetUsageKeepers([]auctiontypes.AuctionUsageKeeper{app.NameServiceRecordKeeper})
|
||||
|
||||
app.BondKeeper = bondkeeper.NewKeeper(
|
||||
appCodec, app.AccountKeeper, app.BankKeeper,
|
||||
[]bondtypes.BondUsageKeeper{app.RegistryRecordKeeper}, keys[bondtypes.StoreKey], app.GetSubspace(bondtypes.ModuleName),
|
||||
[]bondtypes.BondUsageKeeper{app.NameServiceRecordKeeper}, keys[bondtypes.StoreKey], app.GetSubspace(bondtypes.ModuleName),
|
||||
)
|
||||
|
||||
app.RegistryKeeper = registrykeeper.NewKeeper(
|
||||
app.NameServiceKeeper = nameservicekeeper.NewKeeper(
|
||||
appCodec, app.AccountKeeper, app.BankKeeper,
|
||||
app.RegistryRecordKeeper, app.BondKeeper, app.AuctionKeeper,
|
||||
keys[registrytypes.StoreKey], app.GetSubspace(registrytypes.ModuleName),
|
||||
app.NameServiceRecordKeeper, app.BondKeeper, app.AuctionKeeper,
|
||||
keys[nameservicetypes.StoreKey], app.GetSubspace(nameservicetypes.ModuleName),
|
||||
)
|
||||
|
||||
// Create IBC Keeper
|
||||
@ -468,8 +457,7 @@ func NewEthermintApp(
|
||||
govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).
|
||||
AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).
|
||||
AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)).
|
||||
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)).
|
||||
AddRoute(ibchost.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper))
|
||||
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper))
|
||||
govConfig := govtypes.DefaultConfig()
|
||||
/*
|
||||
Example of setting gov params:
|
||||
@ -477,7 +465,7 @@ func NewEthermintApp(
|
||||
*/
|
||||
govKeeper := govkeeper.NewKeeper(
|
||||
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
|
||||
&stakingKeeper, govRouter, app.MsgServiceRouter(), govConfig,
|
||||
&stakingKeeper, govRouter, app.msgSvcRouter, govConfig,
|
||||
)
|
||||
|
||||
app.GovKeeper = *govKeeper.SetHooks(
|
||||
@ -489,15 +477,14 @@ func NewEthermintApp(
|
||||
// Create Transfer Keepers
|
||||
app.TransferKeeper = ibctransferkeeper.NewKeeper(
|
||||
appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName),
|
||||
app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper,
|
||||
app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper,
|
||||
app.AccountKeeper, app.BankKeeper, scopedTransferKeeper,
|
||||
)
|
||||
transferModule := transfer.NewAppModule(app.TransferKeeper)
|
||||
transferIBCModule := transfer.NewIBCModule(app.TransferKeeper)
|
||||
|
||||
// Create static IBC router, add transfer route, then set and seal it
|
||||
ibcRouter := porttypes.NewRouter()
|
||||
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferIBCModule)
|
||||
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule)
|
||||
app.IBCKeeper.SetRouter(ibcRouter)
|
||||
|
||||
// create evidence keeper with router
|
||||
@ -526,7 +513,6 @@ func NewEthermintApp(
|
||||
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
|
||||
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
|
||||
crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants),
|
||||
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
|
||||
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
|
||||
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil),
|
||||
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
|
||||
@ -535,6 +521,7 @@ func NewEthermintApp(
|
||||
upgrade.NewAppModule(app.UpgradeKeeper),
|
||||
evidence.NewAppModule(app.EvidenceKeeper),
|
||||
params.NewAppModule(app.ParamsKeeper),
|
||||
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
|
||||
authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
|
||||
|
||||
// ibc modules
|
||||
@ -543,158 +530,95 @@ func NewEthermintApp(
|
||||
// Ethermint app modules
|
||||
evm.NewAppModule(app.EvmKeeper, app.AccountKeeper),
|
||||
feemarket.NewAppModule(app.FeeMarketKeeper),
|
||||
// laconic modules
|
||||
// DXNs modules
|
||||
auction.NewAppModule(appCodec, app.AuctionKeeper),
|
||||
bond.NewAppModule(appCodec, app.BondKeeper),
|
||||
registry.NewAppModule(app.RegistryKeeper),
|
||||
nameservice.NewAppModule(app.NameServiceKeeper),
|
||||
)
|
||||
|
||||
// During begin block slashing happens after distr.BeginBlocker so that
|
||||
// there is nothing left over in the validator fee pool, so as to keep the
|
||||
// CanWithdrawInvariant invariant.
|
||||
// NOTE: upgrade module must go first to handle software upgrades.
|
||||
// NOTE: staking module is required if HistoricalEntries param > 0
|
||||
// NOTE: staking module is required if HistoricalEntries param > 0.
|
||||
// NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC)
|
||||
app.mm.SetOrderBeginBlockers(
|
||||
upgradetypes.ModuleName,
|
||||
capabilitytypes.ModuleName,
|
||||
feemarkettypes.ModuleName,
|
||||
evmtypes.ModuleName,
|
||||
minttypes.ModuleName,
|
||||
distrtypes.ModuleName,
|
||||
slashingtypes.ModuleName,
|
||||
evidencetypes.ModuleName,
|
||||
stakingtypes.ModuleName,
|
||||
ibchost.ModuleName,
|
||||
// no-op modules
|
||||
ibctransfertypes.ModuleName,
|
||||
authtypes.ModuleName,
|
||||
banktypes.ModuleName,
|
||||
govtypes.ModuleName,
|
||||
crisistypes.ModuleName,
|
||||
genutiltypes.ModuleName,
|
||||
authz.ModuleName,
|
||||
feegrant.ModuleName,
|
||||
paramstypes.ModuleName,
|
||||
vestingtypes.ModuleName,
|
||||
// laconic modules
|
||||
auctiontypes.ModuleName,
|
||||
bondtypes.ModuleName,
|
||||
registrytypes.ModuleName,
|
||||
minttypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName,
|
||||
evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName,
|
||||
)
|
||||
|
||||
// NOTE: fee market module must go last in order to retrieve the block gas used.
|
||||
app.mm.SetOrderEndBlockers(
|
||||
crisistypes.ModuleName,
|
||||
govtypes.ModuleName,
|
||||
stakingtypes.ModuleName,
|
||||
evmtypes.ModuleName,
|
||||
feemarkettypes.ModuleName,
|
||||
// no-op modules
|
||||
ibchost.ModuleName,
|
||||
ibctransfertypes.ModuleName,
|
||||
capabilitytypes.ModuleName,
|
||||
authtypes.ModuleName,
|
||||
banktypes.ModuleName,
|
||||
distrtypes.ModuleName,
|
||||
slashingtypes.ModuleName,
|
||||
minttypes.ModuleName,
|
||||
genutiltypes.ModuleName,
|
||||
evidencetypes.ModuleName,
|
||||
authz.ModuleName,
|
||||
feegrant.ModuleName,
|
||||
paramstypes.ModuleName,
|
||||
upgradetypes.ModuleName,
|
||||
vestingtypes.ModuleName,
|
||||
// laconic modules
|
||||
crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName,
|
||||
evmtypes.ModuleName, feemarkettypes.ModuleName,
|
||||
nameservicetypes.ModuleName,
|
||||
auctiontypes.ModuleName,
|
||||
bondtypes.ModuleName,
|
||||
registrytypes.ModuleName,
|
||||
)
|
||||
|
||||
// NOTE: The genutils module must occur after staking so that pools are
|
||||
// properly initialized with tokens from genesis accounts.
|
||||
// NOTE: The genutils module must also occur after auth so that it can access the params from auth.
|
||||
// NOTE: Capability module must occur first so that it can initialize any capabilities
|
||||
// so that other modules that want to create or claim capabilities afterwards in InitChain
|
||||
// can do so safely.
|
||||
app.mm.SetOrderInitGenesis(
|
||||
// SDK modules
|
||||
capabilitytypes.ModuleName,
|
||||
authtypes.ModuleName,
|
||||
banktypes.ModuleName,
|
||||
distrtypes.ModuleName,
|
||||
stakingtypes.ModuleName,
|
||||
slashingtypes.ModuleName,
|
||||
govtypes.ModuleName,
|
||||
minttypes.ModuleName,
|
||||
ibchost.ModuleName,
|
||||
// evm module denomination is used by the feemarket module, in AnteHandle
|
||||
evmtypes.ModuleName,
|
||||
// NOTE: feemarket need to be initialized before genutil module:
|
||||
// gentx transactions use MinGasPriceDecorator.AnteHandle
|
||||
feemarkettypes.ModuleName,
|
||||
genutiltypes.ModuleName,
|
||||
evidencetypes.ModuleName,
|
||||
ibctransfertypes.ModuleName,
|
||||
authz.ModuleName,
|
||||
feegrant.ModuleName,
|
||||
paramstypes.ModuleName,
|
||||
upgradetypes.ModuleName,
|
||||
vestingtypes.ModuleName,
|
||||
// laconic modules
|
||||
capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName,
|
||||
slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName,
|
||||
ibchost.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName,
|
||||
authz.ModuleName, feegrant.ModuleName,
|
||||
// Ethermint modules
|
||||
evmtypes.ModuleName, feemarkettypes.ModuleName,
|
||||
// DXNS modules
|
||||
auctiontypes.ModuleName,
|
||||
bondtypes.ModuleName,
|
||||
registrytypes.ModuleName,
|
||||
nameservicetypes.ModuleName,
|
||||
|
||||
// NOTE: crisis module must go at the end to check for invariants on each module
|
||||
crisistypes.ModuleName,
|
||||
)
|
||||
|
||||
// Uncomment if you want to set a custom migration order here.
|
||||
// app.mm.SetOrderMigrations(custom order)
|
||||
|
||||
app.mm.RegisterInvariants(&app.CrisisKeeper)
|
||||
app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino)
|
||||
app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter())
|
||||
app.mm.RegisterRoutes(app.legacyRouter, app.QueryRouter(), encodingConfig.Amino)
|
||||
app.configurator = module.NewConfigurator(app.appCodec, app.msgSvcRouter, app.GRPCQueryRouter())
|
||||
app.mm.RegisterServices(app.configurator)
|
||||
|
||||
// RegisterUpgradeHandlers is used for registering any on-chain upgrades.
|
||||
// Make sure it's called after `app.mm` and `app.configurator` are set.
|
||||
app.RegisterUpgradeHandlers()
|
||||
|
||||
// add test gRPC service for testing gRPC queries in isolation
|
||||
// testdata.RegisterTestServiceServer(app.GRPCQueryRouter(), testdata.TestServiceImpl{})
|
||||
|
||||
// initialize stores
|
||||
app.MountKVStores(keys)
|
||||
app.MountTransientStores(tkeys)
|
||||
app.MountMemoryStores(memKeys)
|
||||
// create the simulation manager and define the order of the modules for deterministic simulations
|
||||
|
||||
// NOTE: this is not required apps that don't use the simulator for fuzz testing
|
||||
// transactions
|
||||
app.sm = module.NewSimulationManager(
|
||||
auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
|
||||
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
|
||||
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
|
||||
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
|
||||
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil),
|
||||
staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
|
||||
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
|
||||
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
|
||||
params.NewAppModule(app.ParamsKeeper),
|
||||
evidence.NewAppModule(app.EvidenceKeeper),
|
||||
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
|
||||
authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
|
||||
ibc.NewAppModule(app.IBCKeeper),
|
||||
transferModule,
|
||||
)
|
||||
|
||||
app.sm.RegisterStoreDecoders()
|
||||
|
||||
// initialize BaseApp
|
||||
app.SetInitChainer(app.InitChainer)
|
||||
app.SetBeginBlocker(app.BeginBlocker)
|
||||
app.SetEndBlocker(app.EndBlocker)
|
||||
app.setAnteHandler(encodingConfig.TxConfig, cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted)))
|
||||
// In v0.46, the SDK introduces _postHandlers_. PostHandlers are like
|
||||
// antehandlers, but are run _after_ the `runMsgs` execution. They are also
|
||||
// defined as a chain, and have the same signature as antehandlers.
|
||||
//
|
||||
// In baseapp, postHandlers are run in the same store branch as `runMsgs`,
|
||||
// meaning that both `runMsgs` and `postHandler` state will be committed if
|
||||
// both are successful, and both will be reverted if any of the two fails.
|
||||
//
|
||||
// The SDK exposes a default empty postHandlers chain.
|
||||
//
|
||||
// Please note that changing any of the anteHandler or postHandler chain is
|
||||
// likely to be a state-machine breaking change, which needs a coordinated
|
||||
// upgrade.
|
||||
app.setPostHandler()
|
||||
|
||||
if loadLatest {
|
||||
if err := app.LoadLatestVersion(); err != nil {
|
||||
tmos.Exit(err.Error())
|
||||
}
|
||||
}
|
||||
// TODO: use Ethermint's custom AnteHandler
|
||||
app.setTxHandler(encodingConfig.TxConfig, cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents)))
|
||||
|
||||
app.SetEndBlocker(app.EndBlocker)
|
||||
|
||||
app.ScopedIBCKeeper = scopedIBCKeeper
|
||||
app.ScopedTransferKeeper = scopedTransferKeeper
|
||||
@ -702,37 +626,37 @@ func NewEthermintApp(
|
||||
return app
|
||||
}
|
||||
|
||||
// use Ethermint's custom AnteHandler
|
||||
func (app *EthermintApp) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64) {
|
||||
anteHandler, err := ante.NewAnteHandler(ante.HandlerOptions{
|
||||
AccountKeeper: app.AccountKeeper,
|
||||
BankKeeper: app.BankKeeper,
|
||||
SignModeHandler: txConfig.SignModeHandler(),
|
||||
FeegrantKeeper: app.FeeGrantKeeper,
|
||||
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||
IBCKeeper: app.IBCKeeper,
|
||||
EvmKeeper: app.EvmKeeper,
|
||||
FeeMarketKeeper: app.FeeMarketKeeper,
|
||||
MaxTxGasWanted: maxGasWanted,
|
||||
ExtensionOptionChecker: ethermint.HasDynamicFeeExtensionOption,
|
||||
// TxFeeChecker: ante.NewDynamicFeeChecker(app.EvmKeeper),
|
||||
func (app *EthermintApp) setTxHandler(txConfig client.TxConfig, indexEventsStr []string) {
|
||||
indexEvents := map[string]struct{}{}
|
||||
for _, e := range indexEventsStr {
|
||||
indexEvents[e] = struct{}{}
|
||||
}
|
||||
// need to sub in custom tx handler
|
||||
/*
|
||||
app.SetTxHandler(
|
||||
ante.NewAnteHandler(
|
||||
app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.FeeGrantKeeper, app.IBCKeeper.ChannelKeeper,
|
||||
encodingConfig.TxConfig.SignModeHandler(),
|
||||
),
|
||||
)
|
||||
*/
|
||||
txHandler, err := middleware.NewDefaultTxHandler(middleware.TxHandlerOptions{
|
||||
Debug: app.Trace(),
|
||||
IndexEvents: indexEvents,
|
||||
LegacyRouter: app.legacyRouter,
|
||||
MsgServiceRouter: app.msgSvcRouter,
|
||||
AccountKeeper: app.AccountKeeper,
|
||||
BankKeeper: app.BankKeeper,
|
||||
FeegrantKeeper: app.FeeGrantKeeper,
|
||||
SignModeHandler: txConfig.SignModeHandler(),
|
||||
SigGasConsumer: middleware.DefaultSigVerificationGasConsumer,
|
||||
TxDecoder: txConfig.TxDecoder(),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
app.SetAnteHandler(anteHandler)
|
||||
}
|
||||
|
||||
func (app *EthermintApp) setPostHandler() {
|
||||
postHandler, err := posthandler.NewPostHandler(
|
||||
posthandler.HandlerOptions{},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
app.SetPostHandler(postHandler)
|
||||
app.SetTxHandler(txHandler)
|
||||
}
|
||||
|
||||
// Name returns the name of the App
|
||||
@ -760,13 +684,12 @@ func (app *EthermintApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain)
|
||||
|
||||
// LoadHeight loads state at a particular height
|
||||
func (app *EthermintApp) LoadHeight(height int64) error {
|
||||
return app.LoadVersion(height)
|
||||
return errors.New("cannot load arbitrary height")
|
||||
}
|
||||
|
||||
// ModuleAccountAddrs returns all the app's module account addresses.
|
||||
func (app *EthermintApp) ModuleAccountAddrs() map[string]bool {
|
||||
modAccAddrs := make(map[string]bool)
|
||||
// #nosec G705
|
||||
for acc := range maccPerms {
|
||||
modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true
|
||||
}
|
||||
@ -778,7 +701,6 @@ func (app *EthermintApp) ModuleAccountAddrs() map[string]bool {
|
||||
// allowed to receive external tokens.
|
||||
func (app *EthermintApp) BlockedAddrs() map[string]bool {
|
||||
blockedAddrs := make(map[string]bool)
|
||||
// #nosec G705
|
||||
for acc := range maccPerms {
|
||||
blockedAddrs[authtypes.NewModuleAddress(acc).String()] = !allowedReceivingModAcc[acc]
|
||||
}
|
||||
@ -810,21 +732,21 @@ func (app *EthermintApp) InterfaceRegistry() types.InterfaceRegistry {
|
||||
// GetKey returns the KVStoreKey for the provided store key.
|
||||
//
|
||||
// NOTE: This is solely to be used for testing purposes.
|
||||
func (app *EthermintApp) GetKey(storeKey string) *storetypes.KVStoreKey {
|
||||
func (app *EthermintApp) GetKey(storeKey string) *types3.KVStoreKey {
|
||||
return app.keys[storeKey]
|
||||
}
|
||||
|
||||
// GetTKey returns the TransientStoreKey for the provided store key.
|
||||
//
|
||||
// NOTE: This is solely to be used for testing purposes.
|
||||
func (app *EthermintApp) GetTKey(storeKey string) *storetypes.TransientStoreKey {
|
||||
func (app *EthermintApp) GetTKey(storeKey string) *types3.TransientStoreKey {
|
||||
return app.tkeys[storeKey]
|
||||
}
|
||||
|
||||
// GetMemKey returns the MemStoreKey for the provided mem key.
|
||||
//
|
||||
// NOTE: This is solely used for testing purposes.
|
||||
func (app *EthermintApp) GetMemKey(storeKey string) *storetypes.MemoryStoreKey {
|
||||
func (app *EthermintApp) GetMemKey(storeKey string) *types3.MemoryStoreKey {
|
||||
return app.memKeys[storeKey]
|
||||
}
|
||||
|
||||
@ -836,18 +758,25 @@ func (app *EthermintApp) GetSubspace(moduleName string) paramstypes.Subspace {
|
||||
return subspace
|
||||
}
|
||||
|
||||
// SimulationManager implements the SimulationApp interface
|
||||
func (app *EthermintApp) SimulationManager() *module.SimulationManager {
|
||||
return app.sm
|
||||
}
|
||||
|
||||
// RegisterAPIRoutes registers all application module routes with the provided
|
||||
// API server.
|
||||
func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
|
||||
clientCtx := apiSvr.ClientCtx
|
||||
|
||||
evmrest.RegisterTxRoutes(clientCtx, apiSvr.Router)
|
||||
|
||||
// Register new tx routes from grpc-gateway.
|
||||
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
||||
// Register new tendermint queries routes from grpc-gateway.
|
||||
tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
||||
// Register node gRPC service for grpc-gateway.
|
||||
node.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
||||
|
||||
// Register grpc-gateway routes for all modules.
|
||||
// Register legacy and grpc-gateway routes for all modules.
|
||||
ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router)
|
||||
ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
||||
|
||||
// register swagger API from root so that other applications can override easily
|
||||
@ -856,25 +785,12 @@ func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterTxService implements the Application.RegisterTxService method.
|
||||
func (app *EthermintApp) RegisterTxService(clientCtx client.Context) {
|
||||
authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry)
|
||||
}
|
||||
|
||||
// RegisterTendermintService implements the Application.RegisterTendermintService method.
|
||||
func (app *EthermintApp) RegisterTendermintService(clientCtx client.Context) {
|
||||
tmservice.RegisterTendermintService(
|
||||
clientCtx,
|
||||
app.BaseApp.GRPCQueryRouter(),
|
||||
app.interfaceRegistry,
|
||||
app.Query,
|
||||
)
|
||||
}
|
||||
|
||||
// RegisterNodeService registers the node gRPC service on the provided
|
||||
// application gRPC query router.
|
||||
func (app *EthermintApp) RegisterNodeService(clientCtx client.Context) {
|
||||
node.RegisterNodeService(clientCtx, app.GRPCQueryRouter())
|
||||
tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry)
|
||||
}
|
||||
|
||||
// RegisterSwaggerAPI registers swagger route with API Server
|
||||
@ -894,11 +810,13 @@ func GetMaccPerms() map[string][]string {
|
||||
for k, v := range maccPerms {
|
||||
dupMaccPerms[k] = v
|
||||
}
|
||||
|
||||
return dupMaccPerms
|
||||
}
|
||||
|
||||
// initParamsKeeper init params keeper and its subspaces
|
||||
func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper {
|
||||
func initParamsKeeper(
|
||||
appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey types3.StoreKey) paramskeeper.Keeper {
|
||||
paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey)
|
||||
|
||||
// SDK subspaces
|
||||
@ -908,16 +826,17 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino
|
||||
paramsKeeper.Subspace(minttypes.ModuleName)
|
||||
paramsKeeper.Subspace(distrtypes.ModuleName)
|
||||
paramsKeeper.Subspace(slashingtypes.ModuleName)
|
||||
paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1.ParamKeyTable())
|
||||
paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1beta2.ParamKeyTable())
|
||||
paramsKeeper.Subspace(crisistypes.ModuleName)
|
||||
paramsKeeper.Subspace(ibctransfertypes.ModuleName)
|
||||
paramsKeeper.Subspace(ibchost.ModuleName)
|
||||
// ethermint subspaces
|
||||
paramsKeeper.Subspace(evmtypes.ModuleName)
|
||||
paramsKeeper.Subspace(feemarkettypes.ModuleName)
|
||||
// laconic subspaces
|
||||
// dxns subspaces
|
||||
paramsKeeper.Subspace(auctiontypes.ModuleName)
|
||||
paramsKeeper.Subspace(bondtypes.ModuleName)
|
||||
paramsKeeper.Subspace(registrytypes.ModuleName)
|
||||
paramsKeeper.Subspace(nameservicetypes.ModuleName)
|
||||
|
||||
return paramsKeeper
|
||||
}
|
||||
|
@ -1,26 +1,49 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"os"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/db/memdb"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
"github.com/tharsis/ethermint/encoding"
|
||||
)
|
||||
|
||||
func TestEthermintAppExport(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
app := SetupWithDB(false, nil, db)
|
||||
db := memdb.NewDB()
|
||||
logger, err := log.NewDefaultLogger("plain", "info", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
|
||||
genesisState := NewDefaultGenesisState()
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Initialize the chain
|
||||
app.InitChain(
|
||||
abci.RequestInitChain{
|
||||
ChainId: "ethermint_9000-1",
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
AppStateBytes: stateBytes,
|
||||
},
|
||||
)
|
||||
app.Commit()
|
||||
|
||||
// Making a new app object with the db, so that initchain hasn't been called
|
||||
app2 := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
_, err := app2.ExportAppStateAndValidators(false, []string{})
|
||||
logger, err = log.NewDefaultLogger("plain", "info", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
app2 := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
_, err = app2.ExportAppStateAndValidators(false, []string{})
|
||||
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
||||
}
|
||||
|
@ -2,21 +2,20 @@ package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
"github.com/cosmos/cosmos-sdk/db/memdb"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
"github.com/tharsis/ethermint/encoding"
|
||||
)
|
||||
|
||||
func BenchmarkEthermintApp_ExportAppStateAndValidators(b *testing.B) {
|
||||
db := dbm.NewMemDB()
|
||||
app := NewEthermintApp(log.NewTMLogger(io.Discard), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
db := memdb.NewDB()
|
||||
app := NewEthermintApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
|
||||
genesisState := NewTestGenesisState(app.AppCodec())
|
||||
genesisState := NewDefaultGenesisState()
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
@ -36,7 +35,7 @@ func BenchmarkEthermintApp_ExportAppStateAndValidators(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Making a new app object with the db, so that initchain hasn't been called
|
||||
app2 := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(io.Discard)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
app2 := NewEthermintApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
if _, err := app2.ExportAppStateAndValidators(false, []string{}); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
"github.com/tharsis/ethermint/encoding"
|
||||
)
|
||||
|
||||
// NewDefaultGenesisState generates the default state for the application.
|
||||
@ -62,7 +62,7 @@ func (app *EthermintApp) ExportAppStateAndValidators(
|
||||
|
||||
// prepare for fresh start at zero height
|
||||
// NOTE zero height genesis is a temporary feature which will be deprecated
|
||||
// in favor of export at a block height
|
||||
// in favor of export at a block height
|
||||
func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) error {
|
||||
applyAllowedAddrs := false
|
||||
|
||||
@ -125,9 +125,7 @@ func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAd
|
||||
feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
|
||||
app.DistrKeeper.SetFeePool(ctx, feePool)
|
||||
|
||||
if err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()); err != nil {
|
||||
return true
|
||||
}
|
||||
app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator())
|
||||
return false
|
||||
})
|
||||
|
||||
@ -141,12 +139,8 @@ func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAd
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr)
|
||||
app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr)
|
||||
}
|
||||
|
||||
// reset context height
|
||||
@ -176,6 +170,7 @@ func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAd
|
||||
// update bond intra-tx counters.
|
||||
store := ctx.KVStore(app.keys[stakingtypes.StoreKey])
|
||||
iter := sdk.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey)
|
||||
counter := int16(0)
|
||||
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key()))
|
||||
@ -190,11 +185,10 @@ func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAd
|
||||
}
|
||||
|
||||
app.StakingKeeper.SetValidator(ctx, validator)
|
||||
counter++
|
||||
}
|
||||
|
||||
if err := iter.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
iter.Close()
|
||||
|
||||
if _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx); err != nil {
|
||||
return err
|
||||
|
340
app/simulation_test.go
Normal file
340
app/simulation_test.go
Normal file
@ -0,0 +1,340 @@
|
||||
package app
|
||||
|
||||
// disable for now, enable it once SDK side fix the simulator issue for custom keys
|
||||
//import (
|
||||
// "encoding/json"
|
||||
// "fmt"
|
||||
// "math/rand"
|
||||
// "os"
|
||||
// "testing"
|
||||
//
|
||||
// "github.com/stretchr/testify/require"
|
||||
//
|
||||
// abci "github.com/tendermint/tendermint/abci/types"
|
||||
// "github.com/tendermint/tendermint/libs/log"
|
||||
// tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
// dbm "github.com/tendermint/tm-db"
|
||||
//
|
||||
// "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
// "github.com/cosmos/cosmos-sdk/simapp"
|
||||
// "github.com/cosmos/cosmos-sdk/simapp/helpers"
|
||||
// "github.com/cosmos/cosmos-sdk/store"
|
||||
// sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
// simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
// authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
// banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
// capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
|
||||
// distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
// evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
|
||||
// govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
// ibctransfertypes "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
|
||||
// ibchost "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
|
||||
// minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||
// paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
|
||||
// "github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
// slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
|
||||
// stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
//)
|
||||
//
|
||||
//func init() {
|
||||
// simapp.GetSimulatorFlags()
|
||||
//}
|
||||
//
|
||||
//type storeKeysPrefixes struct {
|
||||
// A sdk.StoreKey
|
||||
// B sdk.StoreKey
|
||||
// Prefixes [][]byte
|
||||
//}
|
||||
//
|
||||
//// fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
|
||||
//// an IAVLStore for faster simulation speed.
|
||||
//func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
|
||||
// bapp.SetFauxMerkleMode()
|
||||
//}
|
||||
//
|
||||
//// interBlockCacheOpt returns a BaseApp option function that sets the persistent
|
||||
//// inter-block write-through cache.
|
||||
//func interBlockCacheOpt() func(*baseapp.BaseApp) {
|
||||
// return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager())
|
||||
//}
|
||||
//
|
||||
//func TestFullAppSimulation(t *testing.T) {
|
||||
// config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
|
||||
// if skip {
|
||||
// t.Skip("skipping application simulation")
|
||||
// }
|
||||
// require.NoError(t, err, "simulation setup failed")
|
||||
//
|
||||
// defer func() {
|
||||
// db.Close()
|
||||
// require.NoError(t, os.RemoveAll(dir))
|
||||
// }()
|
||||
//
|
||||
// app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
||||
// require.Equal(t, appName, app.Name())
|
||||
//
|
||||
// // run randomized simulation
|
||||
// _, simParams, simErr := simulation.SimulateFromSeed(
|
||||
// t,
|
||||
// os.Stdout,
|
||||
// app.BaseApp,
|
||||
// simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
||||
// simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
// simapp.SimulationOperations(app, app.AppCodec(), config),
|
||||
// app.ModuleAccountAddrs(),
|
||||
// config,
|
||||
// app.AppCodec(),
|
||||
// )
|
||||
//
|
||||
// // export state and simParams before the simulation error is checked
|
||||
// err = simapp.CheckExportSimulation(app, config, simParams)
|
||||
// require.NoError(t, err)
|
||||
// require.NoError(t, simErr)
|
||||
//
|
||||
// if config.Commit {
|
||||
// simapp.PrintStats(db)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func TestAppImportExport(t *testing.T) {
|
||||
// config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
|
||||
// if skip {
|
||||
// t.Skip("skipping application import/export simulation")
|
||||
// }
|
||||
// require.NoError(t, err, "simulation setup failed")
|
||||
//
|
||||
// defer func() {
|
||||
// db.Close()
|
||||
// require.NoError(t, os.RemoveAll(dir))
|
||||
// }()
|
||||
//
|
||||
// app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
||||
// require.Equal(t, appName, app.Name())
|
||||
//
|
||||
// // Run randomized simulation
|
||||
// _, simParams, simErr := simulation.SimulateFromSeed(
|
||||
// t,
|
||||
// os.Stdout,
|
||||
// app.BaseApp,
|
||||
// simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
||||
// simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
// simapp.SimulationOperations(app, app.AppCodec(), config),
|
||||
// app.ModuleAccountAddrs(),
|
||||
// config,
|
||||
// app.AppCodec(),
|
||||
// )
|
||||
//
|
||||
// // export state and simParams before the simulation error is checked
|
||||
// err = simapp.CheckExportSimulation(app, config, simParams)
|
||||
// require.NoError(t, err)
|
||||
// require.NoError(t, simErr)
|
||||
//
|
||||
// if config.Commit {
|
||||
// simapp.PrintStats(db)
|
||||
// }
|
||||
//
|
||||
// fmt.Printf("exporting genesis...\n")
|
||||
//
|
||||
// exported, err := app.ExportAppStateAndValidators(false, []string{})
|
||||
// require.NoError(t, err)
|
||||
//
|
||||
// fmt.Printf("importing genesis...\n")
|
||||
//
|
||||
// // nolint: dogsled
|
||||
// _, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2")
|
||||
// require.NoError(t, err, "simulation setup failed")
|
||||
//
|
||||
// defer func() {
|
||||
// newDB.Close()
|
||||
// require.NoError(t, os.RemoveAll(newDir))
|
||||
// }()
|
||||
//
|
||||
// newApp := NewEthermintApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
||||
// require.Equal(t, appName, newApp.Name())
|
||||
//
|
||||
// var genesisState simapp.GenesisState
|
||||
// err = json.Unmarshal(exported.AppState, &genesisState)
|
||||
// require.NoError(t, err)
|
||||
//
|
||||
// ctxA := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
|
||||
// ctxB := newApp.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
|
||||
// newApp.mm.InitGenesis(ctxB, app.AppCodec(), genesisState)
|
||||
// newApp.StoreConsensusParams(ctxB, exported.ConsensusParams)
|
||||
//
|
||||
// fmt.Printf("comparing stores...\n")
|
||||
//
|
||||
// storeKeysPrefixes := []storeKeysPrefixes{
|
||||
// {app.keys[authtypes.StoreKey], newApp.keys[authtypes.StoreKey], [][]byte{}},
|
||||
// {app.keys[stakingtypes.StoreKey], newApp.keys[stakingtypes.StoreKey],
|
||||
// [][]byte{
|
||||
// stakingtypes.UnbondingQueueKey, stakingtypes.RedelegationQueueKey, stakingtypes.ValidatorQueueKey,
|
||||
// stakingtypes.HistoricalInfoKey,
|
||||
// }}, // ordering may change but it doesn't matter
|
||||
// {app.keys[slashingtypes.StoreKey], newApp.keys[slashingtypes.StoreKey], [][]byte{}},
|
||||
// {app.keys[minttypes.StoreKey], newApp.keys[minttypes.StoreKey], [][]byte{}},
|
||||
// {app.keys[distrtypes.StoreKey], newApp.keys[distrtypes.StoreKey], [][]byte{}},
|
||||
// {app.keys[banktypes.StoreKey], newApp.keys[banktypes.StoreKey], [][]byte{banktypes.BalancesPrefix}},
|
||||
// {app.keys[paramtypes.StoreKey], newApp.keys[paramtypes.StoreKey], [][]byte{}},
|
||||
// {app.keys[govtypes.StoreKey], newApp.keys[govtypes.StoreKey], [][]byte{}},
|
||||
// {app.keys[evidencetypes.StoreKey], newApp.keys[evidencetypes.StoreKey], [][]byte{}},
|
||||
// {app.keys[capabilitytypes.StoreKey], newApp.keys[capabilitytypes.StoreKey], [][]byte{}},
|
||||
// {app.keys[ibchost.StoreKey], newApp.keys[ibchost.StoreKey], [][]byte{}},
|
||||
// {app.keys[ibctransfertypes.StoreKey], newApp.keys[ibctransfertypes.StoreKey], [][]byte{}},
|
||||
// }
|
||||
//
|
||||
// for _, skp := range storeKeysPrefixes {
|
||||
// storeA := ctxA.KVStore(skp.A)
|
||||
// storeB := ctxB.KVStore(skp.B)
|
||||
//
|
||||
// failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes)
|
||||
// require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare")
|
||||
//
|
||||
// fmt.Printf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B)
|
||||
// require.Equal(t, len(failedKVAs), 0, simapp.GetSimulationLog(skp.A.Name(), app.SimulationManager().StoreDecoders, failedKVAs, failedKVBs))
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//func TestAppSimulationAfterImport(t *testing.T) {
|
||||
// config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
|
||||
// if skip {
|
||||
// t.Skip("skipping application simulation after import")
|
||||
// }
|
||||
// require.NoError(t, err, "simulation setup failed")
|
||||
//
|
||||
// defer func() {
|
||||
// db.Close()
|
||||
// require.NoError(t, os.RemoveAll(dir))
|
||||
// }()
|
||||
//
|
||||
// app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
||||
// require.Equal(t, appName, app.Name())
|
||||
//
|
||||
// // Run randomized simulation
|
||||
// stopEarly, simParams, simErr := simulation.SimulateFromSeed(
|
||||
// t,
|
||||
// os.Stdout,
|
||||
// app.BaseApp,
|
||||
// simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
||||
// simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
// simapp.SimulationOperations(app, app.AppCodec(), config),
|
||||
// app.ModuleAccountAddrs(),
|
||||
// config,
|
||||
// app.AppCodec(),
|
||||
// )
|
||||
//
|
||||
// // export state and simParams before the simulation error is checked
|
||||
// err = simapp.CheckExportSimulation(app, config, simParams)
|
||||
// require.NoError(t, err)
|
||||
// require.NoError(t, simErr)
|
||||
//
|
||||
// if config.Commit {
|
||||
// simapp.PrintStats(db)
|
||||
// }
|
||||
//
|
||||
// if stopEarly {
|
||||
// fmt.Println("can't export or import a zero-validator genesis, exiting test...")
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// fmt.Printf("exporting genesis...\n")
|
||||
//
|
||||
// exported, err := app.ExportAppStateAndValidators(true, []string{})
|
||||
// require.NoError(t, err)
|
||||
//
|
||||
// fmt.Printf("importing genesis...\n")
|
||||
//
|
||||
// _, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2")
|
||||
// require.NoError(t, err, "simulation setup failed")
|
||||
//
|
||||
// defer func() {
|
||||
// newDB.Close()
|
||||
// require.NoError(t, os.RemoveAll(newDir))
|
||||
// }()
|
||||
//
|
||||
// newApp := NewEthermintApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
||||
// require.Equal(t, appName, newApp.Name())
|
||||
//
|
||||
// newApp.InitChain(abci.RequestInitChain{
|
||||
// AppStateBytes: exported.AppState,
|
||||
// })
|
||||
//
|
||||
// _, _, err = simulation.SimulateFromSeed(
|
||||
// t,
|
||||
// os.Stdout,
|
||||
// newApp.BaseApp,
|
||||
// simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
||||
// simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
// simapp.SimulationOperations(newApp, newApp.AppCodec(), config),
|
||||
// app.ModuleAccountAddrs(),
|
||||
// config,
|
||||
// app.AppCodec(),
|
||||
// )
|
||||
// require.NoError(t, err)
|
||||
//}
|
||||
//
|
||||
//// TODO: Make another test for the fuzzer itself, which just has noOp txs
|
||||
//// and doesn't depend on the application.
|
||||
//func TestAppStateDeterminism(t *testing.T) {
|
||||
// if !simapp.FlagEnabledValue {
|
||||
// t.Skip("skipping application simulation")
|
||||
// }
|
||||
//
|
||||
// config := simapp.NewConfigFromFlags()
|
||||
// config.InitialBlockHeight = 1
|
||||
// config.ExportParamsPath = ""
|
||||
// config.OnOperation = false
|
||||
// config.AllInvariants = false
|
||||
// config.ChainID = helpers.SimAppChainID
|
||||
//
|
||||
// numSeeds := 3
|
||||
// numTimesToRunPerSeed := 5
|
||||
// appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
|
||||
//
|
||||
// for i := 0; i < numSeeds; i++ {
|
||||
// config.Seed = rand.Int63()
|
||||
//
|
||||
// for j := 0; j < numTimesToRunPerSeed; j++ {
|
||||
// var logger log.Logger
|
||||
// if simapp.FlagVerboseValue {
|
||||
// logger = log.TestingLogger()
|
||||
// } else {
|
||||
// logger = log.NewNopLogger()
|
||||
// }
|
||||
//
|
||||
// db := dbm.NewMemDB()
|
||||
// app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, interBlockCacheOpt())
|
||||
//
|
||||
// fmt.Printf(
|
||||
// "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n",
|
||||
// config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
|
||||
// )
|
||||
//
|
||||
// _, _, err := simulation.SimulateFromSeed(
|
||||
// t,
|
||||
// os.Stdout,
|
||||
// app.BaseApp,
|
||||
// simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
||||
// simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
// simapp.SimulationOperations(app, app.AppCodec(), config),
|
||||
// app.ModuleAccountAddrs(),
|
||||
// config,
|
||||
// app.AppCodec(),
|
||||
// )
|
||||
// require.NoError(t, err)
|
||||
//
|
||||
// if config.Commit {
|
||||
// simapp.PrintStats(db)
|
||||
// }
|
||||
//
|
||||
// appHash := app.LastCommitID().Hash
|
||||
// appHashList[j] = appHash
|
||||
//
|
||||
// if j != 0 {
|
||||
// require.Equal(
|
||||
// t, string(appHashList[0]), string(appHashList[j]),
|
||||
// "non-determinism in seed %d: %d/%d, attempt: %d/%d\n", config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
75
app/test_helpers.go
Normal file
75
app/test_helpers.go
Normal file
@ -0,0 +1,75 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/db/memdb"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/tharsis/ethermint/encoding"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// DefaultConsensusParams defines the default Tendermint consensus params used in
|
||||
// EthermintApp testing.
|
||||
var DefaultConsensusParams = &tmproto.ConsensusParams{
|
||||
Block: &tmproto.BlockParams{
|
||||
MaxBytes: 200000,
|
||||
MaxGas: -1, // no limit
|
||||
},
|
||||
Evidence: &tmproto.EvidenceParams{
|
||||
MaxAgeNumBlocks: 302400,
|
||||
MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration
|
||||
MaxBytes: 10000,
|
||||
},
|
||||
Validator: &tmproto.ValidatorParams{
|
||||
PubKeyTypes: []string{
|
||||
tmtypes.ABCIPubKeyTypeEd25519,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Setup initializes a new EthermintApp. A Nop logger is set in EthermintApp.
|
||||
func Setup(isCheckTx bool) *EthermintApp {
|
||||
db := memdb.NewDB()
|
||||
app := NewEthermintApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
if !isCheckTx {
|
||||
// init chain must be called to stop deliverState from being nil
|
||||
genesisState := NewDefaultGenesisState()
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Initialize the chain
|
||||
app.InitChain(
|
||||
abci.RequestInitChain{
|
||||
ChainId: "ethermint_9000-1",
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
ConsensusParams: DefaultConsensusParams,
|
||||
AppStateBytes: stateBytes,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// CreateRandomAccounts will generate random accounts
|
||||
func CreateRandomAccounts(accNum int) []sdk.AccAddress {
|
||||
// createRandomAccounts is a strategy used by addTestAddrs() in order to generated addresses in random order.
|
||||
testAddrs := make([]sdk.AccAddress, accNum)
|
||||
for i := 0; i < accNum; i++ {
|
||||
pk := ed25519.GenPrivKey().PubKey()
|
||||
testAddrs[i] = sdk.AccAddress(pk.Address())
|
||||
}
|
||||
|
||||
return testAddrs
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
)
|
||||
|
||||
func (app *EthermintApp) RegisterUpgradeHandlers() {
|
||||
planName := "integration-test-upgrade"
|
||||
app.UpgradeKeeper.SetUpgradeHandler(planName, func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
|
||||
return app.mm.RunMigrations(ctx, app.configurator, fromVM)
|
||||
})
|
||||
}
|
201
app/utils.go
201
app/utils.go
@ -1,201 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand" // #nosec G702
|
||||
"time"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/mock"
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
)
|
||||
|
||||
// DefaultConsensusParams defines the default Tendermint consensus params used in
|
||||
// EthermintApp testing.
|
||||
var DefaultConsensusParams = &abci.ConsensusParams{
|
||||
Block: &abci.BlockParams{
|
||||
MaxBytes: 200000,
|
||||
MaxGas: -1, // no limit
|
||||
},
|
||||
Evidence: &tmproto.EvidenceParams{
|
||||
MaxAgeNumBlocks: 302400,
|
||||
MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration
|
||||
MaxBytes: 10000,
|
||||
},
|
||||
Validator: &tmproto.ValidatorParams{
|
||||
PubKeyTypes: []string{
|
||||
tmtypes.ABCIPubKeyTypeEd25519,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Setup initializes a new EthermintApp. A Nop logger is set in EthermintApp.
|
||||
func Setup(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState) *EthermintApp {
|
||||
return SetupWithDB(isCheckTx, patchGenesis, dbm.NewMemDB())
|
||||
}
|
||||
|
||||
// SetupWithDB initializes a new EthermintApp. A Nop logger is set in EthermintApp.
|
||||
func SetupWithDB(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState, db dbm.DB) *EthermintApp {
|
||||
app := NewEthermintApp(log.NewNopLogger(),
|
||||
db,
|
||||
nil,
|
||||
true,
|
||||
map[int64]bool{},
|
||||
DefaultNodeHome,
|
||||
5,
|
||||
encoding.MakeConfig(ModuleBasics),
|
||||
simapp.EmptyAppOptions{})
|
||||
if !isCheckTx {
|
||||
// init chain must be called to stop deliverState from being nil
|
||||
genesisState := NewTestGenesisState(app.AppCodec())
|
||||
if patchGenesis != nil {
|
||||
genesisState = patchGenesis(app, genesisState)
|
||||
}
|
||||
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Initialize the chain
|
||||
app.InitChain(
|
||||
abci.RequestInitChain{
|
||||
ChainId: "laconic_9000-1",
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
ConsensusParams: DefaultConsensusParams,
|
||||
AppStateBytes: stateBytes,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// NewTestGenesisState generate genesis state with single validator
|
||||
func NewTestGenesisState(codec codec.Codec) simapp.GenesisState {
|
||||
privVal := mock.NewPV()
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// create validator set with single validator
|
||||
validator := tmtypes.NewValidator(pubKey, 1)
|
||||
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
|
||||
|
||||
// generate genesis account
|
||||
senderPrivKey := secp256k1.GenPrivKey()
|
||||
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
|
||||
balance := banktypes.Balance{
|
||||
Address: acc.GetAddress().String(),
|
||||
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
|
||||
}
|
||||
|
||||
genesisState := NewDefaultGenesisState()
|
||||
return genesisStateWithValSet(codec, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance)
|
||||
}
|
||||
|
||||
// RandomAccounts creates random accounts with an ethsecp256k1 private key
|
||||
// TODO: replace secp256k1.GenPrivKeyFromSecret() with similar function in go-ethereum
|
||||
func RandomAccounts(r *rand.Rand, n int) []simtypes.Account {
|
||||
accs := make([]simtypes.Account, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
// don't need that much entropy for simulation
|
||||
privkeySeed := make([]byte, 15)
|
||||
_, _ = r.Read(privkeySeed)
|
||||
|
||||
prv := secp256k1.GenPrivKeyFromSecret(privkeySeed)
|
||||
ethPrv := ðsecp256k1.PrivKey{}
|
||||
_ = ethPrv.UnmarshalAmino(prv.Bytes()) // UnmarshalAmino simply copies the bytes and assigns them to ethPrv.Key
|
||||
accs[i].PrivKey = ethPrv
|
||||
accs[i].PubKey = accs[i].PrivKey.PubKey()
|
||||
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
|
||||
|
||||
accs[i].ConsKey = ed25519.GenPrivKeyFromSecret(privkeySeed)
|
||||
}
|
||||
|
||||
return accs
|
||||
}
|
||||
|
||||
func genesisStateWithValSet(codec codec.Codec, genesisState simapp.GenesisState,
|
||||
valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount,
|
||||
balances ...banktypes.Balance,
|
||||
) simapp.GenesisState {
|
||||
// set genesis accounts
|
||||
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
|
||||
genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis)
|
||||
|
||||
validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
|
||||
delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))
|
||||
|
||||
bondAmt := sdk.DefaultPowerReduction
|
||||
|
||||
for _, val := range valSet.Validators {
|
||||
pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pkAny, err := codectypes.NewAnyWithValue(pk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
validator := stakingtypes.Validator{
|
||||
OperatorAddress: sdk.ValAddress(val.Address).String(),
|
||||
ConsensusPubkey: pkAny,
|
||||
Jailed: false,
|
||||
Status: stakingtypes.Bonded,
|
||||
Tokens: bondAmt,
|
||||
DelegatorShares: sdk.OneDec(),
|
||||
Description: stakingtypes.Description{},
|
||||
UnbondingHeight: int64(0),
|
||||
UnbondingTime: time.Unix(0, 0).UTC(),
|
||||
Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||
MinSelfDelegation: sdk.ZeroInt(),
|
||||
}
|
||||
validators = append(validators, validator)
|
||||
delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))
|
||||
}
|
||||
// set validators and delegations
|
||||
stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations)
|
||||
genesisState[stakingtypes.ModuleName] = codec.MustMarshalJSON(stakingGenesis)
|
||||
|
||||
totalSupply := sdk.NewCoins()
|
||||
for _, b := range balances {
|
||||
// add genesis acc tokens to total supply
|
||||
totalSupply = totalSupply.Add(b.Coins...)
|
||||
}
|
||||
|
||||
for range delegations {
|
||||
// add delegated tokens to total supply
|
||||
totalSupply = totalSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))
|
||||
}
|
||||
|
||||
// add bonded amount to bonded pool module account
|
||||
balances = append(balances, banktypes.Balance{
|
||||
Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(),
|
||||
Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)},
|
||||
})
|
||||
|
||||
// update total supply
|
||||
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
|
||||
genesisState[banktypes.ModuleName] = codec.MustMarshalJSON(bankGenesis)
|
||||
|
||||
return genesisState
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
version: v1
|
||||
directories:
|
||||
- proto
|
||||
- third_party/proto
|
||||
|
115
clang-format
Normal file
115
clang-format
Normal file
@ -0,0 +1,115 @@
|
||||
---
|
||||
Language: Proto
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: true
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
RawStringFormats:
|
||||
- Delimiters:
|
||||
- pb
|
||||
Language: TextProto
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
...
|
@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
ethermint "github.com/tharsis/ethermint/types"
|
||||
)
|
||||
|
||||
// InitConfig adds the chain-id, encoding and output flags to the persistent flag set.
|
||||
@ -26,7 +26,7 @@ func InitConfig(cmd *cobra.Command) error {
|
||||
_, err = os.Stat(configFile)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
// Immediately return if the error isn't related to the file not existing.
|
||||
// See issue https://github.com/cerc-io/laconicd/issues/539
|
||||
// See issue https://github.com/tharsis/ethermint/issues/539
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
func TestInitConfigNonNotExistError(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
subDir := filepath.Join(tempDir, "nonPerms")
|
||||
if err := os.Mkdir(subDir, 0o600); err != nil {
|
||||
if err := os.Mkdir(subDir, 0600); err != nil {
|
||||
t.Fatalf("Failed to create sub directory: %v", err)
|
||||
}
|
||||
cmd := &cobra.Command{}
|
||||
|
@ -13,6 +13,57 @@
|
||||
"Params": "EvmParams"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "./tmp-swagger-gen/cosmos/auth/v1beta1/query.swagger.json",
|
||||
"operationIds": {
|
||||
"rename": {
|
||||
"Account": "AuthAccount",
|
||||
"Params": "AuthParams"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "./tmp-swagger-gen/cosmos/bank/v1beta1/query.swagger.json",
|
||||
"operationIds": {
|
||||
"rename": {
|
||||
"Balance": "BankBalance",
|
||||
"Params": "BankParams"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "./tmp-swagger-gen/cosmos/distribution/v1beta1/query.swagger.json",
|
||||
"operationIds": {
|
||||
"rename": {
|
||||
"Params": "DistributionParams",
|
||||
"DelegatorValidators": "DistDelegatorValidators"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "./tmp-swagger-gen/cosmos/mint/v1beta1/query.swagger.json",
|
||||
"operationIds": {
|
||||
"rename": {
|
||||
"Params": "MintParams"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "./tmp-swagger-gen/cosmos/gov/v1beta1/query.swagger.json",
|
||||
"operationIds": {
|
||||
"rename": {
|
||||
"Params": "GovParams"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"url": "./tmp-swagger-gen/cosmos/staking/v1beta1/query.swagger.json",
|
||||
"operationIds": {
|
||||
"rename": {
|
||||
"Params": "StakingParams"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
package statik
|
||||
|
||||
// This just for fixing the error in importing empty github.com/cerc-io/laconicd/client/docs/statik
|
||||
// This just for fixing the error in importing empty github.com/tharsis/ethermint/client/docs/statik
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -5,16 +5,17 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/input"
|
||||
"github.com/cosmos/cosmos-sdk/crypto"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||
"github.com/cerc-io/laconicd/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
|
||||
"github.com/tharsis/ethermint/crypto/hd"
|
||||
)
|
||||
|
||||
// UnsafeExportEthKeyCommand exports a key with the given name as a private key in hex format.
|
||||
@ -25,8 +26,18 @@ func UnsafeExportEthKeyCommand() *cobra.Command {
|
||||
Long: `**UNSAFE** Export an Ethereum private key unencrypted to use in dev tooling`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx := client.GetClientContextFromCmd(cmd).WithKeyringOptions(hd.EthSecp256k1Option())
|
||||
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
|
||||
keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
|
||||
rootDir, _ := cmd.Flags().GetString(flags.FlagHome)
|
||||
|
||||
kr, err := keyring.New(
|
||||
sdk.KeyringServiceName(),
|
||||
keyringBackend,
|
||||
rootDir,
|
||||
inBuf,
|
||||
hd.EthSecp256k1Option(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -34,8 +45,7 @@ func UnsafeExportEthKeyCommand() *cobra.Command {
|
||||
decryptPassword := ""
|
||||
conf := true
|
||||
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
switch clientCtx.Keyring.Backend() {
|
||||
switch keyringBackend {
|
||||
case keyring.BackendFile:
|
||||
decryptPassword, err = input.GetPassword(
|
||||
"**WARNING this is an unsafe way to export your unencrypted private key**\nEnter key password:",
|
||||
@ -50,7 +60,7 @@ func UnsafeExportEthKeyCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
// Exports private key from keybase using password
|
||||
armor, err := clientCtx.Keyring.ExportPrivKeyArmor(args[0], decryptPassword)
|
||||
armor, err := kr.ExportPrivKeyArmor(args[0], decryptPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -5,13 +5,15 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/input"
|
||||
"github.com/cosmos/cosmos-sdk/crypto"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/hd"
|
||||
"github.com/tharsis/ethermint/crypto/hd"
|
||||
)
|
||||
|
||||
// UnsafeImportKeyCommand imports private keys from a keyfile.
|
||||
@ -26,13 +28,21 @@ func UnsafeImportKeyCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
func runImportCmd(cmd *cobra.Command, args []string) error {
|
||||
clientCtx := client.GetClientContextFromCmd(cmd).WithKeyringOptions(hd.EthSecp256k1Option())
|
||||
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
|
||||
rootDir, _ := cmd.Flags().GetString(flags.FlagHome)
|
||||
|
||||
kb, err := keyring.New(
|
||||
sdk.KeyringServiceName(),
|
||||
keyringBackend,
|
||||
rootDir,
|
||||
inBuf,
|
||||
hd.EthSecp256k1Option(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
passphrase, err := input.GetPassword("Enter passphrase to encrypt your key:", inBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -44,5 +54,5 @@ func runImportCmd(cmd *cobra.Command, args []string) error {
|
||||
|
||||
armor := crypto.EncryptArmorPrivKey(privKey, passphrase, "eth_secp256k1")
|
||||
|
||||
return clientCtx.Keyring.ImportPrivKey(args[0], armor, passphrase)
|
||||
return kb.ImportPrivKey(args[0], armor, passphrase)
|
||||
}
|
||||
|
@ -6,12 +6,13 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
clientkeys "github.com/cerc-io/laconicd/client/keys"
|
||||
"github.com/cerc-io/laconicd/crypto/hd"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
clientkeys "github.com/tharsis/ethermint/client/keys"
|
||||
"github.com/tharsis/ethermint/crypto/hd"
|
||||
)
|
||||
|
||||
// KeyCommands registers a sub-tree of commands to interact with
|
||||
@ -48,7 +49,7 @@ The pass backend requires GnuPG: https://gnupg.org/
|
||||
addCmd := keys.AddKeyCommand()
|
||||
|
||||
// update the default signing algorithm value to "eth_secp256k1"
|
||||
algoFlag := addCmd.Flag(flags.FlagKeyAlgorithm)
|
||||
algoFlag := addCmd.Flag("algo")
|
||||
algoFlag.DefValue = string(hd.EthSecp256k1Type)
|
||||
err := algoFlag.Value.Set(string(hd.EthSecp256k1Type))
|
||||
if err != nil {
|
||||
@ -64,8 +65,8 @@ The pass backend requires GnuPG: https://gnupg.org/
|
||||
keys.ImportKeyCommand(),
|
||||
keys.ListKeysCmd(),
|
||||
keys.ShowKeysCmd(),
|
||||
flags.LineBreak,
|
||||
keys.DeleteKeyCommand(),
|
||||
keys.RenameKeyCommand(),
|
||||
keys.ParseKeyStringCommand(),
|
||||
keys.MigrateCommand(),
|
||||
flags.LineBreak,
|
||||
@ -81,11 +82,25 @@ The pass backend requires GnuPG: https://gnupg.org/
|
||||
}
|
||||
|
||||
func runAddCmd(cmd *cobra.Command, args []string) error {
|
||||
clientCtx := client.GetClientContextFromCmd(cmd).WithKeyringOptions(hd.EthSecp256k1Option())
|
||||
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
|
||||
buf := bufio.NewReader(cmd.InOrStdin())
|
||||
clientCtx := client.GetClientContextFromCmd(cmd)
|
||||
|
||||
var (
|
||||
kr keyring.Keyring
|
||||
err error
|
||||
)
|
||||
|
||||
dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun)
|
||||
if dryRun {
|
||||
kr, err = keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, clientCtx.KeyringDir, buf, hd.EthSecp256k1Option())
|
||||
} else {
|
||||
backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
|
||||
kr, err = keyring.New(sdk.KeyringServiceName(), backend, clientCtx.KeyringDir, buf, hd.EthSecp256k1Option())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf := bufio.NewReader(clientCtx.Input)
|
||||
return clientkeys.RunAddCmd(clientCtx, cmd, args, buf)
|
||||
|
||||
return clientkeys.RunAddCmd(clientCtx.WithKeyring(kr), cmd, args, buf)
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
etherminthd "github.com/cerc-io/laconicd/crypto/hd"
|
||||
etherminthd "github.com/tharsis/ethermint/crypto/hd"
|
||||
|
||||
bip39 "github.com/cosmos/go-bip39"
|
||||
"github.com/spf13/cobra"
|
||||
@ -38,51 +38,91 @@ const (
|
||||
mnemonicEntropySize = 256
|
||||
)
|
||||
|
||||
/*
|
||||
RunAddCmd
|
||||
input
|
||||
- bip39 mnemonic
|
||||
- bip39 passphrase
|
||||
- bip44 path
|
||||
- local encryption password
|
||||
// AddKeyCommand defines a keys command to add a generated or recovered private key to keybase.
|
||||
func AddKeyCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "add <name>",
|
||||
Short: "Add an encrypted private key (either newly generated or recovered), encrypt it, and save to <name> file",
|
||||
Long: `Derive a new private key and encrypt to disk.
|
||||
Optionally specify a BIP39 mnemonic, a BIP39 passphrase to further secure the mnemonic,
|
||||
and a bip32 HD path to derive a specific account. The key will be stored under the given name
|
||||
and encrypted with the given password. The only input that is required is the encryption password.
|
||||
|
||||
If run with -i, it will prompt the user for BIP44 path, BIP39 mnemonic, and passphrase.
|
||||
The flag --recover allows one to recover a key from a seed passphrase.
|
||||
If run with --dry-run, a key would be generated (or recovered) but not stored to the
|
||||
local keystore.
|
||||
Use the --pubkey flag to add arbitrary public keys to the keystore for constructing
|
||||
multisig transactions.
|
||||
|
||||
You can create and store a multisig key by passing the list of key names stored in a keyring
|
||||
and the minimum number of signatures required through --multisig-threshold. The keys are
|
||||
sorted by address, unless the flag --nosort is set.
|
||||
Example:
|
||||
|
||||
keys add mymultisig --multisig "keyname1,keyname2,keyname3" --multisig-threshold 2
|
||||
`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runAddCmdPrepare,
|
||||
}
|
||||
f := cmd.Flags()
|
||||
f.StringSlice(flagMultisig, nil, "List of key names stored in keyring to construct a public legacy multisig key")
|
||||
f.Int(flagMultiSigThreshold, 1, "K out of N required signatures. For use in conjunction with --multisig")
|
||||
f.Bool(flagNoSort, false, "Keys passed to --multisig are taken in the order they're supplied")
|
||||
f.String(keys.FlagPublicKey, "", "Parse a public key in JSON format and saves key info to <name> file.")
|
||||
f.BoolP(flagInteractive, "i", false, "Interactively prompt user for BIP39 passphrase and mnemonic")
|
||||
f.Bool(flags.FlagUseLedger, false, "Store a local reference to a private key on a Ledger device")
|
||||
f.Bool(flagRecover, false, "Provide seed phrase to recover existing key instead of creating")
|
||||
f.Bool(flagNoBackup, false, "Don't print out seed phrase (if others are watching the terminal)")
|
||||
f.Bool(flags.FlagDryRun, false, "Perform action, but don't add key to local keystore")
|
||||
f.String(flagHDPath, "", "Manual HD Path derivation (overrides BIP44 config)")
|
||||
f.Uint32(flagCoinType, sdk.GetConfig().GetCoinType(), "coin type number for HD derivation")
|
||||
f.Uint32(flagAccount, 0, "Account number for HD derivation")
|
||||
f.Uint32(flagIndex, 0, "Address index number for HD derivation")
|
||||
f.String(flags.FlagKeyAlgorithm, string(etherminthd.EthSecp256k1Type), "Key signing algorithm to generate keys for")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runAddCmdPrepare(cmd *cobra.Command, args []string) error {
|
||||
buf := bufio.NewReader(cmd.InOrStdin())
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return RunAddCmd(clientCtx, cmd, args, buf)
|
||||
}
|
||||
|
||||
/*
|
||||
input
|
||||
- bip39 mnemonic
|
||||
- bip39 passphrase
|
||||
- bip44 path
|
||||
- local encryption password
|
||||
output
|
||||
- armor encrypted private key (saved to file)
|
||||
- armor encrypted private key (saved to file)
|
||||
*/
|
||||
func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *bufio.Reader) error {
|
||||
var (
|
||||
algo keyring.SignatureAlgo
|
||||
err error
|
||||
)
|
||||
var err error
|
||||
|
||||
name := args[0]
|
||||
|
||||
interactive, _ := cmd.Flags().GetBool(flagInteractive)
|
||||
noBackup, _ := cmd.Flags().GetBool(flagNoBackup)
|
||||
useLedger, _ := cmd.Flags().GetBool(flags.FlagUseLedger)
|
||||
algoStr, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm)
|
||||
|
||||
showMnemonic := !noBackup
|
||||
kb := ctx.Keyring
|
||||
outputFormat := ctx.OutputFormat
|
||||
|
||||
keyringAlgos, ledgerAlgos := kb.SupportedAlgorithms()
|
||||
|
||||
// check if the provided signing algorithm is supported by the keyring or
|
||||
// ledger
|
||||
if useLedger {
|
||||
algo, err = keyring.NewSigningAlgoFromString(algoStr, ledgerAlgos)
|
||||
} else {
|
||||
algo, err = keyring.NewSigningAlgoFromString(algoStr, keyringAlgos)
|
||||
}
|
||||
|
||||
keyringAlgos, _ := kb.SupportedAlgorithms()
|
||||
algoStr, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm)
|
||||
algo, err := keyring.NewSigningAlgoFromString(algoStr, keyringAlgos)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun); dryRun {
|
||||
// use in memory keybase
|
||||
kb = keyring.NewInMemory(ctx.Codec, etherminthd.EthSecp256k1Option())
|
||||
kb = keyring.NewInMemory(etherminthd.EthSecp256k1Option())
|
||||
} else {
|
||||
_, err = kb.Key(name)
|
||||
if err == nil {
|
||||
@ -116,11 +156,7 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
||||
return err
|
||||
}
|
||||
|
||||
key, err := k.GetPubKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pks[i] = key
|
||||
pks[i] = k.GetPubKey()
|
||||
}
|
||||
|
||||
if noSort, _ := cmd.Flags().GetBool(flagNoSort); !noSort {
|
||||
@ -130,34 +166,36 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
||||
}
|
||||
|
||||
pk := multisig.NewLegacyAminoPubKey(multisigThreshold, pks)
|
||||
k, err := kb.SaveMultisig(name, pk)
|
||||
info, err := kb.SaveMultisig(name, pk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return printCreate(cmd, k, false, "", outputFormat)
|
||||
return printCreate(cmd, info, false, "", outputFormat)
|
||||
}
|
||||
}
|
||||
|
||||
pubKey, _ := cmd.Flags().GetString(keys.FlagPublicKey)
|
||||
if pubKey != "" {
|
||||
var pk cryptotypes.PubKey
|
||||
if err = ctx.Codec.UnmarshalInterfaceJSON([]byte(pubKey), &pk); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k, err := kb.SaveOfflineKey(name, pk)
|
||||
err = ctx.Codec.UnmarshalInterfaceJSON([]byte(pubKey), &pk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return printCreate(cmd, k, false, "", outputFormat)
|
||||
info, err := kb.SavePubKey(name, pk, algo.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return printCreate(cmd, info, false, "", outputFormat)
|
||||
}
|
||||
|
||||
coinType, _ := cmd.Flags().GetUint32(flagCoinType)
|
||||
account, _ := cmd.Flags().GetUint32(flagAccount)
|
||||
index, _ := cmd.Flags().GetUint32(flagIndex)
|
||||
hdPath, _ := cmd.Flags().GetString(flagHDPath)
|
||||
useLedger, _ := cmd.Flags().GetBool(flags.FlagUseLedger)
|
||||
|
||||
if len(hdPath) == 0 {
|
||||
hdPath = hd.CreateHDPath(coinType, account, index).String()
|
||||
@ -169,13 +207,12 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
||||
if useLedger {
|
||||
bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix()
|
||||
|
||||
// use the provided algo to save the ledger key
|
||||
k, err := kb.SaveLedgerKey(name, algo, bech32PrefixAccAddr, coinType, account, index)
|
||||
info, err := kb.SaveLedgerKey(name, algo, bech32PrefixAccAddr, coinType, account, index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return printCreate(cmd, k, false, "", outputFormat)
|
||||
return printCreate(cmd, info, false, "", outputFormat)
|
||||
}
|
||||
|
||||
// Get bip39 mnemonic
|
||||
@ -237,7 +274,7 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
||||
}
|
||||
}
|
||||
|
||||
k, err := kb.NewAccount(name, mnemonic, bip39Passphrase, hdPath, algo)
|
||||
info, err := kb.NewAccount(name, mnemonic, bip39Passphrase, hdPath, algo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -249,27 +286,24 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
|
||||
mnemonic = ""
|
||||
}
|
||||
|
||||
return printCreate(cmd, k, showMnemonic, mnemonic, outputFormat)
|
||||
return printCreate(cmd, info, showMnemonic, mnemonic, outputFormat)
|
||||
}
|
||||
|
||||
func printCreate(cmd *cobra.Command, k *keyring.Record, showMnemonic bool, mnemonic, outputFormat string) error {
|
||||
func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemonic, outputFormat string) error {
|
||||
switch outputFormat {
|
||||
case OutputFormatText:
|
||||
cmd.PrintErrln()
|
||||
if err := printKeyringRecord(cmd.OutOrStdout(), k, keyring.MkAccKeyOutput, outputFormat); err != nil {
|
||||
return err
|
||||
}
|
||||
printKeyInfo(cmd.OutOrStdout(), info, keyring.MkAccKeyOutput, outputFormat)
|
||||
|
||||
// print mnemonic unless requested not to.
|
||||
if showMnemonic {
|
||||
if _, err := fmt.Fprintf(cmd.ErrOrStderr(),
|
||||
"\n**Important** write this mnemonic phrase in a safe place.\nIt is the only way to recover your account if you ever forget your password.\n\n%s\n\n", //nolint:lll
|
||||
mnemonic); err != nil {
|
||||
return fmt.Errorf("failed to print mnemonic: %v", err)
|
||||
}
|
||||
fmt.Fprintln(cmd.ErrOrStderr(), "\n**Important** write this mnemonic phrase in a safe place.")
|
||||
fmt.Fprintln(cmd.ErrOrStderr(), "It is the only way to recover your account if you ever forget your password.")
|
||||
fmt.Fprintln(cmd.ErrOrStderr(), "")
|
||||
fmt.Fprintln(cmd.ErrOrStderr(), mnemonic)
|
||||
}
|
||||
case OutputFormatJSON:
|
||||
out, err := keyring.MkAccKeyOutput(k)
|
||||
out, err := keyring.MkAccKeyOutput(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -291,14 +325,3 @@ func printCreate(cmd *cobra.Command, k *keyring.Record, showMnemonic bool, mnemo
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateMultisigThreshold(k, nKeys int) error {
|
||||
if k <= 0 {
|
||||
return fmt.Errorf("threshold must be a positive integer")
|
||||
}
|
||||
if nKeys < k {
|
||||
return fmt.Errorf(
|
||||
"threshold k of n multisignature: %d < %d", nKeys, k)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
61
client/keys/keys.go
Normal file
61
client/keys/keys.go
Normal file
@ -0,0 +1,61 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
)
|
||||
|
||||
// Commands registers a sub-tree of commands to interact with
|
||||
// local private key storage.
|
||||
func Commands(defaultNodeHome string) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "keys",
|
||||
Short: "Manage your application's keys",
|
||||
Long: `Keyring management commands. These keys may be in any format supported by the
|
||||
Tendermint crypto library and can be used by light-clients, full nodes, or any other application
|
||||
that needs to sign with a private key.
|
||||
|
||||
The keyring supports the following backends:
|
||||
|
||||
os Uses the operating system's default credentials store.
|
||||
file Uses encrypted file-based keystore within the app's configuration directory.
|
||||
This keyring will request a password each time it is accessed, which may occur
|
||||
multiple times in a single command resulting in repeated password prompts.
|
||||
kwallet Uses KDE Wallet Manager as a credentials management application.
|
||||
pass Uses the pass command line utility to store and retrieve keys.
|
||||
test Stores keys insecurely to disk. It does not prompt for a password to be unlocked
|
||||
and it should be use only for testing purposes.
|
||||
|
||||
kwallet and pass backends depend on external tools. Refer to their respective documentation for more
|
||||
information:
|
||||
KWallet https://github.com/KDE/kwallet
|
||||
pass https://www.passwordstore.org/
|
||||
|
||||
The pass backend requires GnuPG: https://gnupg.org/
|
||||
`,
|
||||
}
|
||||
|
||||
cmd.AddCommand(
|
||||
keys.MnemonicKeyCommand(),
|
||||
AddKeyCommand(),
|
||||
keys.ExportKeyCommand(),
|
||||
keys.ImportKeyCommand(),
|
||||
keys.ListKeysCmd(),
|
||||
keys.ShowKeysCmd(),
|
||||
flags.LineBreak,
|
||||
keys.DeleteKeyCommand(),
|
||||
keys.ParseKeyStringCommand(),
|
||||
keys.MigrateCommand(),
|
||||
)
|
||||
|
||||
cmd.PersistentFlags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
|
||||
cmd.PersistentFlags().String(flags.FlagKeyringDir, "", "The client Keyring directory; if omitted, the default 'home' directory will be used")
|
||||
cmd.PersistentFlags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
|
||||
cmd.PersistentFlags().String(cli.OutputFlag, "text", "Output format (text|json)")
|
||||
|
||||
return cmd
|
||||
}
|
@ -3,8 +3,9 @@ package keys
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
cryptokeyring "github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
@ -14,45 +15,58 @@ import (
|
||||
const (
|
||||
OutputFormatText = "text"
|
||||
OutputFormatJSON = "json"
|
||||
|
||||
// defaultKeyDBName is the client's subdirectory where keys are stored.
|
||||
defaultKeyDBName = "keys"
|
||||
)
|
||||
|
||||
type bechKeyOutFn func(k *cryptokeyring.Record) (cryptokeyring.KeyOutput, error)
|
||||
type bechKeyOutFn func(keyInfo cryptokeyring.Info) (cryptokeyring.KeyOutput, error)
|
||||
|
||||
func printKeyringRecord(w io.Writer, k *cryptokeyring.Record, bechKeyOut bechKeyOutFn, output string) error {
|
||||
ko, err := bechKeyOut(k)
|
||||
// NewLegacyKeyBaseFromDir initializes a legacy keybase at the rootDir directory. Keybase
|
||||
// options can be applied when generating this new Keybase.
|
||||
func NewLegacyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.LegacyKeybase, error) {
|
||||
return getLegacyKeyBaseFromDir(rootDir, opts...)
|
||||
}
|
||||
|
||||
func getLegacyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.LegacyKeybase, error) {
|
||||
return cryptokeyring.NewLegacy(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...)
|
||||
}
|
||||
|
||||
func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn, output string) {
|
||||
ko, err := bechKeyOut(keyInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch output {
|
||||
case OutputFormatText:
|
||||
if err := printTextRecords(w, []cryptokeyring.KeyOutput{ko}); err != nil {
|
||||
return err
|
||||
}
|
||||
printTextInfos(w, []cryptokeyring.KeyOutput{ko})
|
||||
|
||||
case OutputFormatJSON:
|
||||
out, err := keys.KeysCdc.MarshalJSON(ko)
|
||||
if err != nil {
|
||||
return err
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintln(w, string(out)); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(w, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printTextRecords(w io.Writer, kos []cryptokeyring.KeyOutput) error {
|
||||
func printTextInfos(w io.Writer, kos []cryptokeyring.KeyOutput) {
|
||||
out, err := yaml.Marshal(&kos)
|
||||
if err != nil {
|
||||
return err
|
||||
panic(err)
|
||||
}
|
||||
fmt.Fprintln(w, string(out))
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprintln(w, string(out)); err != nil {
|
||||
return err
|
||||
func validateMultisigThreshold(k, nKeys int) error {
|
||||
if k <= 0 {
|
||||
return fmt.Errorf("threshold must be a positive integer")
|
||||
}
|
||||
if nKeys < k {
|
||||
return fmt.Errorf(
|
||||
"threshold k of n multisignature: %d < %d", nKeys, k)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -5,15 +5,19 @@ package client
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
tmconfig "github.com/tendermint/tendermint/config"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
tmrand "github.com/tendermint/tendermint/libs/rand"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
@ -22,10 +26,8 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdkserver "github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
@ -34,200 +36,124 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
|
||||
mintypes "github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/hd"
|
||||
"github.com/cerc-io/laconicd/server/config"
|
||||
srvflags "github.com/cerc-io/laconicd/server/flags"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/testutil/network"
|
||||
"github.com/tharsis/ethermint/crypto/hd"
|
||||
"github.com/tharsis/ethermint/server/config"
|
||||
ethermint "github.com/tharsis/ethermint/types"
|
||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||
)
|
||||
|
||||
var (
|
||||
flagNodeDirPrefix = "node-dir-prefix"
|
||||
flagNumValidators = "v"
|
||||
flagOutputDir = "output-dir"
|
||||
flagNodeDaemonHome = "node-daemon-home"
|
||||
flagStartingIPAddress = "starting-ip-address"
|
||||
flagEnableLogging = "enable-logging"
|
||||
flagRPCAddress = "rpc.address"
|
||||
flagAPIAddress = "api.address"
|
||||
flagPrintMnemonic = "print-mnemonic"
|
||||
flagNodeDirPrefix = "node-dir-prefix"
|
||||
flagNumValidators = "v"
|
||||
flagOutputDir = "output-dir"
|
||||
flagNodeDaemonHome = "node-daemon-home"
|
||||
flagCoinDenom = "coin-denom"
|
||||
flagIPAddrs = "ip-addresses"
|
||||
)
|
||||
|
||||
type initArgs struct {
|
||||
algo string
|
||||
chainID string
|
||||
keyringBackend string
|
||||
minGasPrices string
|
||||
nodeDaemonHome string
|
||||
nodeDirPrefix string
|
||||
numValidators int
|
||||
outputDir string
|
||||
startingIPAddress string
|
||||
}
|
||||
|
||||
type startArgs struct {
|
||||
algo string
|
||||
apiAddress string
|
||||
chainID string
|
||||
grpcAddress string
|
||||
minGasPrices string
|
||||
outputDir string
|
||||
rpcAddress string
|
||||
jsonrpcAddress string
|
||||
numValidators int
|
||||
enableLogging bool
|
||||
printMnemonic bool
|
||||
}
|
||||
|
||||
func addTestnetFlagsToCmd(cmd *cobra.Command) {
|
||||
cmd.Flags().Int(flagNumValidators, 4, "Number of validators to initialize the testnet with")
|
||||
cmd.Flags().StringP(flagOutputDir, "o", "./.testnets", "Directory to store initialization data for the testnet")
|
||||
cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(sdkserver.FlagMinGasPrices,
|
||||
fmt.Sprintf("0.000006%s",
|
||||
ethermint.AttoPhoton),
|
||||
"Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)")
|
||||
cmd.Flags().String(flags.FlagKeyAlgorithm, string(hd.EthSecp256k1Type), "Key signing algorithm to generate keys for")
|
||||
}
|
||||
|
||||
// NewTestnetCmd creates a root testnet command with subcommands to run an in-process testnet or initialize
|
||||
// validator configuration files for running a multi-validator testnet in a separate process
|
||||
func NewTestnetCmd(mbm module.BasicManager, genBalIterator banktypes.GenesisBalancesIterator) *cobra.Command {
|
||||
testnetCmd := &cobra.Command{
|
||||
Use: "testnet",
|
||||
Short: "subcommands for starting or configuring local testnets",
|
||||
DisableFlagParsing: true,
|
||||
SuggestionsMinimumDistance: 2,
|
||||
RunE: client.ValidateCmd,
|
||||
}
|
||||
|
||||
testnetCmd.AddCommand(testnetStartCmd())
|
||||
testnetCmd.AddCommand(testnetInitFilesCmd(mbm, genBalIterator))
|
||||
|
||||
return testnetCmd
|
||||
}
|
||||
|
||||
// get cmd to initialize all files for tendermint testnet and application
|
||||
func testnetInitFilesCmd(mbm module.BasicManager, genBalIterator banktypes.GenesisBalancesIterator) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "init-files",
|
||||
Short: "Initialize config directories & files for a multi-validator testnet running locally via separate processes (e.g. Docker Compose or similar)", //nolint:lll
|
||||
Long: `init-files will setup "v" number of directories and populate each with
|
||||
necessary files (private validator, genesis, config, etc.) for running "v" validator nodes.
|
||||
|
||||
Booting up a network with these validator folders is intended to be used with Docker Compose,
|
||||
or a similar setup where each node has a manually configurable IP address.
|
||||
|
||||
Note, strict routability for addresses is turned off in the config file.
|
||||
|
||||
Example:
|
||||
evmosd testnet init-files --v 4 --output-dir ./.testnets --starting-ip-address 192.168.10.2
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverCtx := sdkserver.GetServerContextFromCmd(cmd)
|
||||
|
||||
args := initArgs{}
|
||||
args.outputDir, _ = cmd.Flags().GetString(flagOutputDir)
|
||||
args.keyringBackend, _ = cmd.Flags().GetString(flags.FlagKeyringBackend)
|
||||
args.chainID, _ = cmd.Flags().GetString(flags.FlagChainID)
|
||||
args.minGasPrices, _ = cmd.Flags().GetString(sdkserver.FlagMinGasPrices)
|
||||
args.nodeDirPrefix, _ = cmd.Flags().GetString(flagNodeDirPrefix)
|
||||
args.nodeDaemonHome, _ = cmd.Flags().GetString(flagNodeDaemonHome)
|
||||
args.startingIPAddress, _ = cmd.Flags().GetString(flagStartingIPAddress)
|
||||
args.numValidators, _ = cmd.Flags().GetInt(flagNumValidators)
|
||||
args.algo, _ = cmd.Flags().GetString(flags.FlagKeyAlgorithm)
|
||||
|
||||
return initTestnetFiles(clientCtx, cmd, serverCtx.Config, mbm, genBalIterator, args)
|
||||
},
|
||||
}
|
||||
|
||||
addTestnetFlagsToCmd(cmd)
|
||||
cmd.Flags().String(flagNodeDirPrefix, "node", "Prefix the directory name for each node with (node results in node0, node1, ...)")
|
||||
cmd.Flags().String(flagNodeDaemonHome, "evmosd", "Home directory of the node's daemon configuration")
|
||||
cmd.Flags().String(flagStartingIPAddress,
|
||||
"192.168.0.1",
|
||||
"Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
|
||||
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// get cmd to start multi validator in-process testnet
|
||||
func testnetStartCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "start",
|
||||
Short: "Launch an in-process multi-validator testnet",
|
||||
Long: `testnet will launch an in-process multi-validator testnet,
|
||||
and generate "v" directories, populated with necessary validator configuration files
|
||||
(private validator, genesis, config, etc.).
|
||||
|
||||
Example:
|
||||
evmosd testnet --v 4 --output-dir ./.testnets
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
args := startArgs{}
|
||||
args.outputDir, _ = cmd.Flags().GetString(flagOutputDir)
|
||||
args.chainID, _ = cmd.Flags().GetString(flags.FlagChainID)
|
||||
args.minGasPrices, _ = cmd.Flags().GetString(sdkserver.FlagMinGasPrices)
|
||||
args.numValidators, _ = cmd.Flags().GetInt(flagNumValidators)
|
||||
args.algo, _ = cmd.Flags().GetString(flags.FlagKeyAlgorithm)
|
||||
args.enableLogging, _ = cmd.Flags().GetBool(flagEnableLogging)
|
||||
args.rpcAddress, _ = cmd.Flags().GetString(flagRPCAddress)
|
||||
args.apiAddress, _ = cmd.Flags().GetString(flagAPIAddress)
|
||||
args.grpcAddress, _ = cmd.Flags().GetString(srvflags.GRPCAddress)
|
||||
args.jsonrpcAddress, _ = cmd.Flags().GetString(srvflags.JSONRPCAddress)
|
||||
args.printMnemonic, _ = cmd.Flags().GetBool(flagPrintMnemonic)
|
||||
|
||||
return startTestnet(cmd, args)
|
||||
},
|
||||
}
|
||||
|
||||
addTestnetFlagsToCmd(cmd)
|
||||
cmd.Flags().Bool(flagEnableLogging, false, "Enable INFO logging of tendermint validator nodes")
|
||||
cmd.Flags().String(flagRPCAddress, "tcp://0.0.0.0:26657", "the RPC address to listen on")
|
||||
cmd.Flags().String(flagAPIAddress, "tcp://0.0.0.0:1317", "the address to listen on for REST API")
|
||||
cmd.Flags().String(srvflags.GRPCAddress, config.DefaultGRPCAddress, "the gRPC server address to listen on")
|
||||
cmd.Flags().String(srvflags.JSONRPCAddress, config.DefaultJSONRPCAddress, "the JSON-RPC server address to listen on")
|
||||
cmd.Flags().Bool(flagPrintMnemonic, true, "print mnemonic of first validator to stdout for manual testing")
|
||||
return cmd
|
||||
}
|
||||
|
||||
const nodeDirPerm = 0o755
|
||||
|
||||
// initTestnetFiles initializes testnet files for a testnet to be run in a separate process
|
||||
func initTestnetFiles(
|
||||
// TestnetCmd initializes all files for tendermint testnet and application
|
||||
func TestnetCmd(
|
||||
mbm module.BasicManager, genBalancesIterator banktypes.GenesisBalancesIterator,
|
||||
) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "testnet",
|
||||
Short: "Initialize files for a Ethermint testnet",
|
||||
Long: `testnet will create "v" number of directories and populate each with
|
||||
necessary files (private validator, genesis, config, etc.).
|
||||
|
||||
Note, strict routability for addresses is turned off in the config file.`,
|
||||
|
||||
Example: "ethermintd testnet --v 4 --keyring-backend test --output-dir ./output --ip-addresses 192.168.10.2",
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
clientCtx := client.GetClientContextFromCmd(cmd)
|
||||
|
||||
serverCtx := server.GetServerContextFromCmd(cmd)
|
||||
config := serverCtx.Config
|
||||
|
||||
outputDir, _ := cmd.Flags().GetString(flagOutputDir)
|
||||
keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
|
||||
chainID, _ := cmd.Flags().GetString(flags.FlagChainID)
|
||||
minGasPrices, _ := cmd.Flags().GetString(server.FlagMinGasPrices)
|
||||
nodeDirPrefix, _ := cmd.Flags().GetString(flagNodeDirPrefix)
|
||||
nodeDaemonHome, _ := cmd.Flags().GetString(flagNodeDaemonHome)
|
||||
ipAddresses, _ := cmd.Flags().GetStringSlice(flagIPAddrs)
|
||||
numValidators, _ := cmd.Flags().GetInt(flagNumValidators)
|
||||
algo, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm)
|
||||
coinDenom, _ := cmd.Flags().GetString(flagCoinDenom)
|
||||
|
||||
if len(ipAddresses) == 0 {
|
||||
return errors.New("IP address list cannot be empty")
|
||||
}
|
||||
|
||||
return InitTestnet(
|
||||
clientCtx, cmd, config, mbm, genBalancesIterator, outputDir, chainID, coinDenom, minGasPrices,
|
||||
nodeDirPrefix, nodeDaemonHome, keyringBackend, algo, ipAddresses, numValidators,
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().Int(flagNumValidators, 4, "Number of validators to initialize the testnet with")
|
||||
cmd.Flags().StringP(flagOutputDir, "o", "./mytestnet", "Directory to store initialization data for the testnet")
|
||||
cmd.Flags().String(flagNodeDirPrefix, "node", "Prefix the directory name for each node with (node results in node0, node1, ...)")
|
||||
cmd.Flags().String(flagNodeDaemonHome, "ethermintd", "Home directory of the node's daemon configuration")
|
||||
cmd.Flags().StringSlice(flagIPAddrs, []string{"192.168.0.1"}, "List of IP addresses to use (i.e. `192.168.0.1,172.168.0.1` results in persistent peers list ID0@192.168.0.1:46656, ID1@172.168.0.1)")
|
||||
cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(server.FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01inj,0.001stake)")
|
||||
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
|
||||
cmd.Flags().String(flags.FlagKeyAlgorithm, string(hd.EthSecp256k1Type), "Key signing algorithm to generate keys for")
|
||||
cmd.Flags().String(flagCoinDenom, ethermint.AttoPhoton, "Coin denomination used for staking, governance, mint, crisis and evm parameters")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// InitTestnet initializes the testnet configuration
|
||||
func InitTestnet(
|
||||
clientCtx client.Context,
|
||||
cmd *cobra.Command,
|
||||
nodeConfig *tmconfig.Config,
|
||||
mbm module.BasicManager,
|
||||
genBalIterator banktypes.GenesisBalancesIterator,
|
||||
args initArgs,
|
||||
outputDir,
|
||||
chainID,
|
||||
coinDenom,
|
||||
minGasPrices,
|
||||
nodeDirPrefix,
|
||||
nodeDaemonHome,
|
||||
keyringBackend,
|
||||
algoStr string,
|
||||
ipAddresses []string,
|
||||
numValidators int,
|
||||
) error {
|
||||
if args.chainID == "" {
|
||||
args.chainID = fmt.Sprintf("ethermint_%d-1", tmrand.Int63n(9999999999999)+1)
|
||||
if chainID == "" {
|
||||
chainID = fmt.Sprintf("ethermint_%d-1", tmrand.Int63n(9999999999999)+1)
|
||||
}
|
||||
|
||||
nodeIDs := make([]string, args.numValidators)
|
||||
valPubKeys := make([]cryptotypes.PubKey, args.numValidators)
|
||||
if !ethermint.IsValidChainID(chainID) {
|
||||
return fmt.Errorf("invalid chain-id: %s", chainID)
|
||||
}
|
||||
|
||||
if err := sdk.ValidateDenom(coinDenom); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(ipAddresses) != 0 {
|
||||
numValidators = len(ipAddresses)
|
||||
}
|
||||
|
||||
nodeIDs := make([]string, numValidators)
|
||||
valPubKeys := make([]cryptotypes.PubKey, numValidators)
|
||||
|
||||
appConfig := config.DefaultConfig()
|
||||
appConfig.MinGasPrices = args.minGasPrices
|
||||
appConfig.MinGasPrices = minGasPrices
|
||||
appConfig.API.Enable = true
|
||||
appConfig.Telemetry.Enabled = true
|
||||
appConfig.Telemetry.PrometheusRetentionTime = 60
|
||||
appConfig.Telemetry.EnableHostnameLabel = false
|
||||
appConfig.Telemetry.GlobalLabels = [][]string{{"chain_id", args.chainID}}
|
||||
appConfig.Telemetry.GlobalLabels = [][]string{{"chain_id", chainID}}
|
||||
|
||||
var (
|
||||
genAccounts []authtypes.GenesisAccount
|
||||
@ -237,50 +163,65 @@ func initTestnetFiles(
|
||||
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
// generate private keys, node IDs, and initial transactions
|
||||
for i := 0; i < args.numValidators; i++ {
|
||||
nodeDirName := fmt.Sprintf("%s%d", args.nodeDirPrefix, i)
|
||||
nodeDir := filepath.Join(args.outputDir, nodeDirName, args.nodeDaemonHome)
|
||||
gentxsDir := filepath.Join(args.outputDir, "gentxs")
|
||||
for i := 0; i < numValidators; i++ {
|
||||
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
|
||||
nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome)
|
||||
gentxsDir := filepath.Join(outputDir, "gentxs")
|
||||
|
||||
nodeConfig.SetRoot(nodeDir)
|
||||
nodeConfig.RPC.ListenAddress = "tcp://0.0.0.0:26657"
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm); err != nil {
|
||||
_ = os.RemoveAll(args.outputDir)
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
nodeConfig.Moniker = nodeDirName
|
||||
|
||||
ip, err := getIP(i, args.startingIPAddress)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(args.outputDir)
|
||||
return err
|
||||
var (
|
||||
ip string
|
||||
err error
|
||||
)
|
||||
|
||||
if len(ipAddresses) == 1 {
|
||||
ip, err = getIP(i, ipAddresses[0])
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
ip = ipAddresses[i]
|
||||
}
|
||||
|
||||
nodeIDs[i], valPubKeys[i], err = genutil.InitializeNodeValidatorFiles(nodeConfig)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(args.outputDir)
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip)
|
||||
genFiles = append(genFiles, nodeConfig.GenesisFile())
|
||||
|
||||
kb, err := keyring.New(sdk.KeyringServiceName(), args.keyringBackend, nodeDir, inBuf, clientCtx.Codec, hd.EthSecp256k1Option())
|
||||
kb, err := keyring.New(
|
||||
sdk.KeyringServiceName(),
|
||||
keyringBackend,
|
||||
nodeDir,
|
||||
inBuf,
|
||||
hd.EthSecp256k1Option(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keyringAlgos, _ := kb.SupportedAlgorithms()
|
||||
algo, err := keyring.NewSigningAlgoFromString(args.algo, keyringAlgos)
|
||||
algo, err := keyring.NewSigningAlgoFromString(algoStr, keyringAlgos)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, "", true, algo)
|
||||
addr, secret, err := server.GenerateSaveCoinKey(kb, nodeDirName, true, algo)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(args.outputDir)
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -292,16 +233,16 @@ func initTestnetFiles(
|
||||
}
|
||||
|
||||
// save private key seed words
|
||||
if err := network.WriteFile(fmt.Sprintf("%v.json", "key_seed"), nodeDir, cliPrint); err != nil {
|
||||
if err := writeFile(fmt.Sprintf("%v.json", "key_seed"), nodeDir, cliPrint); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accStakingTokens := sdk.TokensFromConsensusPower(5000, ethermint.PowerReduction)
|
||||
coins := sdk.Coins{
|
||||
sdk.NewCoin(ethermint.AttoPhoton, accStakingTokens),
|
||||
}
|
||||
coins := sdk.NewCoins(
|
||||
sdk.NewCoin(coinDenom, accStakingTokens),
|
||||
)
|
||||
|
||||
genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: coins.Sort()})
|
||||
genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: coins})
|
||||
genAccounts = append(genAccounts, ðermint.EthAccount{
|
||||
BaseAccount: authtypes.NewBaseAccount(addr, nil, 0, 0),
|
||||
CodeHash: common.BytesToHash(evmtypes.EmptyCodeHash).Hex(),
|
||||
@ -311,7 +252,7 @@ func initTestnetFiles(
|
||||
createValMsg, err := stakingtypes.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addr),
|
||||
valPubKeys[i],
|
||||
sdk.NewCoin(ethermint.AttoPhoton, valTokens),
|
||||
sdk.NewCoin(coinDenom, valTokens),
|
||||
stakingtypes.NewDescription(nodeDirName, "", "", "", ""),
|
||||
stakingtypes.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
|
||||
sdk.OneInt(),
|
||||
@ -329,12 +270,12 @@ func initTestnetFiles(
|
||||
|
||||
txFactory := tx.Factory{}
|
||||
txFactory = txFactory.
|
||||
WithChainID(args.chainID).
|
||||
WithChainID(chainID).
|
||||
WithMemo(memo).
|
||||
WithKeybase(kb).
|
||||
WithTxConfig(clientCtx.TxConfig)
|
||||
|
||||
if err := tx.Sign(txFactory, nodeDirName, txBuilder, true); err != nil {
|
||||
if err := tx.Sign(txFactory, nodeDirName, txBuilder, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -343,32 +284,26 @@ func initTestnetFiles(
|
||||
return err
|
||||
}
|
||||
|
||||
if err := network.WriteFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBz); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
customAppTemplate, customAppConfig := config.AppConfig(ethermint.AttoPhoton)
|
||||
srvconfig.SetConfigTemplate(customAppTemplate)
|
||||
if err := sdkserver.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, tmconfig.DefaultConfig()); err != nil {
|
||||
if err := writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBz); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srvconfig.WriteConfigFile(filepath.Join(nodeDir, "config/app.toml"), appConfig)
|
||||
}
|
||||
|
||||
if err := initGenFiles(clientCtx, mbm, args.chainID, ethermint.AttoPhoton, genAccounts, genBalances, genFiles, args.numValidators); err != nil {
|
||||
if err := initGenFiles(clientCtx, mbm, chainID, coinDenom, genAccounts, genBalances, genFiles, numValidators); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := collectGenFiles(
|
||||
clientCtx, nodeConfig, args.chainID, nodeIDs, valPubKeys, args.numValidators,
|
||||
args.outputDir, args.nodeDirPrefix, args.nodeDaemonHome, genBalIterator,
|
||||
clientCtx, nodeConfig, chainID, nodeIDs, valPubKeys, numValidators,
|
||||
outputDir, nodeDirPrefix, nodeDaemonHome, genBalIterator,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd.PrintErrf("Successfully initialized %d node directories\n", args.numValidators)
|
||||
cmd.PrintErrf("Successfully initialized %d node directories\n", numValidators)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -383,6 +318,7 @@ func initGenFiles(
|
||||
numValidators int,
|
||||
) error {
|
||||
appGenState := mbm.DefaultGenesis(clientCtx.Codec)
|
||||
|
||||
// set the accounts in the genesis state
|
||||
var authGenState authtypes.GenesisState
|
||||
clientCtx.Codec.MustUnmarshalJSON(appGenState[authtypes.ModuleName], &authGenState)
|
||||
@ -408,7 +344,7 @@ func initGenFiles(
|
||||
stakingGenState.Params.BondDenom = coinDenom
|
||||
appGenState[stakingtypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&stakingGenState)
|
||||
|
||||
var govGenState govv1.GenesisState
|
||||
var govGenState govtypes.GenesisState
|
||||
clientCtx.Codec.MustUnmarshalJSON(appGenState[govtypes.ModuleName], &govGenState)
|
||||
|
||||
govGenState.DepositParams.MinDeposit[0].Denom = coinDenom
|
||||
@ -499,7 +435,7 @@ func collectGenFiles(
|
||||
|
||||
func getIP(i int, startingIPAddr string) (ip string, err error) {
|
||||
if len(startingIPAddr) == 0 {
|
||||
ip, err = sdkserver.ExternalIP()
|
||||
ip, err = server.ExternalIP()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -521,49 +457,19 @@ func calculateIP(ip string, i int) (string, error) {
|
||||
return ipv4.String(), nil
|
||||
}
|
||||
|
||||
// startTestnet starts an in-process testnet
|
||||
func startTestnet(cmd *cobra.Command, args startArgs) error {
|
||||
networkConfig := network.DefaultConfig()
|
||||
func writeFile(name, dir string, contents []byte) error {
|
||||
writePath := filepath.Join(dir)
|
||||
file := filepath.Join(writePath, name)
|
||||
|
||||
// Default networkConfig.ChainID is random, and we should only override it if chainID provided
|
||||
// is non-empty
|
||||
if args.chainID != "" {
|
||||
networkConfig.ChainID = args.chainID
|
||||
}
|
||||
networkConfig.SigningAlgo = args.algo
|
||||
networkConfig.MinGasPrices = args.minGasPrices
|
||||
networkConfig.NumValidators = args.numValidators
|
||||
networkConfig.EnableTMLogging = args.enableLogging
|
||||
networkConfig.RPCAddress = args.rpcAddress
|
||||
networkConfig.APIAddress = args.apiAddress
|
||||
networkConfig.GRPCAddress = args.grpcAddress
|
||||
networkConfig.JSONRPCAddress = args.jsonrpcAddress
|
||||
networkConfig.PrintMnemonic = args.printMnemonic
|
||||
networkLogger := network.NewCLILogger(cmd)
|
||||
|
||||
baseDir := fmt.Sprintf("%s/%s", args.outputDir, networkConfig.ChainID)
|
||||
if _, err := os.Stat(baseDir); !os.IsNotExist(err) {
|
||||
return fmt.Errorf(
|
||||
"testnests directory already exists for chain-id '%s': %s, please remove or select a new --chain-id",
|
||||
networkConfig.ChainID, baseDir)
|
||||
}
|
||||
|
||||
testnet, err := network.New(networkLogger, baseDir, networkConfig)
|
||||
err := tmos.EnsureDir(writePath, 0o755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = testnet.WaitForHeight(1)
|
||||
err = tmos.WriteFile(file, contents, 0o644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd.Println("press the Enter Key to terminate")
|
||||
_, err = fmt.Scanln() // wait for Enter Key
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
testnet.Cleanup()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package config
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
ethermint "github.com/tharsis/ethermint/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -40,7 +40,7 @@ func SetBech32Prefixes(config *sdk.Config) {
|
||||
func SetBip44CoinType(config *sdk.Config) {
|
||||
config.SetCoinType(ethermint.Bip44CoinType)
|
||||
config.SetPurpose(sdk.Purpose) // Shared
|
||||
config.SetFullFundraiserPath(ethermint.BIP44HDPath) //nolint: staticcheck
|
||||
config.SetFullFundraiserPath(ethermint.BIP44HDPath) // nolint: staticcheck
|
||||
}
|
||||
|
||||
// RegisterDenoms registers the base and display denominations to the SDK.
|
||||
|
@ -3,8 +3,8 @@ package config
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
ethermint "github.com/tharsis/ethermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -10,12 +10,12 @@ import (
|
||||
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
|
||||
|
||||
"github.com/cerc-io/laconicd/app"
|
||||
laconicd "github.com/cerc-io/laconicd/cmd/laconicd"
|
||||
"github.com/tharsis/ethermint/app"
|
||||
ethermintd "github.com/tharsis/ethermint/cmd/ethermintd"
|
||||
)
|
||||
|
||||
func TestInitCmd(t *testing.T) {
|
||||
rootCmd, _ := laconicd.NewRootCmd()
|
||||
rootCmd, _ := ethermintd.NewRootCmd()
|
||||
rootCmd.SetArgs([]string{
|
||||
"init", // Test the init cmd
|
||||
"etherminttest", // Moniker
|
||||
@ -23,6 +23,6 @@ func TestInitCmd(t *testing.T) {
|
||||
fmt.Sprintf("--%s=%s", flags.FlagChainID, "ethermint_9000-1"),
|
||||
})
|
||||
|
||||
err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome)
|
||||
err := svrcmd.Execute(rootCmd, app.DefaultNodeHome)
|
||||
require.NoError(t, err)
|
||||
}
|
@ -5,10 +5,12 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cerc-io/laconicd/version"
|
||||
"github.com/tharsis/ethermint/version"
|
||||
)
|
||||
|
||||
const flagLong = "long"
|
||||
const (
|
||||
flagLong = "long"
|
||||
)
|
||||
|
||||
func init() {
|
||||
infoCmd.Flags().Bool(flagLong, false, "Print full information")
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -18,9 +19,10 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/hd"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/tharsis/ethermint/crypto/hd"
|
||||
ethermint "github.com/tharsis/ethermint/types"
|
||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -32,7 +34,7 @@ const (
|
||||
// AddGenesisAccountCmd returns add-genesis-account cobra Command.
|
||||
func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "add-genesis-account ADDRESS_OR_KEY_NAME COIN...",
|
||||
Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]",
|
||||
Short: "Add a genesis account to genesis.json",
|
||||
Long: `Add a genesis account to genesis.json. The provided account must specify
|
||||
the account address or key name and a list of initial coins. If a key name is given,
|
||||
@ -41,29 +43,39 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
|
||||
`,
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx := client.GetClientContextFromCmd(cmd).WithKeyringOptions(hd.EthSecp256k1Option())
|
||||
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clientCtx := client.GetClientContextFromCmd(cmd)
|
||||
cdc := clientCtx.Codec
|
||||
|
||||
serverCtx := server.GetServerContextFromCmd(cmd)
|
||||
config := serverCtx.Config
|
||||
|
||||
config.SetRoot(clientCtx.HomeDir)
|
||||
|
||||
kr := clientCtx.Keyring
|
||||
addr, err := sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
info, err := kr.Key(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get address from Keyring: %w", err)
|
||||
}
|
||||
|
||||
addr, err = info.GetAddress()
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
keyringBackend, err := cmd.Flags().GetString(flags.FlagKeyringBackend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// attempt to lookup address from Keybase if no address was provided
|
||||
kb, err := keyring.New(
|
||||
sdk.KeyringServiceName(),
|
||||
keyringBackend,
|
||||
clientCtx.HomeDir,
|
||||
inBuf,
|
||||
hd.EthSecp256k1Option(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := kb.Key(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get address from Keybase: %w", err)
|
||||
}
|
||||
|
||||
addr = info.GetAddress()
|
||||
}
|
||||
|
||||
coins, err := sdk.ParseCoinsNormalized(args[1])
|
||||
@ -130,7 +142,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
|
||||
return fmt.Errorf("failed to unmarshal genesis state: %w", err)
|
||||
}
|
||||
|
||||
authGenState := authtypes.GetGenesisStateFromAppState(clientCtx.Codec, appState)
|
||||
authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState)
|
||||
|
||||
accs, err := authtypes.UnpackAccounts(authGenState.Accounts)
|
||||
if err != nil {
|
||||
@ -152,19 +164,19 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
|
||||
}
|
||||
authGenState.Accounts = genAccs
|
||||
|
||||
authGenStateBz, err := clientCtx.Codec.MarshalJSON(&authGenState)
|
||||
authGenStateBz, err := cdc.MarshalJSON(&authGenState)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal auth genesis state: %w", err)
|
||||
}
|
||||
|
||||
appState[authtypes.ModuleName] = authGenStateBz
|
||||
|
||||
bankGenState := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState)
|
||||
bankGenState := banktypes.GetGenesisStateFromAppState(cdc, appState)
|
||||
bankGenState.Balances = append(bankGenState.Balances, balances)
|
||||
bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances)
|
||||
bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...)
|
||||
|
||||
bankGenStateBz, err := clientCtx.Codec.MarshalJSON(bankGenState)
|
||||
bankGenStateBz, err := cdc.MarshalJSON(bankGenState)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal bank genesis state: %w", err)
|
||||
}
|
||||
@ -182,7 +194,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
|
||||
}
|
||||
|
||||
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory")
|
||||
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test)")
|
||||
cmd.Flags().String(flags.FlagKeyringBackend, keyring.BackendFile, "Select keyring's backend (os|file|kwallet|pass|test)")
|
||||
cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts")
|
||||
cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts")
|
||||
cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts")
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user