Sync from fork #74

Merged
0xmuralik merged 232 commits from murali/update-fork into main 2023-01-10 04:50:57 +00:00
354 changed files with 44802 additions and 13430 deletions

View File

@ -1,115 +1,6 @@
---
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
BasedOnStyle: google
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
...

5
.flake8 Normal file
View File

@ -0,0 +1,5 @@
[flake8]
ignore = BLK100, W503
max-line-length = 88
extend-ignore = E203
exclude = .git,__pycache__,node_modules,.direnv

5
.github/CODEOWNERS vendored
View File

@ -1,4 +1,5 @@
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
# Primary repo maintainers
* @fedekunze @khoslaventures @jolube
# Primary (global) repo maintainers
* @evmos/core-engineering

View File

@ -17,16 +17,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v2
- uses: actions/setup-go@v3
with:
go-version: 1.18
- uses: technote-space/get-diff-action@v6.0.1
go-version: 1.19
check-latest: true
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
SUFFIX_FILTER: |
.go
.mod
.sum
PATTERNS: |
**/**.go
go.mod
go.sum
- run: |
make build
if: env.GIT_DIFF

View File

@ -32,7 +32,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'go', 'javascript' ]
language: [ 'go' ]
# 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
@ -40,21 +40,33 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.2
with:
PATTERNS: |
**/**.sol
**/**.go
**/**.ts
**/**.js
go.mod
go.sum
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
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
queries: crypto-com/cosmos-sdk-codeql@main,security-and-quality
if: env.GIT_DIFF
# 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
uses: github/codeql-action/autobuild@v2
if: env.GIT_DIFF
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -68,4 +80,5 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2
if: env.GIT_DIFF

28
.github/workflows/dependencies.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: "Dependency Review"
on: pull_request
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
check-latest: true
- name: "Checkout Repository"
uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.2
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: "Dependency Review"
uses: actions/dependency-review-action@v3
if: env.GIT_DIFF
- name: "Go vulnerability check"
run: make vulncheck
if: env.GIT_DIFF

View File

@ -23,14 +23,14 @@ jobs:
node-version: '12.x'
- name: Install dependencies
run: npm install
- uses: technote-space/get-diff-action@v6.0.1
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
SUFFIX_FILTER: |
.go
.mod
.sum
.sol
PATTERNS: |
**/**.sol
**/**.go
go.mod
go.sum
- name: Test contract
run: |
sudo make contract-tools

View File

@ -13,9 +13,10 @@ jobs:
with:
submodules: true
- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19
check-latest: true
- name: release dry run
run: make release-dry-run
- name: setup release environment

View File

@ -1,12 +0,0 @@
name: Check Markdown links
on:
schedule:
- cron: "* */24 * * *"
jobs:
markdown-link-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: gaurav-nelson/github-action-markdown-link-check@1.0.14
with:
folder-path: "docs"

View File

@ -13,20 +13,40 @@ jobs:
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.18
go-version: 1.19
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.0
- uses: technote-space/get-diff-action@v6.1.2
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- uses: golangci/golangci-lint-action@v3
- uses: golangci/golangci-lint-action@v3.3.1
with:
version: v1.48.0
# 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 }}
# Check only if there are differences in the source code
if: "env.GIT_DIFF"
if: env.GIT_DIFF
python-lint:
name: Run flake8 on python integration tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: cachix/install-nix-action@v18
- uses: cachix/cachix-action@v12
with:
name: ethermint
- uses: technote-space/get-diff-action@v6.1.2
with:
PATTERNS: |
**/**.py
- run: |
nix-shell -I nixpkgs=./nix -p test-env --run "make lint-py"
if: env.GIT_DIFF

View File

@ -3,6 +3,8 @@ name: Protobuf
# This workflow is only run when a .proto file has been changed
on:
pull_request:
paths:
- "proto/**"
jobs:
lint:
@ -10,21 +12,17 @@ jobs:
timeout-minutes: 5
steps:
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.0.1
- uses: bufbuild/buf-setup-action@v1.9.0
- uses: bufbuild/buf-lint-action@v1
with:
PATTERNS: |
**/**.proto
- name: lint
run: make proto-lint
if: env.GIT_DIFF
breakage:
input: "proto"
break-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.0.1
- uses: bufbuild/buf-setup-action@v1.9.0
- uses: bufbuild/buf-breaking-action@v1
with:
PATTERNS: |
**/**.proto
- name: check-breakage
run: make proto-check-breaking
if: env.GIT_DIFF
input: "proto"
against: "https://github.com/${{ github.repository }}.git#branch=${{ github.event.pull_request.base.ref }},ref=HEAD~1,subdir=proto"

View File

@ -7,6 +7,9 @@ on:
jobs:
Gosec:
permissions:
security-events: write
runs-on: ubuntu-latest
env:
GO111MODULE: on
@ -14,7 +17,7 @@ jobs:
- name: Checkout Source
uses: actions/checkout@v3
- name: Get Diff
uses: technote-space/get-diff-action@v6.0.1
uses: technote-space/get-diff-action@v6.1.2
with:
PATTERNS: |
**/*.go
@ -27,7 +30,7 @@ jobs:
args: '-no-fail -fmt sarif -out results.sarif -exclude=G701,G703 ./...'
if: "env.GIT_DIFF_FILTERED != ''"
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v1
uses: github/codeql-action/upload-sarif@v2
with:
# Path to SARIF file relative to the root of the repository
sarif_file: results.sarif

View File

@ -10,14 +10,19 @@ on:
schedule:
- cron: '0 0 * * 0'
jobs:
# Update from: https://semgrep.dev/docs/semgrep-ci/sample-ci-configs/#github-actions
semgrep:
name: Scan
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
if: (github.actor != 'dependabot[bot]')
steps:
- name: Permission issue fix
run: git config --global --add safe.directory /__w/laconicd/laconicd
- uses: actions/checkout@v3
- name: Get Diff
uses: technote-space/get-diff-action@v6.0.1
uses: technote-space/get-diff-action@v6.1.2
with:
PATTERNS: |
**/*.go
@ -26,16 +31,15 @@ jobs:
**/*.sol
go.mod
go.sum
- uses: returntocorp/semgrep-action@v1
with:
publishToken: ${{ secrets.SEMGREP_APP_TOKEN }}
- uses: actions/checkout@v3
- run: semgrep scan --sarif --output=semgrep.sarif --config auto
env:
# Upload findings to GitHub Advanced Security Dashboard [step 1/2]
# See also the next step.
generateSarif: "1"
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
if: "env.GIT_DIFF_FILTERED != ''"
# Upload findings to GitHub Advanced Security Dashboard [step 2/2]
- name: Upload SARIF file for GitHub Advanced Security Dashboard
uses: github/codeql-action/upload-sarif@v1
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: semgrep.sarif
if: "env.GIT_DIFF_FILTERED != ''"

21
.github/workflows/stale.yml vendored Normal file
View 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@v6
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"

View File

@ -20,10 +20,10 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
- uses: technote-space/get-diff-action@v6.1.2
with:
PATTERNS: |
**/**.go
@ -45,10 +45,10 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
@ -66,10 +66,10 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.18
go-version: 1.19
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
- uses: technote-space/get-diff-action@v6.1.2
with:
PATTERNS: |
**/**.sol
@ -81,37 +81,16 @@ jobs:
make test-rpc
if: env.GIT_DIFF
test-e2e:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.18
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
with:
PATTERNS: |
**/**.sol
**/**.go
go.mod
go.sum
- name: Test e2e
run: |
make test-integration
if: env.GIT_DIFF
# integration_tests:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - uses: cachix/install-nix-action@v18
# - uses: cachix/cachix-action@v11
# - uses: cachix/cachix-action@v12
# with:
# name: ethermint
# signingKey: "${{ secrets.CACHIX_SIGNING_KEY }}"
# - uses: technote-space/get-diff-action@v6.1.1
# - uses: technote-space/get-diff-action@v6.1.2
# with:
# PATTERNS: |
# **/**.sol
@ -142,89 +121,9 @@ jobs:
# steps:
# - uses: actions/checkout@v2
# - uses: cachix/install-nix-action@v18
# - uses: cachix/cachix-action@v11
# - uses: cachix/cachix-action@v12
# with:
# name: ethermint
# signingKey: "${{ secrets.CACHIX_SIGNING_KEY }}"
# - name: 'instantiate integration test env'
# run: nix-store -r $(nix-instantiate tests/integration_tests/shell.nix)
test-sim-nondeterminism:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.18
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Test simulation nondeterminism
run: |
make test-sim-nondeterminism
if: env.GIT_DIFF
test-sim-random-genesis-fast:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.18
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Test simulation with random genesis
run: |
make test-sim-random-genesis-fast
if: env.GIT_DIFF
test-sim-import-export:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.18
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Simulation of import and export genesis
run: |
make test-sim-import-export
if: env.GIT_DIFF
test-sim-after-import:
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.18
check-latest: true
- uses: actions/checkout@v3
- uses: technote-space/get-diff-action@v6.1.1
with:
PATTERNS: |
**/**.go
go.mod
go.sum
- name: Test simulation after import
run: |
make test-sim-after-import
if: env.GIT_DIFF
# run: nix-store -r "$(nix-instantiate tests/integration_tests/shell.nix)"

14
.gitignore vendored
View File

@ -13,6 +13,7 @@
*.dll
*.so
*.dylib
.dccache
# Build
*.test
@ -34,10 +35,14 @@ 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
@ -55,6 +60,7 @@ vagrant
# IDE
.idea/
*.iml
*.code-workspace
# Graphviz
dependency-graph.png
@ -69,6 +75,8 @@ dependency-graph.png
*.abi
# Node.js
tests/**/node_modules/*
tests-solidity/**/node_modules/*
**/**.json
**/node_modules
# OpenZeppelin contracts
contracts/@openzeppelin/*

2766
.gitleaks.toml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,47 +6,35 @@ run:
linters:
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
- errcheck
- goconst
- gocritic
- gofmt
- goimports
- gofumpt
- revive
- gosec
- gosimple
- govet
- ineffassign
# - lll TODO: enable
- lll
- misspell
- nakedret
- prealloc
- exportloopref
- staticcheck
- structcheck
- stylecheck
# - typecheck #TODO: enable
- typecheck
- unconvert
- unparam
- unused
- varcheck
- nolintlint
- asciicheck
# - exhaustive
- exportloopref
- gofumpt
- gomodguard
# - nestif
# - nlreturn
- noctx
- rowserrcheck
# - whitespace
# - wsl
disable:
- typecheck
- whitespace
issues:
exclude-rules:
@ -59,6 +47,8 @@ issues:
max-same-issues: 50
linters-settings:
lll:
line-length: 150
dogsled:
max-blank-identifiers: 3
golint:
@ -73,7 +63,7 @@ linters-settings:
require-explanation: false
require-specific: false
gofumpt:
lang-version: "1.17"
lang-version: "1.19"
gomodguard:
blocked:
versions: # List of blocked module version constraints

21
.markdownlint.yml Normal file
View File

@ -0,0 +1,21 @@
"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

3
.markdownlintignore Normal file
View File

@ -0,0 +1,3 @@
CHANGELOG.md
docs/api/proto-docs.md
docs/node_modules

View File

@ -4,7 +4,7 @@ queue_rules:
- "#approved-reviews-by>1"
pull_request_rules:
- name: automerge to the base branch with label automerge and branch protection passing
- name: automerge to main with label "automerge" and branch protection passing
conditions:
- "#approved-reviews-by>1"
- base=main
@ -12,22 +12,30 @@ pull_request_rules:
actions:
queue:
name: default
merge:
method: squash
commit_message: title+body
- name: backport patches to v0.9.x branch
commit_message_template: |
{{ title }} (#{{ number }})
{{ body }}
- name: backport patches to main branch
conditions:
- base=main
- label=backport/0.9.x
- label=backport/main
actions:
backport:
branches:
- release/v0.9.x
- name: backport patches to v0.7.x branch
- main
- name: backport patches to v0.20.x branch
conditions:
- base=main
- label=backport/0.7.x
- label=backport/0.20.x
actions:
backport:
branches:
- release/v0.7.x
- 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

174
.protolint.yml Normal file
View File

@ -0,0 +1,174 @@
---
# 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

3
.solhint.json Normal file
View File

@ -0,0 +1,3 @@
{
"extends": "solhint:default"
}

31
.yamllint Normal file
View File

@ -0,0 +1,31 @@
---
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

View File

@ -36,7 +36,57 @@ Ref: https://keepachangelog.com/en/1.0.0/
# Changelog
## Unreleased
## [v0.20.0] - 2022-12-28
### 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
### 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`.
### 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)
### 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
@ -63,11 +113,30 @@ Ref: https://keepachangelog.com/en/1.0.0/
### 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
@ -197,7 +266,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (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/cosmos/ethermint/pull/1112) Add `GetBaseAccount` to avoid invalid account error when create vesting account.
* (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
@ -633,7 +702,7 @@ the Tracer type used to collect execution traces from the EVM transaction execut
### 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/tag/v0.39.2)
* (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)

View File

@ -17,7 +17,7 @@ COPY . .
RUN make build
# Final image
FROM alpine:3.16.2
FROM alpine:3.17.0
# Install ca-certificates
RUN apk add --update ca-certificates jq

155
Makefile Executable file → Normal file
View File

@ -14,7 +14,6 @@ SIMAPP = ./app
HTTPS_GIT := https://github.com/cerc-io/laconicd.git
PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
DOCKER := $(shell which docker)
DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf:1.0.0-rc8
# 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
@ -111,6 +110,12 @@ 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
@ -158,7 +163,7 @@ clean:
all: build
build-all: tools build lint test
build-all: tools build lint test vulncheck
.PHONY: distclean clean build-all
@ -167,7 +172,7 @@ build-all: tools build lint test
###############################################################################
PACKAGE_NAME:=github.com/cerc-io/laconicd
GOLANG_CROSS_VERSION = v1.18
GOLANG_CROSS_VERSION = v1.19
GOPATH ?= '$(HOME)/go'
release-dry-run:
docker run \
@ -276,6 +281,10 @@ go.sum: go.mod
go mod verify
go mod tidy
vulncheck: $(BUILDDIR)/
GOBIN=$(BUILDDIR) go install golang.org/x/vuln/cmd/govulncheck@latest
$(BUILDDIR)/govulncheck ./...
###############################################################################
### Documentation ###
###############################################################################
@ -330,9 +339,6 @@ test-import:
test-rpc:
./scripts/integration-test-all.sh -t "rpc" -q 1 -z 1 -s 2 -m "rpc" -r "true"
test-integration:
./scripts/integration-test-all.sh -t "integration" -q 1 -z 1 -s 2 -m "integration" -r "true"
run-integration-tests:
@nix-shell ./tests/integration_tests/shell.nix --run ./scripts/run-integration-tests.sh
@ -349,51 +355,6 @@ 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-random-genesis-fast:
@echo "Running random genesis simulation..."
@go test -mod=readonly $(SIMAPP) -run TestFullAppSimulation \
-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-random-genesis-multi-seed: runsim
@echo "Running multi-seed custom genesis simulation..."
@$(BINDIR)/runsim -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)
@ -427,74 +388,62 @@ format-fix:
### Protobuf ###
###############################################################################
protoVer=v0.2
# ------
# NOTE: Link to the tendermintdev/sdk-proto-gen docker images:
# https://hub.docker.com/r/tendermintdev/sdk-proto-gen/tags
#
protoVer=v0.7
protoImageName=tendermintdev/sdk-proto-gen:$(protoVer)
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)
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)
# ------
# 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"
@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
$(protoImage) sh ./scripts/protocgen.sh
proto-swagger-gen:
@echo "Generating Protobuf Swagger"
@./scripts/proto-tools-installer.sh
@./scripts/protoc-swagger-gen.sh
# TODO: Rethink API docs generation
# proto-swagger-gen:
# @echo "Generating Protobuf Swagger"
# $(protoImage) sh ./scripts/protoc-swagger-gen.sh
proto-format:
@echo "Formatting Protobuf files"
@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
$(protoCosmosImage) find ./ -name *.proto -exec clang-format -i {} \;
# NOTE: The linter configuration lives in .protolint.yaml
proto-lint:
@$(DOCKER_BUF) lint --error-format=json
@echo "Linting Protobuf files"
$(protolintImage) lint ./proto
proto-check-breaking:
@$(DOCKER_BUF) breaking --against $(HTTPS_GIT)#branch=main
@echo "Checking Protobuf files for breaking changes"
$(protoImage) buf breaking --against $(HTTPS_GIT)#branch=main
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
.PHONY: proto-all proto-gen proto-gen-any proto-format proto-lint proto-check-breaking
###############################################################################
### Localnet ###

View File

@ -7,7 +7,7 @@
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.
**Note**: Requires [Go 1.18+](https://golang.org/dl/)
**Note**: Requires [Go 1.19+](https://golang.org/dl/)
## Installation

62
SECURITY.md Normal file
View File

@ -0,0 +1,62 @@
# Security
As part of our vulnerability disclosure policy, we operate a security vulnerability program through [Immunefi](https://immunefi.com/). This document serves as a complementary guideline for reporting vulnerabilities and how the disclosure process is managed. Please refer to the official Evmos [bug bounty program](https://immunefi.com/bounty/evmos/) for up-to-date information.
## Guidelines
We require that all researchers:
- Use the Evmos [bug bounty program](https://immunefi.com/bounty/evmos/) on Immunefi to disclose all vulnerabilities, and avoid posting vulnerability information in public places, including GitHub, Discord, Telegram, Twitter or other non-private channels.
- Make every effort to avoid privacy violations, degradation of user experience, disruption to production systems, and destruction of data.
- Keep any information about vulnerabilities that youve discovered confidential between yourself and the engineering team until the issue has been resolved and disclosed
- Avoid posting personally identifiable information, privately or publicly
If you follow these guidelines when reporting an issue to us, we commit to:
- Not pursue or support any legal action related to your research on this vulnerability
- Work with you to understand, resolve and ultimately disclose the issue in a timely fashion
## Disclosure Process
Evmos uses the following disclosure process:
1. Once a security report is received via the Immunefi Bug Bounty program, the team works to verify the issue and confirm its severity level using [CVSS](https://nvd.nist.gov/vuln-metrics/cvss) or [Immunefis Vulnerability Severity Classification System v2.2](https://immunefi.com/immunefi-vulnerability-severity-classification-system-v2-2/).
1. Two people from the affected project will review, replicate and acknowledge the report within 48-96 hours of the alert according to the table below:
| Security Level | Hours to First Response (ACK) from Escalation |
| -------------------- | --------------------------------------------- |
| Critical | 48 |
| High | 96 |
| Medium | 96 |
| Low or Informational | 96 |
| None | 96 |
2. If the report is not applicable or reproducible, the Security Lead (or Security Secondary) will revert to the reporter to request more info or close the report.
3. The report is confirmed by the Security Lead to the reporter.
2. The team determines the vulnerabilitys potential impact on Evmos.
1. Vulnerabilities with `Informational` and `Low` categorization will result in creating a public issue.
2. Vulnerabilities with `Medium` categorization will result in the creation of an internal ticket and patch of the code.
3. Vulnerabilities with `High` or `Critical` will result in the [creation of a new Security Advisory](https://docs.github.com/en/code-security/repository-security-advisories/creating-a-repository-security-advisory)
Once the vulnerability severity is defined, the following steps apply:
- For `High` and `Critical`:
1. Patches are prepared for supported releases of Evmos in a [temporary private fork](https://docs.github.com/en/code-security/repository-security-advisories/collaborating-in-a-temporary-private-fork-to-resolve-a-repository-security-vulnerability) of the repository.
2. Only relevant parties will be notified about an upcoming upgrade. These being validators, the core developer team, and users directly affected by the vulnerability.
3. 24 hours following this notification, relevant releases with the patch will be made public.
4. The nodes and validators update their Evmos and Ethermint dependencies to use these releases.
5. A week (or less) after the security vulnerability has been patched on Evmos, we will disclose that the mentioned release contained a security fix.
6. After an additional 2 weeks, we will publish a public announcement of the vulnerability. We also publish a security Advisory on GitHub and publish a [CVE](https://en.wikipedia.org/wiki/Common_Vulnerabilities_and_Exposures)
- For `Informational` , `Low` and `Medium` severities:
1. `Medium` and `Low` severity bug reports are included in a public issue and will be incorporated in the current sprint and patched in the next release. `Informational` reports are additionally categorized as with low or medium priority and might not be included in the next release.
2. One week after the releases go out, we will publish a post with further details on the vulnerability as well as our response to it.
This process can take some time. Every effort will be made to handle the bug in as timely a manner as possible, however, it's important that we follow the process described above to ensure that disclosures are handled consistently and to keep Ethermint and its downstream dependent projects, including but not limited to Evmos, as secure as possible.
### Payment Process
The payment process will be executed according to Evmoss Immunefi Bug Bounty program Rules.
### Contact
The Evmos Security Team is constantly being monitored. If you need to reach out to the team directly, please reach out via email: [security@evmos.org](mailto:security@evmos.org)

View File

@ -6,8 +6,10 @@ import (
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"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
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"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
@ -44,14 +46,14 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
// handle as *evmtypes.MsgEthereumTx
anteHandler = newEthAnteHandler(options)
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
anteHandler = newCosmosAnteHandlerEip712(options)
// 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)
default:
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrUnknownExtensionOptions,
return ctx, errorsmod.Wrapf(
errortypes.ErrUnknownExtensionOptions,
"rejecting tx with unsupported extension option: %s", typeURL,
)
}
@ -65,7 +67,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
case sdk.Tx:
anteHandler = newCosmosAnteHandler(options)
default:
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid transaction type: %T", tx)
}
return anteHandler(ctx, tx, sim)
@ -74,7 +76,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
func Recover(logger tmlog.Logger, err *error) {
if r := recover(); r != nil {
*err = sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r)
*err = errorsmod.Wrapf(errortypes.ErrPanic, "%v", r)
if e, ok := r.(error); ok {
logger.Error(
@ -99,12 +101,48 @@ var _ authante.SignatureVerificationGasConsumer = DefaultSigVerificationGasConsu
func DefaultSigVerificationGasConsumer(
meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params,
) error {
// support for ethereum ECDSA secp256k1 keys
_, ok := sig.PubKey.(*ethsecp256k1.PubKey)
if ok {
pubkey := sig.PubKey
switch pubkey := pubkey.(type) {
case *ethsecp256k1.PubKey:
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 authante.DefaultSigVerificationGasConsumer(meter, sig, params)
return nil
}

View File

@ -2,24 +2,36 @@ package ante_test
import (
"errors"
"fmt"
"math/big"
"strings"
"time"
sdkmath "cosmossdk.io/math"
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
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/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/authz"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cerc-io/laconicd/app/ante"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
"github.com/cerc-io/laconicd/tests"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/ethereum/go-ethereum/core/types"
ethparams "github.com/ethereum/go-ethereum/params"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
)
func (suite AnteTestSuite) TestAnteHandler() {
@ -337,6 +349,17 @@ func (suite AnteTestSuite) TestAnteHandler() {
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 create validator (with blank fields)",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MsgCreateValidator2(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 MsgSubmitProposal",
func() sdk.Tx {
@ -364,7 +387,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
from, grantee, &banktypes.SendAuthorization{SpendLimit: gasAmount}, &expiresAt,
)
suite.Require().NoError(err)
return suite.CreateTestEIP712CosmosTxBuilder(from, privKey, "ethermint_9000-1", gas, gasAmount, msg).GetTx()
return suite.CreateTestEIP712SingleMessageTxBuilder(from, privKey, "ethermint_9000-1", gas, gasAmount, msg).GetTx()
}, false, false, true,
},
@ -397,10 +420,65 @@ func (suite AnteTestSuite) TestAnteHandler() {
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MsgEditValidator(from, privKey, "ethermint_9000-1", gas, amount)
txBuilder := suite.CreateTestEIP712MsgSubmitEvidence(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 submit proposal v1",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712SubmitProposalV1(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 MsgExec",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MsgExec(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 MsgVoteV1",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MsgVoteV1(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 Multiple MsgSend",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MultipleMsgSend(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"fails - DeliverTx EIP712 Multiple Signers",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MultipleSignerMsgs(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, false,
},
{
"fails - DeliverTx EIP712 signed Cosmos Tx with wrong Chain ID",
func() sdk.Tx {
@ -496,6 +574,301 @@ func (suite AnteTestSuite) TestAnteHandler() {
return tx
}, true, false, false,
},
{
"passes - Single-signer EIP-712",
func() sdk.Tx {
msg := banktypes.NewMsgSend(
sdk.AccAddress(privKey.PubKey().Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSingleSignedTx(
privKey,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
msg,
"ethermint_9000-1",
2000000,
"EIP-712",
)
return txBuilder.GetTx()
}, false, false, true,
},
{
"passes - EIP-712 multi-key",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
msg,
"ethermint_9000-1",
2000000,
"EIP-712",
)
return txBuilder.GetTx()
}, false, false, true,
},
{
"passes - Mixed multi-key",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
msg,
"ethermint_9000-1",
2000000,
"mixed", // Combine EIP-712 and standard signatures
)
return txBuilder.GetTx()
}, false, false, true,
},
{
"passes - Mixed multi-key with MsgVote",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := govtypes.NewMsgVote(
sdk.AccAddress(pk.Address()),
1,
govtypes.OptionYes,
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
msg,
"ethermint_9000-1",
2000000,
"mixed", // Combine EIP-712 and standard signatures
)
return txBuilder.GetTx()
}, false, false, true,
},
{
"Fails - Multi-Key with incorrect Chain ID",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
msg,
"ethermint_9005-1",
2000000,
"mixed",
)
return txBuilder.GetTx()
}, false, false, false,
},
{
"Fails - Multi-Key with incorrect sign mode",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_DIRECT,
msg,
"ethermint_9000-1",
2000000,
"mixed",
)
return txBuilder.GetTx()
}, false, false, false,
},
{
"Fails - Multi-Key with too little gas",
func() sdk.Tx {
numKeys := 5
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_DIRECT,
msg,
"ethermint_9000-1",
2000,
"mixed", // Combine EIP-712 and standard signatures
)
return txBuilder.GetTx()
}, false, false, false,
},
{
"Fails - Multi-Key with different payload than one signed",
func() sdk.Tx {
numKeys := 1
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_DIRECT,
msg,
"ethermint_9000-1",
2000,
"EIP-712",
)
msg.Amount[0].Amount = sdk.NewInt(5)
txBuilder.SetMsgs(msg)
return txBuilder.GetTx()
}, false, false, false,
},
{
"Fails - Multi-Key with messages added after signing",
func() sdk.Tx {
numKeys := 1
privKeys, pubKeys := suite.GenerateMultipleKeys(numKeys)
pk := kmultisig.NewLegacyAminoPubKey(numKeys, pubKeys)
msg := banktypes.NewMsgSend(
sdk.AccAddress(pk.Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSignedMultisigTx(
privKeys,
signing.SignMode_SIGN_MODE_DIRECT,
msg,
"ethermint_9000-1",
2000,
"EIP-712",
)
// Duplicate
txBuilder.SetMsgs(msg, msg)
return txBuilder.GetTx()
}, false, false, false,
},
{
"Fails - Single-Signer EIP-712 with messages added after signing",
func() sdk.Tx {
msg := banktypes.NewMsgSend(
sdk.AccAddress(privKey.PubKey().Address()),
addr[:],
sdk.NewCoins(
sdk.NewCoin(
"photon",
sdk.NewInt(1),
),
),
)
txBuilder := suite.CreateTestSingleSignedTx(
privKey,
signing.SignMode_SIGN_MODE_DIRECT,
msg,
"ethermint_9000-1",
2000,
"EIP-712",
)
txBuilder.SetMsgs(msg, msg)
return txBuilder.GetTx()
}, false, false, false,
},
}
for _, tc := range testCases {
@ -914,3 +1287,93 @@ func (suite AnteTestSuite) TestAnteHandlerWithParams() {
}
suite.evmParamsOption = nil
}
func (suite *AnteTestSuite) TestConsumeSignatureVerificationGas() {
params := authtypes.DefaultParams()
msg := []byte{1, 2, 3, 4}
cdc := simapp.MakeTestEncodingConfig().Amino
p := authtypes.DefaultParams()
skR1, _ := secp256r1.GenPrivKey()
pkSet1, sigSet1, err := generatePubKeysAndSignatures(5, msg, false)
suite.Require().NoError(err)
multisigKey1 := kmultisig.NewLegacyAminoPubKey(2, pkSet1)
multisignature1 := multisig.NewMultisig(len(pkSet1))
expectedCost1 := expectedGasCostByKeys(pkSet1)
for i := 0; i < len(pkSet1); i++ {
stdSig := legacytx.StdSignature{PubKey: pkSet1[i], Signature: sigSet1[i]}
sigV2, err := legacytx.StdSignatureToSignatureV2(cdc, stdSig)
suite.Require().NoError(err)
err = multisig.AddSignatureV2(multisignature1, sigV2, pkSet1)
suite.Require().NoError(err)
}
type args struct {
meter sdk.GasMeter
sig signing.SignatureData
pubkey cryptotypes.PubKey
params authtypes.Params
}
tests := []struct {
name string
args args
gasConsumed uint64
shouldErr bool
}{
{"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), nil, ed25519.GenPrivKey().PubKey(), params}, p.SigVerifyCostED25519, true},
{"PubKeyEthSecp256k1", args{sdk.NewInfiniteGasMeter(), nil, pkSet1[0], params}, 21_000, false},
{"PubKeySecp256r1", args{sdk.NewInfiniteGasMeter(), nil, skR1.PubKey(), params}, p.SigVerifyCostSecp256r1(), false},
{"Multisig", args{sdk.NewInfiniteGasMeter(), multisignature1, multisigKey1, params}, expectedCost1, false},
{"unknown key", args{sdk.NewInfiniteGasMeter(), nil, nil, params}, 0, true},
}
for _, tt := range tests {
sigV2 := signing.SignatureV2{
PubKey: tt.args.pubkey,
Data: tt.args.sig,
Sequence: 0, // Arbitrary account sequence
}
err := ante.DefaultSigVerificationGasConsumer(tt.args.meter, sigV2, tt.args.params)
if tt.shouldErr {
suite.Require().NotNil(err)
} else {
suite.Require().Nil(err)
suite.Require().Equal(tt.gasConsumed, tt.args.meter.GasConsumed(), fmt.Sprintf("%d != %d", tt.gasConsumed, tt.args.meter.GasConsumed()))
}
}
}
func generatePubKeysAndSignatures(n int, msg []byte, _ bool) (pubkeys []cryptotypes.PubKey, signatures [][]byte, err error) {
pubkeys = make([]cryptotypes.PubKey, n)
signatures = make([][]byte, n)
for i := 0; i < n; i++ {
privkey, err := ethsecp256k1.GenerateKey()
if err != nil {
return nil, nil, err
}
pubkeys[i] = privkey.PubKey()
signatures[i], _ = privkey.Sign(msg)
}
return
}
func expectedGasCostByKeys(pubkeys []cryptotypes.PubKey) uint64 {
cost := uint64(0)
for _, pubkey := range pubkeys {
pubkeyType := strings.ToLower(fmt.Sprintf("%T", pubkey))
switch {
case strings.Contains(pubkeyType, "ed25519"):
cost += authtypes.DefaultParams().SigVerifyCostED25519
case strings.Contains(pubkeyType, "ethsecp256k1"):
cost += 21_000
case strings.Contains(pubkeyType, "secp256k1"):
cost += authtypes.DefaultParams().SigVerifyCostSecp256k1
default:
panic("unexpected key type")
}
}
return cost
}

View File

@ -3,15 +3,17 @@ 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"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
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"
@ -19,6 +21,7 @@ import (
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
@ -29,19 +32,47 @@ func init() {
ethermintCodec = codec.NewProtoCodec(registry)
}
// Eip712SigVerificationDecorator Verify all signatures for a tx and return an error if any are invalid. Note,
// the Eip712SigVerificationDecorator decorator will not get executed on ReCheck.
// 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 Eip712SigVerificationDecorator struct {
type LegacyEip712SigVerificationDecorator struct {
ak evmtypes.AccountKeeper
signModeHandler authsigning.SignModeHandler
}
// NewEip712SigVerificationDecorator creates a new Eip712SigVerificationDecorator
func NewEip712SigVerificationDecorator(ak evmtypes.AccountKeeper, signModeHandler authsigning.SignModeHandler) Eip712SigVerificationDecorator {
return Eip712SigVerificationDecorator{
// Deprecated: NewLegacyEip712SigVerificationDecorator creates a new LegacyEip712SigVerificationDecorator
func NewLegacyEip712SigVerificationDecorator(
ak evmtypes.AccountKeeper,
signModeHandler authsigning.SignModeHandler,
) LegacyEip712SigVerificationDecorator {
return LegacyEip712SigVerificationDecorator{
ak: ak,
signModeHandler: signModeHandler,
}
@ -49,7 +80,7 @@ func NewEip712SigVerificationDecorator(ak evmtypes.AccountKeeper, signModeHandle
// AnteHandle handles validation of EIP712 signed cosmos txs.
// it is not run on RecheckTx
func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
func (svd LegacyEip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
tx sdk.Tx,
simulate bool,
next sdk.AnteHandler,
@ -61,12 +92,12 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement authsigning.SigVerifiableTx", tx)
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "tx %T doesn't implement authsigning.SigVerifiableTx", tx)
}
authSignTx, ok := tx.(authsigning.Tx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement the authsigning.Tx interface", tx)
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.
@ -80,12 +111,16 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
// EIP712 allows just one signature
if len(sigs) != 1 {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signers (%d); EIP712 signatures allows just one signature", len(sigs))
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, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs))
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
@ -100,13 +135,13 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
// retrieve pubkey
pubKey := acc.GetPubKey()
if !simulate && pubKey == nil {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
return ctx, errorsmod.Wrap(errortypes.ErrInvalidPubKey, "pubkey on account is not set")
}
// Check account sequence number.
if sig.Sequence != acc.GetSequence() {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrWrongSequence,
return ctx, errorsmod.Wrapf(
errortypes.ErrWrongSequence,
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
)
}
@ -132,7 +167,7 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
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, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg.Error())
return ctx, errorsmod.Wrap(errortypes.ErrUnauthorized, errMsg.Error())
}
return next(ctx, tx, simulate)
@ -150,12 +185,12 @@ func VerifySignature(
switch data := sigData.(type) {
case *signing.SingleSignatureData:
if data.SignMode != signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON {
return sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "unexpected SignatureData %T: wrong SignMode", sigData)
return errorsmod.Wrapf(errortypes.ErrNotSupported, "unexpected SignatureData %T: wrong SignMode", sigData)
}
// Note: this prevents the user from sending thrash data in the signature field
// Note: this prevents the user from sending trash data in the signature field
if len(data.Signature) != 0 {
return sdkerrors.Wrap(sdkerrors.ErrTooManySignatures, "invalid signature value; EIP712 must have the cosmos transaction signature empty")
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),
@ -163,7 +198,7 @@ func VerifySignature(
msgs := tx.GetMsgs()
if len(msgs) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrNoSignatures, "tx doesn't contain any msgs to verify signature")
return errorsmod.Wrap(errortypes.ErrNoSignatures, "tx doesn't contain any msgs to verify signature")
}
txBytes := legacytx.StdSignBytes(
@ -180,33 +215,33 @@ func VerifySignature(
signerChainID, err := ethermint.ParseChainID(signerData.ChainID)
if err != nil {
return sdkerrors.Wrapf(err, "failed to parse chainID: %s", signerData.ChainID)
return errorsmod.Wrapf(err, "failed to parse chain-id: %s", signerData.ChainID)
}
txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx)
if !ok {
return sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, "tx doesnt contain any extensions")
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "tx doesnt contain any extensions")
}
opts := txWithExtensions.GetExtensionOptions()
if len(opts) != 1 {
return sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, "tx doesnt contain expected amount of extension options")
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "tx doesnt contain expected amount of extension options")
}
extOpt, ok := opts[0].GetCachedValue().(*ethermint.ExtensionOptionsWeb3Tx)
if !ok {
return sdkerrors.Wrap(sdkerrors.ErrInvalidChainID, "unknown extension option")
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "unknown extension option")
}
if extOpt.TypedDataChainID != signerChainID.Uint64() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidChainID, "invalid chainID")
return errorsmod.Wrap(errortypes.ErrInvalidChainID, "invalid chain-id")
}
if len(extOpt.FeePayer) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, "no feePayer on ExtensionOptionsWeb3Tx")
return errorsmod.Wrap(errortypes.ErrUnknownExtensionOptions, "no feePayer on ExtensionOptionsWeb3Tx")
}
feePayer, err := sdk.AccAddressFromBech32(extOpt.FeePayer)
if err != nil {
return sdkerrors.Wrap(err, "failed to parse feePayer from ExtensionOptionsWeb3Tx")
return errorsmod.Wrap(err, "failed to parse feePayer from ExtensionOptionsWeb3Tx")
}
feeDelegation := &eip712.FeeDelegationOptions{
@ -215,17 +250,17 @@ func VerifySignature(
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
if err != nil {
return sdkerrors.Wrap(err, "failed to pack tx data in EIP712 object")
return errorsmod.Wrap(err, "failed to create EIP-712 typed data from tx")
}
sigHash, err := eip712.ComputeTypedDataHash(typedData)
sigHash, _, err := apitypes.TypedDataAndHash(typedData)
if err != nil {
return err
}
feePayerSig := extOpt.FeePayerSig
if len(feePayerSig) != ethcrypto.SignatureLength {
return sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, "signature length doesn't match typical [R||S||V] signature 65 bytes")
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)
@ -235,12 +270,12 @@ func VerifySignature(
feePayerPubkey, err := secp256k1.RecoverPubkey(sigHash, feePayerSig)
if err != nil {
return sdkerrors.Wrap(err, "failed to recover delegated fee payer from sig")
return errorsmod.Wrap(err, "failed to recover delegated fee payer from sig")
}
ecPubKey, err := ethcrypto.UnmarshalPubkey(feePayerPubkey)
if err != nil {
return sdkerrors.Wrap(err, "failed to unmarshal recovered fee payer pubkey")
return errorsmod.Wrap(err, "failed to unmarshal recovered fee payer pubkey")
}
pk := &ethsecp256k1.PubKey{
@ -248,23 +283,23 @@ func VerifySignature(
}
if !pubKey.Equals(pk) {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "feePayer pubkey %s is different from transaction pubkey %s", pubKey, 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 sdkerrors.Wrapf(sdkerrors.ErrorInvalidSigner, "failed to verify delegated fee payer %s signature", recoveredFeePayerAcc)
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 sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, "unable to verify signer signature of EIP712 typed data")
return errorsmod.Wrap(errortypes.ErrorInvalidSigner, "unable to verify signer signature of EIP712 typed data")
}
return nil
default:
return sdkerrors.Wrapf(sdkerrors.ErrTooManySignatures, "unexpected SignatureData %T", sigData)
return errorsmod.Wrapf(errortypes.ErrTooManySignatures, "unexpected SignatureData %T", sigData)
}
}

View File

@ -1,19 +1,32 @@
// 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 (
"errors"
"math"
"math/big"
"strconv"
errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
ethermint "github.com/cerc-io/laconicd/types"
evmkeeper "github.com/cerc-io/laconicd/x/evm/keeper"
"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"
@ -21,61 +34,6 @@ import (
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()
params := esvd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.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, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
ethTx := msgEthTx.AsTransaction()
if !params.AllowUnprotectedTxs && !ethTx.Protected() {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrNotSupported,
"rejected unprotected Ethereum txs. Please EIP155 sign your transaction to protect it against replay-attacks")
}
sender, err := signer.Sender(ethTx)
if err != nil {
return ctx, sdkerrors.Wrapf(
sdkerrors.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)
}
// EthAccountVerificationDecorator validates an account balance checks
type EthAccountVerificationDecorator struct {
ak evmtypes.AccountKeeper
@ -109,35 +67,35 @@ func (avd EthAccountVerificationDecorator) AnteHandle(
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to unpack tx data any for tx %d", i)
return ctx, errorsmod.Wrapf(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, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "from address cannot be 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) //nolint: all
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, sdkerrors.Wrapf(sdkerrors.ErrInvalidType,
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType,
"the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash)
}
if err := evmkeeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil {
return ctx, sdkerrors.Wrap(err, "failed to check sender balance")
if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil {
return ctx, errorsmod.Wrap(err, "failed to check sender balance")
}
}
return next(ctx, tx, simulate)
@ -165,7 +123,7 @@ 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 inccured by additional bytes
// transaction is executed. The gas is a constant value plus any cost incurred by additional bytes
// of data supplied with the transaction.
//
// This AnteHandler decorator will fail if:
@ -175,31 +133,43 @@ func NewEthGasConsumeDecorator(
// - 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) {
params := egcd.evmKeeper.GetParams(ctx)
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)
}
ethCfg := params.ChainConfig.EthereumConfig(egcd.evmKeeper.ChainID())
chainCfg := egcd.evmKeeper.GetChainConfig(ctx)
ethCfg := chainCfg.EthereumConfig(egcd.evmKeeper.ChainID())
blockHeight := big.NewInt(ctx.BlockHeight())
homestead := ethCfg.IsHomestead(blockHeight)
istanbul := ethCfg.IsIstanbul(blockHeight)
london := ethCfg.IsLondon(blockHeight)
evmDenom := params.EvmDenom
gasWanted := uint64(0)
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() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrap(err, "failed to unpack tx data")
return ctx, errorsmod.Wrap(err, "failed to unpack tx data")
}
if ctx.IsCheckTx() && egcd.maxGasWanted != 0 {
@ -213,45 +183,59 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
gasWanted += txData.GetGas()
}
fees, priority, err := egcd.evmKeeper.DeductTxCostsFromUserBalance(
ctx,
*msgEthTx,
txData,
evmDenom,
homestead,
istanbul,
london,
)
evmDenom := egcd.evmKeeper.GetEVMDenom(ctx)
fees, err := keeper.VerifyFee(txData, evmDenom, baseFee, homestead, istanbul, ctx.IsCheckTx())
if err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to deduct transaction costs from user balance")
return ctx, errorsmod.Wrapf(err, "failed to verify the fees")
}
events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String())))
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()),
),
)
priority := evmtypes.GetTxPriority(txData, baseFee)
if priority < minPriority {
minPriority = priority
}
}
// 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)
// 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")
// 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,
)
}
// Set ctx.GasMeter with a limit of GasWanted (gasLimit)
gasConsumed := ctx.GasMeter().GasConsumed()
ctx = ctx.WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted))
ctx.GasMeter().ConsumeGas(gasConsumed, "copy gas consumed")
// 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.
newCtx := ctx.WithPriority(minPriority)
// 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)
@ -280,19 +264,35 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
baseFee := ctd.evmKeeper.GetBaseFee(ctx, ethCfg)
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
if err != nil {
return ctx, sdkerrors.Wrapf(
return ctx, errorsmod.Wrapf(
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,
@ -300,35 +300,20 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
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)
// 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, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFunds,
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 evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) {
if baseFee == nil {
return ctx, sdkerrors.Wrap(
evmtypes.ErrInvalidBaseFee,
"base fee is supported but evm block context value is nil",
)
}
if coreMsg.GasFeeCap().Cmp(baseFee) < 0 {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFee,
"max fee per gas less than block base fee (%s < %s)",
coreMsg.GasFeeCap(), baseFee,
)
}
}
}
return next(ctx, tx, simulate)
@ -353,19 +338,19 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrap(err, "failed to unpack tx data")
return ctx, errorsmod.Wrap(err, "failed to unpack tx data")
}
// increase sequence of sender
acc := issd.ak.GetAccount(ctx, msgEthTx.GetFrom())
if acc == nil {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrUnknownAddress,
return ctx, errorsmod.Wrapf(
errortypes.ErrUnknownAddress,
"account %s is nil", common.BytesToAddress(msgEthTx.GetFrom().Bytes()),
)
}
@ -374,14 +359,14 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
// 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, sdkerrors.Wrapf(
sdkerrors.ErrInvalidSequence,
return ctx, errorsmod.Wrapf(
errortypes.ErrInvalidSequence,
"invalid nonce; got %d, expected %d", txData.GetNonce(), nonce,
)
}
if err := acc.SetSequence(nonce + 1); err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1)
return ctx, errorsmod.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1)
}
issd.ak.SetAccount(ctx, acc)
@ -389,216 +374,3 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
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, sdkerrors.ErrNoSignatures) {
return ctx, sdkerrors.Wrap(err, "tx basic validation failed")
}
// For eth type cosmos tx, some fields should be veified 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, sdkerrors.Wrapf(sdkerrors.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, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty")
}
if len(body.ExtensionOptions) != 1 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1")
}
txFee := sdk.Coins{}
txGasLimit := uint64(0)
params := vbd.evmKeeper.GetParams(ctx)
chainID := vbd.evmKeeper.ChainID()
ethCfg := params.ChainConfig.EthereumConfig(chainID)
baseFee := vbd.evmKeeper.GetBaseFee(ctx, ethCfg)
for _, msg := range protoTx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
// Validate `From` field
if msgEthTx.From != "" {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid From %s, expect empty string", msgEthTx.From)
}
txGasLimit += msgEthTx.GetGas()
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrap(err, "failed to unpack MsgEthereumTx Data")
}
// return error if contract creation or call are disabled through governance
if !params.EnableCreate && txData.GetTo() == nil {
return ctx, sdkerrors.Wrap(evmtypes.ErrCreateDisabled, "failed to create new contract")
} else if !params.EnableCall && txData.GetTo() != nil {
return ctx, sdkerrors.Wrap(evmtypes.ErrCallDisabled, "failed to call contract")
}
if baseFee == nil && txData.TxType() == ethtypes.DynamicFeeTxType {
return ctx, sdkerrors.Wrap(ethtypes.ErrTxTypeNotSupported, "dynamic fee tx not supported")
}
txFee = txFee.Add(sdk.NewCoin(params.EvmDenom, sdkmath.NewIntFromBigInt(txData.Fee())))
}
authInfo := protoTx.AuthInfo
if len(authInfo.SignerInfos) > 0 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty")
}
if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty")
}
if !authInfo.Fee.Amount.IsEqual(txFee) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee Amount (%s != %s)", authInfo.Fee.Amount, txFee)
}
if authInfo.Fee.GasLimit != txGasLimit {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee GasLimit (%d != %d)", authInfo.Fee.GasLimit, txGasLimit)
}
sigs := protoTx.Signatures
if len(sigs) > 0 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty")
}
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 {
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 newCtx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
}
newCtx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
// 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)
}
// 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
}
func NewEthMempoolFeeDecorator(ek EVMKeeper) EthMempoolFeeDecorator {
return EthMempoolFeeDecorator{
evmKeeper: ek,
}
}
// AnteHandle ensures 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.
// It only do the check if london hardfork not enabled or feemarket not enabled, because in that case feemarket will take over the task.
func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if ctx.IsCheckTx() && !simulate {
params := mfd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(mfd.evmKeeper.ChainID())
baseFee := mfd.evmKeeper.GetBaseFee(ctx, ethCfg)
if baseFee == nil {
for _, msg := range tx.GetMsgs() {
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
evmDenom := params.EvmDenom
feeAmt := ethMsg.GetFee()
glDec := sdk.NewDec(int64(ethMsg.GetGas()))
requiredFee := ctx.MinGasPrices().AmountOf(evmDenom).Mul(glDec)
if sdk.NewDecFromBigInt(feeAmt).LT(requiredFee) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeAmt, requiredFee)
}
}
}
}
return next(ctx, 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, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
// emit ethereum tx hash as event, should be indexed by tm tx indexer for query purpose.
// 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)
}

View File

@ -9,65 +9,13 @@ import (
"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"
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
}
func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
dec := ante.NewEthAccountVerificationDecorator(
suite.app.AccountKeeper, suite.app.EvmKeeper,
@ -233,6 +181,9 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
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, &ethtypes.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
@ -269,6 +220,14 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
false, false,
0,
},
{
"gas limit above block gas limit",
tx3,
math.MaxUint64,
func() {},
false, false,
0,
},
{
"not enough balance for fees",
tx2,
@ -320,6 +279,17 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
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 {
@ -521,33 +491,3 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
})
}
}
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() {
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -4,12 +4,13 @@ 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"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
)
@ -64,7 +65,7 @@ func NewDynamicFeeChecker(k DynamicFeeEVMKeeper) authante.TxFeeChecker {
baseFeeInt := sdkmath.NewIntFromBigInt(baseFee)
if feeCap.LT(baseFeeInt) {
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient gas prices; got: %s required: %s", feeCap, 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.
@ -112,7 +113,7 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.FeeTx) (sdk.Coi
}
if !feeCoins.IsAnyGTE(requiredFees) {
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees)
return nil, 0, errorsmod.Wrapf(errortypes.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees)
}
}

View File

@ -3,8 +3,8 @@ package ante
import (
"math/big"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// GasWantedDecorator keeps track of the gasWanted amount on the current block in transient store
@ -27,8 +27,8 @@ func NewGasWantedDecorator(
}
func (gwd GasWantedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
params := gwd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(gwd.evmKeeper.ChainID())
chainCfg := gwd.evmKeeper.GetChainConfig(ctx)
ethCfg := chainCfg.EthereumConfig(gwd.evmKeeper.ChainID())
blockHeight := big.NewInt(ctx.BlockHeight())
isLondon := ethCfg.IsLondon(blockHeight)
@ -39,12 +39,12 @@ func (gwd GasWantedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo
}
gasWanted := feeTx.GetGas()
feeMktParams := gwd.feeMarketKeeper.GetParams(ctx)
isBaseFeeEnabled := gwd.feeMarketKeeper.GetBaseFeeEnabled(ctx)
// Add total gasWanted to cumulative in block transientStore in FeeMarket module
if feeMktParams.IsBaseFeeEnabled(ctx.BlockHeight()) {
if isBaseFeeEnabled {
if _, err := gwd.feeMarketKeeper.AddTransientGasWanted(ctx, gasWanted); err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to add gas wanted to transient store")
return ctx, errorsmod.Wrapf(err, "failed to add gas wanted to transient store")
}
}

View File

@ -3,8 +3,9 @@ package ante
import (
"math/big"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
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"
@ -20,14 +21,50 @@ type MinGasPriceDecorator struct {
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, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "invalid transaction type %T, expected sdk.FeeTx", tx)
}
minGasPrice := mpd.feesKeeper.GetParams(ctx).MinGasPrice
@ -37,10 +74,10 @@ func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
return next(ctx, tx, simulate)
}
evmParams := mpd.evmKeeper.GetParams(ctx)
evmDenom := mpd.evmKeeper.GetEVMDenom(ctx)
minGasPrices := sdk.DecCoins{
{
Denom: evmParams.EvmDenom,
Denom: evmDenom,
Amount: minGasPrice,
},
}
@ -62,7 +99,7 @@ func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
}
if !feeCoins.IsAnyGTE(requiredFees) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee,
return ctx, errorsmod.Wrapf(errortypes.ErrInsufficientFee,
"provided fee < minimum global fee (%s < %s). Please increase the gas price.",
feeCoins,
requiredFees)
@ -71,20 +108,8 @@ func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
return next(ctx, tx, simulate)
}
// 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
}
func NewEthMinGasPriceDecorator(fk FeeMarketKeeper, ek EVMKeeper) EthMinGasPriceDecorator {
return EthMinGasPriceDecorator{feesKeeper: fk, evmKeeper: ek}
}
// 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
@ -93,15 +118,15 @@ func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
return next(ctx, tx, simulate)
}
paramsEvm := empd.evmKeeper.GetParams(ctx)
ethCfg := paramsEvm.ChainConfig.EthereumConfig(empd.evmKeeper.ChainID())
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, sdkerrors.Wrapf(
sdkerrors.ErrUnknownRequest,
return ctx, errorsmod.Wrapf(
errortypes.ErrUnknownRequest,
"invalid message type %T, expected %T",
msg, (*evmtypes.MsgEthereumTx)(nil),
)
@ -120,7 +145,7 @@ func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
txData, err := evmtypes.UnpackTxData(ethMsg.Data)
if err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to unpack tx data %s", ethMsg.Hash)
return ctx, errorsmod.Wrapf(err, "failed to unpack tx data %s", ethMsg.Hash)
}
if txData.TxType() != ethtypes.LegacyTxType {
@ -133,8 +158,8 @@ func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
fee := sdk.NewDecFromBigInt(feeAmt)
if fee.LT(requiredFee) {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFee,
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(),
)
@ -143,3 +168,44 @@ func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
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)
}

View File

@ -42,7 +42,7 @@ func (s AnteTestSuite) TestMinGasPriceDecorator() {
return &invalidTx{}
},
false,
"must be a FeeTx",
"invalid transaction type",
false,
},
{
@ -345,3 +345,7 @@ func (s AnteTestSuite) TestEthMinGasPriceDecorator() {
}
}
}
func (suite AnteTestSuite) TestEthMempoolFeeDecorator() {
// TODO: add test
}

View File

@ -1,8 +1,9 @@
package ante
import (
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
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"
@ -20,7 +21,7 @@ type HandlerOptions struct {
AccountKeeper evmtypes.AccountKeeper
BankKeeper evmtypes.BankKeeper
IBCKeeper *ibckeeper.Keeper
FeeMarketKeeper evmtypes.FeeMarketKeeper
FeeMarketKeeper FeeMarketKeeper
EvmKeeper EVMKeeper
FeegrantKeeper ante.FeegrantKeeper
SignModeHandler authsigning.SignModeHandler
@ -31,20 +32,20 @@ type HandlerOptions struct {
}
func (options HandlerOptions) validate() error {
if options.AccountKeeper == evmtypes.AccountKeeper(nil) {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for AnteHandler")
if options.AccountKeeper == nil {
return errorsmod.Wrap(errortypes.ErrLogic, "account keeper is required for AnteHandler")
}
if options.BankKeeper == evmtypes.BankKeeper(nil) {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for AnteHandler")
if options.BankKeeper == nil {
return errorsmod.Wrap(errortypes.ErrLogic, "bank keeper is required for AnteHandler")
}
if options.SignModeHandler == authsigning.SignModeHandler(nil) {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
if options.SignModeHandler == nil {
return errorsmod.Wrap(errortypes.ErrLogic, "sign mode handler is required for ante builder")
}
if options.FeeMarketKeeper == evmtypes.FeeMarketKeeper(nil) {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "fee market keeper is required for AnteHandler")
if options.FeeMarketKeeper == nil {
return errorsmod.Wrap(errortypes.ErrLogic, "fee market keeper is required for AnteHandler")
}
if options.EvmKeeper == EVMKeeper(nil) {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "evm keeper is required for AnteHandler")
if options.EvmKeeper == nil {
return errorsmod.Wrap(errortypes.ErrLogic, "evm keeper is required for AnteHandler")
}
return nil
}
@ -70,9 +71,9 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler {
RejectMessagesDecorator{}, // reject MsgEthereumTxs
ante.NewSetUpContextDecorator(),
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
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),
@ -86,27 +87,3 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler {
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
)
}
func newCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler {
return sdk.ChainAnteDecorators(
RejectMessagesDecorator{}, // reject MsgEthereumTxs
ante.NewSetUpContextDecorator(),
// NOTE: extensions option decorator removed
// ante.NewRejectExtensionOptionsDecorator(),
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
ante.NewValidateBasicDecorator(),
ante.NewTxTimeoutHeightDecorator(),
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),
// Note: signature verification uses EIP instead of the cosmos signature validator
NewEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
ibcante.NewRedundantRelayDecorator(options.IBCKeeper),
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
)
}

View File

@ -28,12 +28,15 @@ type EVMKeeper interface {
DynamicFeeEVMKeeper
NewEVM(ctx sdk.Context, msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM
DeductTxCostsFromUserBalance(
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
) (fees sdk.Coins, priority int64, err error)
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 {
@ -44,4 +47,5 @@ type protoTxProvider interface {
type FeeMarketKeeper interface {
GetParams(ctx sdk.Context) (params feemarkettypes.Params)
AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error)
GetBaseFeeEnabled(ctx sdk.Context) bool
}

View File

@ -1,9 +1,10 @@
package ante
import (
errorsmod "cosmossdk.io/errors"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
)
// RejectMessagesDecorator prevents invalid msg types from being executed
@ -15,8 +16,8 @@ type RejectMessagesDecorator struct{}
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, sdkerrors.Wrapf(
sdkerrors.ErrInvalidType,
return ctx, errorsmod.Wrapf(
errortypes.ErrInvalidType,
"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
)
}

189
app/ante/setup.go Normal file
View File

@ -0,0 +1,189 @@
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)
}

42
app/ante/setup_test.go Normal file
View File

@ -0,0 +1,42 @@
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)
}
})
}
}

View File

@ -0,0 +1,64 @@
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
}

65
app/ante/sigverify.go Normal file
View File

@ -0,0 +1,65 @@
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)
}

View File

@ -15,26 +15,32 @@ import (
"github.com/cerc-io/laconicd/types"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
types2 "github.com/cosmos/cosmos-sdk/x/bank/types"
types3 "github.com/cosmos/cosmos-sdk/x/staking/types"
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/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"
@ -46,7 +52,8 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
evtypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
"github.com/cosmos/cosmos-sdk/x/feegrant"
types5 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
@ -92,6 +99,8 @@ func (suite *AnteTestSuite) SetupTest() {
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)
@ -111,6 +120,7 @@ func (suite *AnteTestSuite) SetupTest() {
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)
@ -263,41 +273,57 @@ func (suite *AnteTestSuite) CreateTestCosmosTxBuilder(gasPrice sdkmath.Int, deno
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 := types2.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
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 := types3.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
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 := types3.NewMsgCreateValidator(
msgCreate, err := stakingtypes.NewMsgCreateValidator(
valAddr,
privEd.PubKey(),
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)),
// TODO: can this values be empty strings?
types3.NewDescription("moniker", "indentity", "website", "security_contract", "details"),
types3.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
stakingtypes.NewDescription("moniker", "indentity", "website", "security_contract", "details"),
stakingtypes.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
sdk.OneInt(),
)
suite.Require().NoError(err)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgCreate)
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 := types5.ContentFromProposalType("My proposal", "My description", types5.ProposalTypeText)
proposal, ok := govtypes.ContentFromProposalType("My proposal", "My description", govtypes.ProposalTypeText)
suite.Require().True(ok)
msgSubmit, err := types5.NewMsgSubmitProposal(proposal, deposit, from)
msgSubmit, err := govtypes.NewMsgSubmitProposal(proposal, deposit, from)
suite.Require().NoError(err)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSubmit)
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 {
@ -311,18 +337,18 @@ func (suite *AnteTestSuite) CreateTestEIP712GrantAllowance(from sdk.AccAddress,
grantedAddr := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, granted.Bytes())
msgGrant, err := feegrant.NewMsgGrantAllowance(basic, from, grantedAddr.GetAddress())
suite.Require().NoError(err)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgGrant)
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 := types3.NewMsgEditValidator(
msgEdit := stakingtypes.NewMsgEditValidator(
valAddr,
types3.NewDescription("moniker", "identity", "website", "security_contract", "details"),
stakingtypes.NewDescription("moniker", "identity", "website", "security_contract", "details"),
nil,
nil,
)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgEdit)
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 {
@ -335,7 +361,72 @@ func (suite *AnteTestSuite) CreateTestEIP712MsgSubmitEvidence(from sdk.AccAddres
})
suite.Require().NoError(err)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgEvidence)
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.
@ -376,8 +467,14 @@ func StdSignBytes(cdc *codec.LegacyAmino, chainID string, accnum uint64, sequenc
return sdk.MustSortJSON(bz)
}
func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
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
@ -398,13 +495,13 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
fee := legacytx.NewStdFee(gas, gasAmount)
accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber()
data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, []sdk.Msg{msg}, "", nil)
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msg, data, &eip712.FeeDelegationOptions{
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 := eip712.ComputeTypedDataHash(typedData)
sigHash, _, err := apitypes.TypedDataAndHash(typedData)
suite.Require().NoError(err)
// Sign typedData
@ -442,12 +539,189 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
err = builder.SetSignatures(sigsV2)
suite.Require().NoError(err)
err = builder.SetMsgs(msg)
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
}

View File

@ -2,6 +2,7 @@ package app
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
@ -18,6 +19,7 @@ import (
"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"
@ -26,6 +28,7 @@ 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"
@ -101,6 +104,7 @@ import (
_ "github.com/cerc-io/laconicd/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"
@ -184,7 +188,7 @@ var (
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
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,
@ -199,8 +203,6 @@ var (
}
)
var _ simapp.App = (*EthermintApp)(nil)
// var _ server.Application (*EthermintApp)(nil)
// EthermintApp implements an extended ABCI application. It is an application
@ -256,9 +258,6 @@ type EthermintApp struct {
// the module manager
mm *module.Manager
// simulation manager
sm *module.SimulationManager
// the configurator
configurator module.Configurator
}
@ -280,6 +279,8 @@ func NewEthermintApp(
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,
@ -313,6 +314,12 @@ func NewEthermintApp(
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.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)
}
app := &EthermintApp{
BaseApp: bApp,
cdc: cdc,
@ -658,17 +665,6 @@ func NewEthermintApp(
// add test gRPC service for testing gRPC queries in isolation
// testdata.RegisterTestServiceServer(app.GRPCQueryRouter(), testdata.TestServiceImpl{})
// 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
overrideModules := map[string]module.AppModuleSimulation{
authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
}
app.sm = module.NewSimulationManagerFromAppModules(app.mm.Modules, overrideModules)
app.sm.RegisterStoreDecoders()
// initialize stores
app.MountKVStores(keys)
app.MountTransientStores(tkeys)
@ -718,6 +714,8 @@ func (app *EthermintApp) setAnteHandler(txConfig client.TxConfig, maxGasWanted u
EvmKeeper: app.EvmKeeper,
FeeMarketKeeper: app.FeeMarketKeeper,
MaxTxGasWanted: maxGasWanted,
ExtensionOptionChecker: ethermint.HasDynamicFeeExtensionOption,
// TxFeeChecker: ante.NewDynamicFeeChecker(app.EvmKeeper),
})
if err != nil {
panic(err)
@ -838,11 +836,6 @@ 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) {
@ -851,6 +844,8 @@ func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.
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.
ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
@ -876,6 +871,12 @@ func (app *EthermintApp) RegisterTendermintService(clientCtx client.Context) {
)
}
// 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())
}
// RegisterSwaggerAPI registers swagger route with API Server
func RegisterSwaggerAPI(_ client.Context, rtr *mux.Router) {
statikFS, err := fs.New()

View File

@ -1,414 +0,0 @@
package app
// TODO: COsmos SDK fix for the simulator issue for custom keys
import (
"encoding/json"
"fmt"
"math/rand"
"os"
"runtime/debug"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/cerc-io/laconicd/app/ante"
evmenc "github.com/cerc-io/laconicd/encoding"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/store"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
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"
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"
ibctransfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types"
ibchost "github.com/cosmos/ibc-go/v5/modules/core/24-host"
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"
)
// MakeEncodingConfig creates the EncodingConfig
func MakeEncodingConfig() params.EncodingConfig {
return evmenc.MakeConfig(ModuleBasics)
}
func init() {
simapp.GetSimulatorFlags()
}
const SimAppChainID = "simulation_777-1"
type storeKeysPrefixes struct {
A storetypes.StoreKey
B storetypes.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()
}
// NewSimApp disable feemarket on native tx, otherwise the cosmos-sdk simulation tests will fail.
func NewSimApp(logger log.Logger, db dbm.DB) (*EthermintApp, error) {
encodingConfig := MakeEncodingConfig()
app := NewEthermintApp(logger, db, nil, false, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, encodingConfig, simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
// disable feemarket on native tx
anteHandler, err := ante.NewAnteHandler(ante.HandlerOptions{
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
FeegrantKeeper: app.FeeGrantKeeper,
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
IBCKeeper: app.IBCKeeper,
EvmKeeper: app.EvmKeeper,
FeeMarketKeeper: app.FeeMarketKeeper,
MaxTxGasWanted: 0,
})
if err != nil {
return nil, err
}
app.SetAnteHandler(anteHandler)
if err := app.LoadLatestVersion(); err != nil {
return nil, err
}
return app, nil
}
// 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")
config.ChainID = SimAppChainID
defer func() {
require.NoError(t, db.Close())
require.NoError(t, os.RemoveAll(dir))
}()
app, err := NewSimApp(logger, db)
require.Equal(t, appName, app.Name())
require.NoError(t, err)
// run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
t,
os.Stdout,
app.BaseApp,
StateFn(app.AppCodec(), app.SimulationManager()),
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")
config.ChainID = SimAppChainID
defer func() {
require.NoError(t, db.Close())
require.NoError(t, os.RemoveAll(dir))
}()
app, err := NewSimApp(logger, db)
require.NoError(t, err)
require.Equal(t, appName, app.Name())
// Run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
t,
os.Stdout,
app.BaseApp,
StateFn(app.AppCodec(), app.SimulationManager()),
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() {
require.NoError(t, newDB.Close())
require.NoError(t, os.RemoveAll(newDir))
}()
newApp, err := NewSimApp(log.NewNopLogger(), newDB)
require.Equal(t, appName, newApp.Name())
require.NoError(t, err)
var genesisState simapp.GenesisState
err = json.Unmarshal(exported.AppState, &genesisState)
require.NoError(t, err)
defer func() {
if r := recover(); r != nil {
err := fmt.Sprintf("%v", r)
if !strings.Contains(err, "validator set is empty after InitGenesis") {
panic(r)
}
logger.Info("Skipping simulation as all validators have been unbonded")
logger.Info("err", err, "stacktrace", string(debug.Stack()))
}
}()
ctxA := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight(), ChainID: SimAppChainID})
ctxB := newApp.NewContext(true, tmproto.Header{Height: app.LastBlockHeight(), ChainID: SimAppChainID})
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[authzkeeper.StoreKey], newApp.keys[authzkeeper.StoreKey], [][]byte{authzkeeper.GrantKey, authzkeeper.GrantQueuePrefix}},
{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")
config.ChainID = SimAppChainID
defer func() {
require.NoError(t, db.Close())
require.NoError(t, os.RemoveAll(dir))
}()
app, err := NewSimApp(logger, db)
require.Equal(t, appName, app.Name())
require.NoError(t, err)
// Run randomized simulation
stopEarly, simParams, simErr := simulation.SimulateFromSeed(
t,
os.Stdout,
app.BaseApp,
StateFn(app.AppCodec(), app.SimulationManager()),
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)
defer func() {
if r := recover(); r != nil {
err := fmt.Sprintf("%v", r)
if !strings.Contains(err, "validator set is empty after InitGenesis") {
panic(r)
}
logger.Info("Skipping simulation as all validators have been unbonded")
logger.Info("err", err, "stacktrace", string(debug.Stack()))
}
}()
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() {
require.NoError(t, newDB.Close())
require.NoError(t, os.RemoveAll(newDir))
}()
newApp, err := NewSimApp(log.NewNopLogger(), newDB)
require.Equal(t, appName, newApp.Name())
require.NoError(t, err)
newApp.InitChain(abci.RequestInitChain{
ChainId: SimAppChainID,
AppStateBytes: exported.AppState,
})
_, _, err = simulation.SimulateFromSeed(
t,
os.Stdout,
newApp.BaseApp,
StateFn(app.AppCodec(), app.SimulationManager()),
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 = 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, err := NewSimApp(logger, db)
require.NoError(t, err)
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,
StateFn(app.AppCodec(), app.SimulationManager()),
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,
)
}
}
}
}

View File

@ -5,27 +5,21 @@ import (
"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"
"github.com/cosmos/cosmos-sdk/types/module"
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"
ethermint "github.com/cerc-io/laconicd/types"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
@ -94,22 +88,27 @@ func SetupWithDB(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.Genesis
return app
}
// RandomGenesisAccounts is used by the auth module to create random genesis accounts in simulation when a genesis.json is not specified.
// In contrast, the default auth module's RandomGenesisAccounts implementation creates only base accounts and vestings accounts.
func RandomGenesisAccounts(simState *module.SimulationState) authtypes.GenesisAccounts {
emptyCodeHash := crypto.Keccak256(nil)
genesisAccs := make(authtypes.GenesisAccounts, len(simState.Accounts))
for i, acc := range simState.Accounts {
bacc := authtypes.NewBaseAccountWithAddress(acc.Address)
ethacc := &ethermint.EthAccount{
BaseAccount: bacc,
CodeHash: common.BytesToHash(emptyCodeHash).String(),
// 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)
}
genesisAccs[i] = ethacc
// 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))),
}
return genesisAccs
genesisState := NewDefaultGenesisState()
return genesisStateWithValSet(codec, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance)
}
// RandomAccounts creates random accounts with an ethsecp256k1 private key
@ -135,78 +134,6 @@ func RandomAccounts(r *rand.Rand, n int) []simtypes.Account {
return accs
}
// StateFn returns the initial application state using a genesis or the simulation parameters.
// It is a wrapper of simapp.AppStateFn to replace evm param EvmDenom with staking param BondDenom.
func StateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simtypes.AppStateFn {
return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config,
) (appState json.RawMessage, simAccs []simtypes.Account, chainID string, genesisTimestamp time.Time) {
appStateFn := simapp.AppStateFn(cdc, simManager)
appState, simAccs, chainID, genesisTimestamp = appStateFn(r, accs, config)
rawState := make(map[string]json.RawMessage)
err := json.Unmarshal(appState, &rawState)
if err != nil {
panic(err)
}
stakingStateBz, ok := rawState[stakingtypes.ModuleName]
if !ok {
panic("staking genesis state is missing")
}
stakingState := new(stakingtypes.GenesisState)
cdc.MustUnmarshalJSON(stakingStateBz, stakingState)
// we should get the BondDenom and make it the evmdenom.
// thus simulation accounts could have positive amount of gas token.
bondDenom := stakingState.Params.BondDenom
evmStateBz, ok := rawState[evmtypes.ModuleName]
if !ok {
panic("evm genesis state is missing")
}
evmState := new(evmtypes.GenesisState)
cdc.MustUnmarshalJSON(evmStateBz, evmState)
// we should replace the EvmDenom with BondDenom
evmState.Params.EvmDenom = bondDenom
// change appState back
rawState[evmtypes.ModuleName] = cdc.MustMarshalJSON(evmState)
// replace appstate
appState, err = json.Marshal(rawState)
if err != nil {
panic(err)
}
return appState, simAccs, chainID, genesisTimestamp
}
}
// 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)
}
func genesisStateWithValSet(codec codec.Codec, genesisState simapp.GenesisState,
valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount,
balances ...banktypes.Balance,

View File

@ -1,113 +0,0 @@
package app
import (
"encoding/json"
"math/rand"
"os"
"testing"
"github.com/stretchr/testify/require"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
ethermint "github.com/cerc-io/laconicd/types"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var (
maxTestingAccounts = 100
seed = int64(233)
)
func TestRandomGenesisAccounts(t *testing.T) {
r := rand.New(rand.NewSource(seed))
accs := RandomAccounts(r, rand.Intn(maxTestingAccounts))
encodingConfig := MakeEncodingConfig()
appCodec := encodingConfig.Codec
cdc := encodingConfig.Amino
paramsKeeper := initParamsKeeper(appCodec, cdc, sdk.NewKVStoreKey(paramstypes.StoreKey), sdk.NewTransientStoreKey(paramstypes.StoreKey))
subSpace, find := paramsKeeper.GetSubspace(authtypes.ModuleName)
require.True(t, find)
accountKeeper := authkeeper.NewAccountKeeper(
appCodec, sdk.NewKVStoreKey(authtypes.StoreKey), subSpace, ethermint.ProtoAccount, maccPerms, sdk.GetConfig().GetBech32AccountAddrPrefix(),
)
authModule := auth.NewAppModule(appCodec, accountKeeper, RandomGenesisAccounts)
genesisState := simapp.NewDefaultGenesisState(appCodec)
simState := &module.SimulationState{Accounts: accs, Cdc: appCodec, Rand: r, GenState: genesisState}
authModule.GenerateGenesisState(simState)
authStateBz, find := genesisState[authtypes.ModuleName]
require.True(t, find)
authState := new(authtypes.GenesisState)
appCodec.MustUnmarshalJSON(authStateBz, authState)
accounts, err := authtypes.UnpackAccounts(authState.Accounts)
require.NoError(t, err)
for _, acc := range accounts {
_, ok := acc.(ethermint.EthAccountI)
require.True(t, ok)
}
}
func TestStateFn(t *testing.T) {
config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
if skip {
t.Skip("skipping AppStateFn testing")
}
require.NoError(t, err, "simulation setup failed")
config.ChainID = SimAppChainID
config.Commit = true
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())
appStateFn := StateFn(app.AppCodec(), app.SimulationManager())
r := rand.New(rand.NewSource(seed))
accounts := RandomAccounts(r, rand.Intn(maxTestingAccounts))
appState, _, _, _ := appStateFn(r, accounts, config)
rawState := make(map[string]json.RawMessage)
err = json.Unmarshal(appState, &rawState)
require.NoError(t, err)
stakingStateBz, ok := rawState[stakingtypes.ModuleName]
require.True(t, ok)
stakingState := new(stakingtypes.GenesisState)
app.AppCodec().MustUnmarshalJSON(stakingStateBz, stakingState)
bondDenom := stakingState.Params.BondDenom
evmStateBz, ok := rawState[evmtypes.ModuleName]
require.True(t, ok)
evmState := new(evmtypes.GenesisState)
app.AppCodec().MustUnmarshalJSON(evmStateBz, evmState)
require.Equal(t, bondDenom, evmState.Params.EvmDenom)
}
func TestRandomAccounts(t *testing.T) {
r := rand.New(rand.NewSource(seed))
accounts := RandomAccounts(r, rand.Intn(maxTestingAccounts))
for _, acc := range accounts {
_, ok := acc.PrivKey.(*ethsecp256k1.PrivKey)
require.True(t, ok)
}
}

View File

@ -1,4 +1,3 @@
version: v1
directories:
- proto
- third_party/proto

View File

@ -13,57 +13,6 @@
"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"
}
}
}
]
}

File diff suppressed because one or more lines are too long

View File

@ -154,10 +154,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -369,10 +372,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -583,10 +589,20 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
<<<<<<< HEAD
any, err := ptypes.MarshalAny(foo)
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
=======
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := any.UnmarshalTo(foo); err != nil {
>>>>>>> v0.20.0
...
}
@ -791,10 +807,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -1014,10 +1033,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -1226,10 +1248,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -1301,6 +1326,18 @@ paths:
required: false
type: string
format: uint64
- name: proposer_address
description: the proposer of the requested block.
in: query
required: false
type: string
format: byte
- name: chain_id
description: the eip155 chain id parsed from the requested block header.
in: query
required: false
type: string
format: int64
tags:
- Query
/ethermint/evm/v1/eth_call:
@ -1524,10 +1561,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -1599,6 +1639,18 @@ paths:
required: false
type: string
format: uint64
- name: proposer_address
description: the proposer of the requested block.
in: query
required: false
type: string
format: byte
- name: chain_id
description: the eip155 chain id parsed from the requested block header.
in: query
required: false
type: string
format: int64
tags:
- Query
/ethermint/evm/v1/params:
@ -1713,11 +1765,24 @@ paths:
title: >-
Eip-4345 (bomb delay) switch block (nil = no fork, 0 =
already activated)
<<<<<<< HEAD
merge_fork_block:
type: string
title: >-
EIP-3675 (TheMerge) switch block (nil = no fork, 0 =
already in merge proceedings)
=======
gray_glacier_block:
type: string
title: >-
EIP-5133 (bomb delay) switch block (nil = no fork, 0 =
already activated)
merge_netsplit_block:
type: string
title: >-
Virtual fork after The Merge to use as a network
splitter
>>>>>>> v0.20.0
description: >-
ChainConfig defines the Ethereum ChainConfig parameters
using *sdk.Int values
@ -1727,7 +1792,11 @@ paths:
type: boolean
description: >-
Allow unprotected transactions defines if replay-protected
<<<<<<< HEAD
(i.e non EIP155
=======
(i.e non EIP155
>>>>>>> v0.20.0
signed) transactions can be executed on the state machine.
title: Params defines the EVM module parameters
@ -1861,10 +1930,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -2072,10 +2144,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -2292,10 +2367,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -2481,10 +2559,22 @@ paths:
in: query
required: false
type: string
<<<<<<< HEAD
- name: trace_config.overrides.merge_fork_block
description: >-
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
merge proceedings).
=======
- name: trace_config.overrides.gray_glacier_block
description: >-
EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already
activated).
in: query
required: false
type: string
- name: trace_config.overrides.merge_netsplit_block
description: Virtual fork after The Merge to use as a network splitter.
>>>>>>> v0.20.0
in: query
required: false
type: string
@ -2498,6 +2588,11 @@ paths:
in: query
required: false
type: boolean
- name: trace_config.tracer_json_config
description: tracer config.
in: query
required: false
type: string
- name: block_number
description: block number.
in: query
@ -2515,6 +2610,18 @@ paths:
required: false
type: string
format: date-time
- name: proposer_address
description: the proposer of the requested block.
in: query
required: false
type: string
format: byte
- name: chain_id
description: the eip155 chain id parsed from the requested block header.
in: query
required: false
type: string
format: int64
tags:
- Query
/ethermint/evm/v1/trace_tx:
@ -2659,10 +2766,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -2783,7 +2893,7 @@ paths:
type: string
format: byte
- name: msg.size
description: encoded storage size of the transaction.
description: 'DEPRECATED: encoded storage size of the transaction.'
in: query
required: false
type: number
@ -2927,10 +3037,22 @@ paths:
in: query
required: false
type: string
<<<<<<< HEAD
- name: trace_config.overrides.merge_fork_block
description: >-
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
merge proceedings).
=======
- name: trace_config.overrides.gray_glacier_block
description: >-
EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already
activated).
in: query
required: false
type: string
- name: trace_config.overrides.merge_netsplit_block
description: Virtual fork after The Merge to use as a network splitter.
>>>>>>> v0.20.0
in: query
required: false
type: string
@ -2944,6 +3066,11 @@ paths:
in: query
required: false
type: boolean
- name: trace_config.tracer_json_config
description: tracer config.
in: query
required: false
type: string
- name: block_number
description: block number of requested transaction.
in: query
@ -2961,6 +3088,18 @@ paths:
required: false
type: string
format: date-time
- name: proposer_address
description: the proposer of the requested block.
in: query
required: false
type: string
format: byte
- name: chain_id
description: the eip155 chain id parsed from the requested block header.
in: query
required: false
type: string
format: int64
tags:
- Query
/ethermint/evm/v1/validator_account/{cons_address}:
@ -3120,10 +3259,13 @@ paths:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -3190,6 +3332,7 @@ paths:
type: string
tags:
- Query
<<<<<<< HEAD
/cosmos/auth/v1beta1/accounts:
get:
summary: Accounts returns all the existing accounts
@ -14052,6 +14195,8 @@ paths:
type: boolean
tags:
- Query
=======
>>>>>>> v0.20.0
definitions:
ethermint.evm.v1.ChainConfig:
type: object
@ -14111,11 +14256,22 @@ definitions:
title: >-
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
activated)
<<<<<<< HEAD
merge_fork_block:
type: string
title: >-
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in merge
proceedings)
=======
gray_glacier_block:
type: string
title: >-
EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already
activated)
merge_netsplit_block:
type: string
title: Virtual fork after The Merge to use as a network splitter
>>>>>>> v0.20.0
description: >-
ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int
values
@ -14287,10 +14443,13 @@ definitions:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -14344,7 +14503,7 @@ definitions:
size:
type: number
format: double
title: encoded storage size of the transaction
title: 'DEPRECATED: encoded storage size of the transaction'
hash:
type: string
title: transaction hash in hex format
@ -14515,11 +14674,22 @@ definitions:
title: >-
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
activated)
<<<<<<< HEAD
merge_fork_block:
type: string
title: >-
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
merge proceedings)
=======
gray_glacier_block:
type: string
title: >-
EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already
activated)
merge_netsplit_block:
type: string
title: Virtual fork after The Merge to use as a network splitter
>>>>>>> v0.20.0
description: >-
ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int
values
@ -14529,7 +14699,11 @@ definitions:
type: boolean
description: >-
Allow unprotected transactions defines if replay-protected (i.e non
<<<<<<< HEAD
EIP155
=======
EIP155
>>>>>>> v0.20.0
signed) transactions can be executed on the state machine.
title: Params defines the EVM module parameters
@ -14684,11 +14858,22 @@ definitions:
title: >-
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
activated)
<<<<<<< HEAD
merge_fork_block:
type: string
title: >-
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already
in merge proceedings)
=======
gray_glacier_block:
type: string
title: >-
EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already
activated)
merge_netsplit_block:
type: string
title: Virtual fork after The Merge to use as a network splitter
>>>>>>> v0.20.0
description: >-
ChainConfig defines the Ethereum ChainConfig parameters using
*sdk.Int values
@ -14698,7 +14883,11 @@ definitions:
type: boolean
description: >-
Allow unprotected transactions defines if replay-protected (i.e
<<<<<<< HEAD
non EIP155
=======
non EIP155
>>>>>>> v0.20.0
signed) transactions can be executed on the state machine.
title: Params defines the EVM module parameters
@ -14839,11 +15028,22 @@ definitions:
title: >-
Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already
activated)
<<<<<<< HEAD
merge_fork_block:
type: string
title: >-
EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in
merge proceedings)
=======
gray_glacier_block:
type: string
title: >-
EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already
activated)
merge_netsplit_block:
type: string
title: Virtual fork after The Merge to use as a network splitter
>>>>>>> v0.20.0
description: >-
ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int
values
@ -14855,6 +15055,9 @@ definitions:
enable_return_data:
type: boolean
title: enable return data capture
tracer_json_config:
type: string
title: tracer config
description: TraceConfig holds extra parameters to trace functions.
google.protobuf.Any:
type: object
@ -14958,10 +15161,13 @@ definitions:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -15132,10 +15338,13 @@ definitions:
Example 4: Pack and unpack a message in Go
foo := &pb.Foo{...}
any, err := ptypes.MarshalAny(foo)
any, err := anypb.New(foo)
if err != nil {
...
}
...
foo := &pb.Foo{}
if err := ptypes.UnmarshalAny(any, foo); err != nil {
if err := any.UnmarshalTo(foo); err != nil {
...
}
@ -15185,6 +15394,7 @@ definitions:
"@type": "type.googleapis.com/google.protobuf.Duration",
"value": "1.212s"
}
<<<<<<< HEAD
cosmos.auth.v1beta1.Params:
type: object
properties:
@ -21145,3 +21355,5 @@ definitions:
application's
state transition machine.
=======
>>>>>>> v0.20.0

View File

@ -50,18 +50,32 @@ output
- armor encrypted private key (saved to file)
*/
func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *bufio.Reader) error {
var err error
var (
algo keyring.SignatureAlgo
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, _ := kb.SupportedAlgorithms()
algoStr, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm)
algo, err := keyring.NewSigningAlgoFromString(algoStr, keyringAlgos)
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)
}
if err != nil {
return err
}
@ -144,7 +158,6 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
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()
@ -155,7 +168,9 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
// If we're using ledger, only thing we need is the path and the bech32 prefix.
if useLedger {
bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix()
k, err := kb.SaveLedgerKey(name, hd.Secp256k1, bech32PrefixAccAddr, coinType, account, index)
// use the provided algo to save the ledger key
k, err := kb.SaveLedgerKey(name, algo, bech32PrefixAccAddr, coinType, account, index)
if err != nil {
return err
}

View File

@ -8,9 +8,7 @@ import (
"github.com/cerc-io/laconicd/version"
)
const (
flagLong = "long"
)
const flagLong = "long"
func init() {
infoCmd.Flags().Bool(flagLong, false, "Print full information")

View File

@ -32,7 +32,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][,[coin]]",
Use: "add-genesis-account ADDRESS_OR_KEY_NAME 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,

View File

@ -37,13 +37,14 @@ import (
"github.com/cerc-io/laconicd/client/debug"
"github.com/cerc-io/laconicd/crypto/hd"
"github.com/cerc-io/laconicd/encoding"
"github.com/cerc-io/laconicd/ethereum/eip712"
"github.com/cerc-io/laconicd/server"
servercfg "github.com/cerc-io/laconicd/server/config"
srvflags "github.com/cerc-io/laconicd/server/flags"
ethermint "github.com/cerc-io/laconicd/types"
)
const EnvPrefix = "ETHERMINT"
const EnvPrefix = "LACONIC"
// NewRootCmd creates a new root command for simd. It is called once in the
// main function.
@ -61,9 +62,11 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
WithKeyringOptions(hd.EthSecp256k1Option()).
WithViper(EnvPrefix)
eip712.SetEncodingConfig(encodingConfig)
rootCmd := &cobra.Command{
Use: "laconicd",
Short: "Ethermint Daemon",
Short: "Laconic Daemon",
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
// set the default command outputs
cmd.SetOut(cmd.OutOrStdout())
@ -182,6 +185,7 @@ func txCommand() *cobra.Command {
authcmd.GetBroadcastCommand(),
authcmd.GetEncodeCommand(),
authcmd.GetDecodeCommand(),
authcmd.GetAuxToFeeCommand(),
)
app.ModuleBasics.AddTxCommands(cmd)
@ -246,6 +250,8 @@ func (a appCreator) newApp(logger tmlog.Logger, db dbm.DB, traceStore io.Writer,
baseapp.SetTrace(cast.ToBool(appOpts.Get(sdkserver.FlagTrace))),
baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(sdkserver.FlagIndexEvents))),
baseapp.SetSnapshot(snapshotStore, snapshotOptions),
baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(sdkserver.FlagIAVLCacheSize))),
baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(sdkserver.FlagDisableIAVLFastNode))),
)
return ethermintApp

View File

@ -6,11 +6,12 @@ import (
"crypto/subtle"
"fmt"
errorsmod "cosmossdk.io/errors"
"github.com/cerc-io/laconicd/ethereum/eip712"
"github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/crypto"
tmcrypto "github.com/tendermint/tendermint/crypto"
)
@ -182,7 +183,7 @@ func (pubKey PubKey) MarshalAmino() ([]byte, error) {
// UnmarshalAmino overrides Amino binary marshaling.
func (pubKey *PubKey) UnmarshalAmino(bz []byte) error {
if len(bz) != PubKeySize {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "invalid pubkey size, expected %d, got %d", PubKeySize, len(bz))
return errorsmod.Wrapf(errortypes.ErrInvalidPubKey, "invalid pubkey size, expected %d, got %d", PubKeySize, len(bz))
}
pubKey.Key = bz
@ -203,10 +204,28 @@ func (pubKey *PubKey) UnmarshalAminoJSON(bz []byte) error {
// VerifySignature verifies that the ECDSA public key created a given signature over
// the provided message. It will calculate the Keccak256 hash of the message
// prior to verification.
// prior to verification and approve verification if the signature can be verified
// from either the original message or its EIP-712 representation.
//
// CONTRACT: The signature should be in [R || S] format.
func (pubKey PubKey) VerifySignature(msg, sig []byte) bool {
return pubKey.verifySignatureECDSA(msg, sig) || pubKey.verifySignatureAsEIP712(msg, sig)
}
// Verifies the signature as an EIP-712 signature by first converting the message payload
// to EIP-712 object bytes, then performing ECDSA verification on the hash. This is to support
// signing a Cosmos payload using EIP-712.
func (pubKey PubKey) verifySignatureAsEIP712(msg, sig []byte) bool {
eip712Bytes, err := eip712.GetEIP712BytesForMsg(msg)
if err != nil {
return false
}
return pubKey.verifySignatureECDSA(eip712Bytes, sig)
}
// Perform standard ECDSA signature verification for the given raw bytes and signature.
func (pubKey PubKey) verifySignatureECDSA(msg, sig []byte) bool {
if len(sig) == crypto.SignatureLength {
// remove recovery ID (V) if contained in the signature
sig = sig[:len(sig)-1]

View File

@ -5,7 +5,7 @@ package ethsecp256k1
import (
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
_ "github.com/cosmos/gogoproto/gogoproto"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
@ -27,6 +27,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// Tendermint's PubKey interface. It represents the 33-byte compressed public
// key format.
type PubKey struct {
// key is the public key in byte form
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
}
@ -72,6 +73,7 @@ func (m *PubKey) GetKey() []byte {
// PrivKey defines a type alias for an ecdsa.PrivateKey that implements
// Tendermint's PrivateKey interface.
type PrivKey struct {
// key is the private key in byte form
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
}

View File

@ -1,6 +1,7 @@
package hd
import (
"os"
"strings"
"testing"
@ -10,7 +11,6 @@ import (
hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
"github.com/cosmos/cosmos-sdk/codec"
amino "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
@ -20,10 +20,10 @@ import (
ethermint "github.com/cerc-io/laconicd/types"
)
var TestCodec codec.Codec
var TestCodec amino.Codec
func init() {
cdc := codec.NewLegacyAmino()
cdc := amino.NewLegacyAmino()
cryptocodec.RegisterCrypto(cdc)
interfaceRegistry := types.NewInterfaceRegistry()
@ -31,12 +31,18 @@ func init() {
enccodec.RegisterInterfaces(interfaceRegistry)
}
const mnemonic = "picnic rent average infant boat squirrel federal assault mercy purity very motor fossil wheel verify upset box fresh horse vivid copy predict square regret"
const (
mnemonic = "picnic rent average infant boat squirrel federal assault mercy purity very motor fossil wheel verify upset box fresh horse vivid copy predict square regret"
// hdWalletFixEnv defines whether the standard (correct) bip39
// derivation path was used, or if derivation was affected by
// https://github.com/btcsuite/btcutil/issues/172
hdWalletFixEnv = "GO_ETHEREUM_HDWALLET_FIX_ISSUE_179"
)
func TestKeyring(t *testing.T) {
dir := t.TempDir()
mockIn := strings.NewReader("")
kr, err := keyring.New("ethermint", keyring.BackendTest, dir, mockIn, TestCodec, EthSecp256k1Option())
require.NoError(t, err)
@ -68,7 +74,9 @@ func TestKeyring(t *testing.T) {
privkey := EthSecp256k1.Generate()(bz)
addr := common.BytesToAddress(privkey.PubKey().Address().Bytes())
os.Setenv(hdWalletFixEnv, "true")
wallet, err := hdwallet.NewFromMnemonic(mnemonic)
os.Setenv(hdWalletFixEnv, "")
require.NoError(t, err)
path := hdwallet.MustParseDerivationPath(hdPath)

View File

@ -423,6 +423,7 @@ TraceConfig holds extra parameters to trace functions.
| `overrides` | [ChainConfig](#ethermint.evm.v1.ChainConfig) | | Chain overrides, can be used to execute a trace using future fork rules |
| `enable_memory` | [bool](#bool) | | enable memory capture |
| `enable_return_data` | [bool](#bool) | | enable return data capture |
| `tracer_json_config` | [string](#string) | | tracer config |
@ -710,6 +711,8 @@ EthCallRequest defines EthCall request
| ----- | ---- | ----- | ----------- |
| `args` | [bytes](#bytes) | | same json format as the json rpc api. |
| `gas_cap` | [uint64](#uint64) | | the default gas cap to be used |
| `proposer_address` | [bytes](#bytes) | | the proposer of the requested block |
| `chain_id` | [int64](#int64) | | the eip155 chain id parsed from the requested block header |
@ -939,6 +942,8 @@ QueryTraceBlockRequest defines TraceTx request
| `block_number` | [int64](#int64) | | block number |
| `block_hash` | [string](#string) | | block hex hash |
| `block_time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | block time |
| `proposer_address` | [bytes](#bytes) | | the proposer of the requested block |
| `chain_id` | [int64](#int64) | | the eip155 chain id parsed from the requested block header |
@ -974,6 +979,8 @@ QueryTraceTxRequest defines TraceTx request
| `block_number` | [int64](#int64) | | block number of requested transaction |
| `block_hash` | [string](#string) | | block hex hash of requested transaction |
| `block_time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | block time of requested transaction |
| `proposer_address` | [bytes](#bytes) | | the proposer of the requested block |
| `chain_id` | [int64](#int64) | | the eip155 chain id parsed from the requested block header |

View File

@ -14,35 +14,17 @@ import (
"golang.org/x/text/cases"
"golang.org/x/text/language"
errorsmod "cosmossdk.io/errors"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
registry "github.com/cerc-io/laconicd/x/registry/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
)
// ComputeTypedDataHash computes keccak hash of typed data for signing.
func ComputeTypedDataHash(typedData apitypes.TypedData) ([]byte, error) {
domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
if err != nil {
err = sdkerrors.Wrap(err, "failed to pack and hash typedData EIP712Domain")
return nil, err
}
typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
if err != nil {
err = sdkerrors.Wrap(err, "failed to pack and hash typedData primary type")
return nil, err
}
rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash)))
return crypto.Keccak256(rawData), nil
}
// WrapTxToTypedData is an ultimate method that wraps Amino-encoded Cosmos Tx JSON data
// into an EIP712-compatible TypedData request.
func WrapTxToTypedData(
@ -55,7 +37,7 @@ func WrapTxToTypedData(
txData := make(map[string]interface{})
if err := json.Unmarshal(data, &txData); err != nil {
return apitypes.TypedData{}, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, "failed to JSON unmarshal data")
return apitypes.TypedData{}, errorsmod.Wrap(errortypes.ErrJSONUnmarshal, "failed to JSON unmarshal data")
}
if txData["msgs"].([]interface{})[0].(map[string]interface{})["value"].(map[string]interface{})["payload"] != nil {
@ -65,7 +47,7 @@ func WrapTxToTypedData(
attr = append(attr, fmt.Sprintf("%v", b))
}
txData["msgs"].([]interface{})[0].(map[string]interface{})["value"].(map[string]interface{})["payload"].(map[string]interface{})["record"].(map[string]interface{})["attributes"] = map[string]interface{}{
txData["msgs"].([]interface{})[0].(map[string]interface{})["value"].(map[string]interface{})["payload"].(map[string]interface{})["record"].(map[string]interface{})["attributes"] = map[string]interface{}{ //nolint:lll
"type_url": setRecordMsg.Payload.Record.Attributes.TypeUrl,
"value": attr,
}
@ -105,7 +87,7 @@ func WrapTxToTypedData(
if feeDelegation != nil {
feeInfo, ok := txData["fee"].(map[string]interface{})
if !ok {
return apitypes.TypedData{}, sdkerrors.Wrap(sdkerrors.ErrInvalidType, "cannot parse fee from tx data")
return apitypes.TypedData{}, errorsmod.Wrap(errortypes.ErrInvalidType, "cannot parse fee from tx data")
}
feeInfo["feePayer"] = feeDelegation.FeePayer.String()
@ -238,7 +220,11 @@ func traverseFields(
}
for i := 0; i < n; i++ {
var field reflect.Value
var (
field reflect.Value
err error
)
if v.IsValid() {
field = v.Field(i)
}
@ -247,23 +233,15 @@ func traverseFields(
fieldName := jsonNameFromTag(t.Field(i).Tag)
if fieldType == cosmosAnyType {
any, ok := field.Interface().(*codectypes.Any)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrPackAny, "%T", field.Interface())
// Unpack field, value as Any
if fieldType, field, err = unpackAny(cdc, field); err != nil {
return err
}
}
anyWrapper := &cosmosAnyWrapper{
Type: any.TypeUrl,
}
if err := cdc.UnpackAny(any, &anyWrapper.Value); err != nil {
return sdkerrors.Wrap(err, "failed to unpack Any in msg struct")
}
fieldType = reflect.TypeOf(anyWrapper)
field = reflect.ValueOf(anyWrapper)
// then continue as normal
// If field is an empty value, do not include in types, since it will not be present in the object
if field.IsZero() {
continue
}
// If its a nil pointer, do not include in types
@ -305,6 +283,12 @@ func traverseFields(
fieldType = fieldType.Elem()
field = field.Index(0)
isCollection = true
if fieldType == cosmosAnyType {
if fieldType, field, err = unpackAny(cdc, field); err != nil {
return err
}
}
}
for {
@ -395,6 +379,27 @@ func jsonNameFromTag(tag reflect.StructTag) string {
return parts[0]
}
// Unpack the given Any value with Type/Value deconstruction
func unpackAny(cdc codectypes.AnyUnpacker, field reflect.Value) (reflect.Type, reflect.Value, error) {
any, ok := field.Interface().(*codectypes.Any)
if !ok {
return nil, reflect.Value{}, errorsmod.Wrapf(errortypes.ErrPackAny, "%T", field.Interface())
}
anyWrapper := &cosmosAnyWrapper{
Type: any.TypeUrl,
}
if err := cdc.UnpackAny(any, &anyWrapper.Value); err != nil {
return nil, reflect.Value{}, errorsmod.Wrap(err, "failed to unpack Any in msg struct")
}
fieldType := reflect.TypeOf(anyWrapper)
field = reflect.ValueOf(anyWrapper)
return fieldType, field, nil
}
// _.foo_bar.baz -> TypeFooBarBaz
//
// this is needed for Geth's own signing code which doesn't
@ -497,7 +502,7 @@ func typToEth(typ reflect.Type) string {
func doRecover(err *error) {
if r := recover(); r != nil {
if e, ok := r.(error); ok {
e = sdkerrors.Wrap(e, "panicked with error")
e = errorsmod.Wrap(e, "panicked with error")
*err = e
return
}

View File

@ -0,0 +1,432 @@
package eip712_test
import (
"testing"
"cosmossdk.io/math"
"github.com/cerc-io/laconicd/ethereum/eip712"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/ethereum/go-ethereum/crypto"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cerc-io/laconicd/app"
"github.com/cerc-io/laconicd/encoding"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/suite"
)
// Unit tests for single-signer EIP-712 signature verification. Multi-signer verification tests are included
// in ante_test.go.
type EIP712TestSuite struct {
suite.Suite
config params.EncodingConfig
clientCtx client.Context
}
func TestEIP712TestSuite(t *testing.T) {
suite.Run(t, &EIP712TestSuite{})
}
// Set up test env to replicate prod. environment
func (suite *EIP712TestSuite) SetupTest() {
suite.config = encoding.MakeConfig(app.ModuleBasics)
suite.clientCtx = client.Context{}.WithTxConfig(suite.config.TxConfig)
sdk.GetConfig().SetBech32PrefixForAccount("ethm", "")
eip712.SetEncodingConfig(suite.config)
}
// Helper to create random test addresses for messages
func (suite *EIP712TestSuite) createTestAddress() sdk.AccAddress {
privkey, _ := ethsecp256k1.GenerateKey()
key, err := privkey.ToECDSA()
suite.Require().NoError(err)
addr := crypto.PubkeyToAddress(key.PublicKey)
return addr.Bytes()
}
// Helper to create random keypair for signing + verification
func (suite *EIP712TestSuite) createTestKeyPair() (*ethsecp256k1.PrivKey, *ethsecp256k1.PubKey) {
privKey, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
pubKey := &ethsecp256k1.PubKey{
Key: privKey.PubKey().Bytes(),
}
suite.Require().Implements((*cryptotypes.PubKey)(nil), pubKey)
return privKey, pubKey
}
// Helper to create instance of sdk.Coins[] with single coin
func (suite *EIP712TestSuite) makeCoins(denom string, amount math.Int) sdk.Coins {
return sdk.NewCoins(
sdk.NewCoin(
denom,
amount,
),
)
}
func (suite *EIP712TestSuite) TestEIP712SignatureVerification() {
suite.SetupTest()
signModes := []signing.SignMode{
signing.SignMode_SIGN_MODE_DIRECT,
signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
}
// Fixed test address
testAddress := suite.createTestAddress()
testCases := []struct {
title string
chainId string
fee txtypes.Fee
memo string
msgs []sdk.Msg
accountNumber uint64
sequence uint64
timeoutHeight uint64
expectSuccess bool
}{
{
title: "Succeeds - Standard MsgSend",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
banktypes.NewMsgSend(
suite.createTestAddress(),
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(1)),
),
},
accountNumber: 8,
sequence: 5,
expectSuccess: true,
},
{
title: "Succeeds - Standard MsgVote",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
govtypes.NewMsgVote(
suite.createTestAddress(),
5,
govtypes.OptionNo,
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: true,
},
{
title: "Succeeds - Standard MsgDelegate",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
stakingtypes.NewMsgDelegate(
suite.createTestAddress(),
sdk.ValAddress(suite.createTestAddress()),
suite.makeCoins("photon", math.NewInt(1))[0],
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: true,
},
{
title: "Succeeds - Standard MsgWithdrawDelegationReward",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
distributiontypes.NewMsgWithdrawDelegatorReward(
suite.createTestAddress(),
sdk.ValAddress(suite.createTestAddress()),
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: true,
},
{
title: "Succeeds - Two Single-Signer MsgDelegate",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
stakingtypes.NewMsgDelegate(
testAddress,
sdk.ValAddress(suite.createTestAddress()),
suite.makeCoins("photon", math.NewInt(1))[0],
),
stakingtypes.NewMsgDelegate(
testAddress,
sdk.ValAddress(suite.createTestAddress()),
suite.makeCoins("photon", math.NewInt(5))[0],
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: true,
},
{
title: "Fails - Two MsgVotes with Different Signers",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
govtypes.NewMsgVote(
suite.createTestAddress(),
5,
govtypes.OptionNo,
),
govtypes.NewMsgVote(
suite.createTestAddress(),
25,
govtypes.OptionAbstain,
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: false,
},
{
title: "Fails - Empty transaction",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{},
accountNumber: 25,
sequence: 78,
expectSuccess: false,
},
{
title: "Fails - Single-Signer MsgSend + MsgVote",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
govtypes.NewMsgVote(
testAddress,
5,
govtypes.OptionNo,
),
banktypes.NewMsgSend(
testAddress,
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(50)),
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: false,
},
{
title: "Fails - Invalid ChainID",
chainId: "invalidchainid",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
govtypes.NewMsgVote(
suite.createTestAddress(),
5,
govtypes.OptionNo,
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: false,
},
{
title: "Fails - Includes TimeoutHeight",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
govtypes.NewMsgVote(
suite.createTestAddress(),
5,
govtypes.OptionNo,
),
},
accountNumber: 25,
sequence: 78,
timeoutHeight: 1000,
expectSuccess: false,
},
{
title: "Fails - Single Message / Multi-Signer",
fee: txtypes.Fee{
Amount: suite.makeCoins("aphoton", math.NewInt(2000)),
GasLimit: 20000,
},
memo: "",
msgs: []sdk.Msg{
banktypes.NewMsgMultiSend(
[]banktypes.Input{
banktypes.NewInput(
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(50)),
),
banktypes.NewInput(
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(50)),
),
},
[]banktypes.Output{
banktypes.NewOutput(
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(50)),
),
banktypes.NewOutput(
suite.createTestAddress(),
suite.makeCoins("photon", math.NewInt(50)),
),
},
),
},
accountNumber: 25,
sequence: 78,
expectSuccess: false,
},
}
for _, tc := range testCases {
for _, signMode := range signModes {
suite.Run(tc.title, func() {
privKey, pubKey := suite.createTestKeyPair()
// Init tx builder
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
// Set gas and fees
txBuilder.SetGasLimit(tc.fee.GasLimit)
txBuilder.SetFeeAmount(tc.fee.Amount)
// Set messages
err := txBuilder.SetMsgs(tc.msgs...)
suite.Require().NoError(err)
// Set memo
txBuilder.SetMemo(tc.memo)
// Prepare signature field
txSigData := signing.SingleSignatureData{
SignMode: signMode,
Signature: nil,
}
txSig := signing.SignatureV2{
PubKey: pubKey,
Data: &txSigData,
Sequence: tc.sequence,
}
err = txBuilder.SetSignatures([]signing.SignatureV2{txSig}...)
suite.Require().NoError(err)
chainId := "ethermint_9000-1"
if tc.chainId != "" {
chainId = tc.chainId
}
if tc.timeoutHeight != 0 {
txBuilder.SetTimeoutHeight(tc.timeoutHeight)
}
// Declare signerData
signerData := authsigning.SignerData{
ChainID: chainId,
AccountNumber: tc.accountNumber,
Sequence: tc.sequence,
PubKey: pubKey,
Address: sdk.MustBech32ifyAddressBytes("ethm", pubKey.Bytes()),
}
bz, err := suite.clientCtx.TxConfig.SignModeHandler().GetSignBytes(
signMode,
signerData,
txBuilder.GetTx(),
)
suite.Require().NoError(err)
suite.verifyEIP712SignatureVerification(tc.expectSuccess, *privKey, *pubKey, bz)
})
}
}
}
// Verify that the payload passes signature verification if signed as its EIP-712 representation.
func (suite *EIP712TestSuite) verifyEIP712SignatureVerification(expectedSuccess bool, privKey ethsecp256k1.PrivKey, pubKey ethsecp256k1.PubKey, signBytes []byte) {
// Convert to EIP712 bytes and sign
eip712Bytes, err := eip712.GetEIP712BytesForMsg(signBytes)
if !expectedSuccess {
// Expect failure generating EIP-712 bytes
suite.Require().Error(err)
return
}
suite.Require().NoError(err)
sig, err := privKey.Sign(eip712Bytes)
suite.Require().NoError(err)
// Verify against original payload bytes. This should pass, even though it is not
// the original message that was signed.
res := pubKey.VerifySignature(signBytes, sig)
suite.Require().True(res)
// Verify against the signed EIP-712 bytes. This should pass, since it is the message signed.
res = pubKey.VerifySignature(eip712Bytes, sig)
suite.Require().True(res)
// Verify against random bytes to ensure it does not pass unexpectedly (sanity check).
randBytes := make([]byte, len(signBytes))
copy(randBytes, signBytes)
// Change the first element of signBytes to a different value
randBytes[0] = (signBytes[0] + 10) % 128
res = pubKey.VerifySignature(randBytes, sig)
suite.Require().False(res)
}

299
ethereum/eip712/encoding.go Normal file
View File

@ -0,0 +1,299 @@
package eip712
import (
"encoding/json"
"errors"
"fmt"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
sdk "github.com/cosmos/cosmos-sdk/types"
txTypes "github.com/cosmos/cosmos-sdk/types/tx"
ethermint "github.com/cerc-io/laconicd/types"
apitypes "github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/cosmos/cosmos-sdk/codec"
)
type aminoMessage struct {
Type string `json:"type"`
Value interface{} `json:"value"`
}
var (
protoCodec codec.ProtoCodecMarshaler
aminoCodec *codec.LegacyAmino
)
// SetEncodingConfig set the encoding config to the singleton codecs (Amino and Protobuf).
// The process of unmarshaling SignDoc bytes into a SignDoc object requires having a codec
// populated with all relevant message types. As a result, we must call this method on app
// initialization with the app's encoding config.
func SetEncodingConfig(cfg params.EncodingConfig) {
aminoCodec = cfg.Amino
protoCodec = codec.NewProtoCodec(cfg.InterfaceRegistry)
}
// Get the EIP-712 object bytes for the given SignDoc bytes by first decoding the bytes into
// an EIP-712 object, then hashing the EIP-712 object to create the bytes to be signed.
// See https://eips.ethereum.org/EIPS/eip-712 for more.
func GetEIP712BytesForMsg(signDocBytes []byte) ([]byte, error) {
typedData, err := GetEIP712TypedDataForMsg(signDocBytes)
if err != nil {
return nil, err
}
_, rawData, err := apitypes.TypedDataAndHash(typedData)
if err != nil {
return nil, fmt.Errorf("could not get EIP-712 object bytes: %w", err)
}
return []byte(rawData), nil
}
// GetEIP712TypedDataForMsg returns the EIP-712 TypedData representation for either
// Amino or Protobuf encoded signature doc bytes.
func GetEIP712TypedDataForMsg(signDocBytes []byte) (apitypes.TypedData, error) {
// Attempt to decode as both Amino and Protobuf since the message format is unknown.
// If either decode works, we can move forward with the corresponding typed data.
typedDataAmino, errAmino := decodeAminoSignDoc(signDocBytes)
if errAmino == nil && isValidEIP712Payload(typedDataAmino) {
return typedDataAmino, nil
}
typedDataProtobuf, errProtobuf := decodeProtobufSignDoc(signDocBytes)
if errProtobuf == nil && isValidEIP712Payload(typedDataProtobuf) {
return typedDataProtobuf, nil
}
return apitypes.TypedData{}, fmt.Errorf("could not decode sign doc as either Amino or Protobuf.\n amino: %v\n protobuf: %v", errAmino, errProtobuf)
}
// isValidEIP712Payload ensures that the given TypedData does not contain empty fields from
// an improper initialization.
func isValidEIP712Payload(typedData apitypes.TypedData) bool {
return len(typedData.Message) != 0 && len(typedData.Types) != 0 && typedData.PrimaryType != "" && typedData.Domain != apitypes.TypedDataDomain{}
}
// decodeAminoSignDoc attempts to decode the provided sign doc (bytes) as an Amino payload
// and returns a signable EIP-712 TypedData object.
func decodeAminoSignDoc(signDocBytes []byte) (apitypes.TypedData, error) {
// Ensure codecs have been initialized
if err := validateCodecInit(); err != nil {
return apitypes.TypedData{}, err
}
var aminoDoc legacytx.StdSignDoc
if err := aminoCodec.UnmarshalJSON(signDocBytes, &aminoDoc); err != nil {
return apitypes.TypedData{}, err
}
var fees legacytx.StdFee
if err := aminoCodec.UnmarshalJSON(aminoDoc.Fee, &fees); err != nil {
return apitypes.TypedData{}, err
}
// Validate payload messages
msgs := make([]sdk.Msg, len(aminoDoc.Msgs))
for i, jsonMsg := range aminoDoc.Msgs {
var m sdk.Msg
if err := aminoCodec.UnmarshalJSON(jsonMsg, &m); err != nil {
return apitypes.TypedData{}, fmt.Errorf("failed to unmarshal sign doc message: %w", err)
}
msgs[i] = m
}
if err := validatePayloadMessages(msgs); err != nil {
return apitypes.TypedData{}, err
}
// Use first message for fee payer and type inference
msg := msgs[0]
// By convention, the fee payer is the first address in the list of signers.
feePayer := msg.GetSigners()[0]
feeDelegation := &FeeDelegationOptions{
FeePayer: feePayer,
}
chainID, err := ethermint.ParseChainID(aminoDoc.ChainID)
if err != nil {
return apitypes.TypedData{}, errors.New("invalid chain ID passed as argument")
}
typedData, err := WrapTxToTypedData(
protoCodec,
chainID.Uint64(),
msg,
signDocBytes,
feeDelegation,
)
if err != nil {
return apitypes.TypedData{}, fmt.Errorf("could not convert to EIP712 representation: %w", err)
}
return typedData, nil
}
// decodeProtobufSignDoc attempts to decode the provided sign doc (bytes) as a Protobuf payload
// and returns a signable EIP-712 TypedData object.
func decodeProtobufSignDoc(signDocBytes []byte) (apitypes.TypedData, error) {
// Ensure codecs have been initialized
if err := validateCodecInit(); err != nil {
return apitypes.TypedData{}, err
}
signDoc := &txTypes.SignDoc{}
if err := signDoc.Unmarshal(signDocBytes); err != nil {
return apitypes.TypedData{}, err
}
authInfo := &txTypes.AuthInfo{}
if err := authInfo.Unmarshal(signDoc.AuthInfoBytes); err != nil {
return apitypes.TypedData{}, err
}
body := &txTypes.TxBody{}
if err := body.Unmarshal(signDoc.BodyBytes); err != nil {
return apitypes.TypedData{}, err
}
// Until support for these fields is added, throw an error at their presence
if body.TimeoutHeight != 0 || len(body.ExtensionOptions) != 0 || len(body.NonCriticalExtensionOptions) != 0 {
return apitypes.TypedData{}, errors.New("body contains unsupported fields: TimeoutHeight, ExtensionOptions, or NonCriticalExtensionOptions")
}
if len(authInfo.SignerInfos) != 1 {
return apitypes.TypedData{}, fmt.Errorf("invalid number of signer infos provided, expected 1 got %v", len(authInfo.SignerInfos))
}
// Validate payload messages
msgs := make([]sdk.Msg, len(body.Messages))
for i, protoMsg := range body.Messages {
var m sdk.Msg
if err := protoCodec.UnpackAny(protoMsg, &m); err != nil {
return apitypes.TypedData{}, fmt.Errorf("could not unpack message object with error %w", err)
}
msgs[i] = m
}
if err := validatePayloadMessages(msgs); err != nil {
return apitypes.TypedData{}, err
}
// Use first message for fee payer and type inference
msg := msgs[0]
signerInfo := authInfo.SignerInfos[0]
chainID, err := ethermint.ParseChainID(signDoc.ChainId)
if err != nil {
return apitypes.TypedData{}, fmt.Errorf("invalid chain ID passed as argument: %w", err)
}
stdFee := &legacytx.StdFee{
Amount: authInfo.Fee.Amount,
Gas: authInfo.Fee.GasLimit,
}
feePayer := msg.GetSigners()[0]
feeDelegation := &FeeDelegationOptions{
FeePayer: feePayer,
}
tip := authInfo.Tip
// WrapTxToTypedData expects the payload as an Amino Sign Doc
signBytes := legacytx.StdSignBytes(
signDoc.ChainId,
signDoc.AccountNumber,
signerInfo.Sequence,
body.TimeoutHeight,
*stdFee,
msgs,
body.Memo,
tip,
)
typedData, err := WrapTxToTypedData(
protoCodec,
chainID.Uint64(),
msg,
signBytes,
feeDelegation,
)
if err != nil {
return apitypes.TypedData{}, err
}
return typedData, nil
}
// validateCodecInit ensures that both Amino and Protobuf encoding codecs have been set on app init,
// so the module does not panic if either codec is not found.
func validateCodecInit() error {
if aminoCodec == nil || protoCodec == nil {
return errors.New("missing codec: codecs have not been properly initialized using SetEncodingConfig")
}
return nil
}
// validatePayloadMessages ensures that the transaction messages can be represented in an EIP-712
// encoding by checking that messages exist, are of the same type, and share a single signer.
func validatePayloadMessages(msgs []sdk.Msg) error {
if len(msgs) == 0 {
return errors.New("unable to build EIP-712 payload: transaction does contain any messages")
}
var msgType string
var msgSigner sdk.AccAddress
for i, m := range msgs {
t, err := getMsgType(m)
if err != nil {
return err
}
if len(m.GetSigners()) != 1 {
return errors.New("unable to build EIP-712 payload: expect exactly 1 signer")
}
if i == 0 {
msgType = t
msgSigner = m.GetSigners()[0]
continue
}
if t != msgType {
return errors.New("unable to build EIP-712 payload: different types of messages detected")
}
if !msgSigner.Equals(m.GetSigners()[0]) {
return errors.New("unable to build EIP-712 payload: multiple signers detected")
}
}
return nil
}
// getMsgType returns the message type prefix for the given Cosmos SDK Msg
func getMsgType(msg sdk.Msg) (string, error) {
jsonBytes, err := aminoCodec.MarshalJSON(msg)
if err != nil {
return "", err
}
var jsonMsg aminoMessage
if err := json.Unmarshal(jsonBytes, &jsonMsg); err != nil {
return "", err
}
// Verify Type was successfully filled in
if jsonMsg.Type == "" {
return "", errors.New("could not decode message: type is missing")
}
return jsonMsg.Type, nil
}

63
go.mod
View File

@ -1,19 +1,22 @@
module github.com/cerc-io/laconicd
go 1.18
go 1.19
require (
cosmossdk.io/math v1.0.0-beta.3
github.com/99designs/gqlgen v0.17.20
cosmossdk.io/errors v1.0.0-beta.7
cosmossdk.io/math v1.0.0-beta.4
github.com/99designs/gqlgen v0.17.22
github.com/armon/go-metrics v0.4.1
github.com/btcsuite/btcd v0.22.1
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce
github.com/cosmos/cosmos-sdk v0.46.3
github.com/cosmos/cosmos-proto v1.0.0-beta.1
github.com/cosmos/cosmos-sdk v0.46.7
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/ibc-go/v5 v5.0.1
github.com/cosmos/gogoproto v1.4.3
github.com/cosmos/ibc-go/v5 v5.2.0
github.com/davecgh/go-spew v1.1.1
github.com/deckarep/golang-set v1.8.0
github.com/ethereum/go-ethereum v1.10.19
github.com/ethereum/go-ethereum v1.10.26
github.com/gibson042/canonicaljson-go v1.0.3
github.com/gogo/protobuf v1.3.3
github.com/golang/protobuf v1.5.2
@ -26,27 +29,26 @@ require (
github.com/ipfs/go-ipld-cbor v0.0.6
github.com/ipld/go-ipld-prime v0.18.0
github.com/miguelmota/go-ethereum-hdwallet v0.1.1
github.com/multiformats/go-multihash v0.2.1
github.com/onsi/ginkgo/v2 v2.2.0
github.com/onsi/gomega v1.20.2
github.com/multiformats/go-multihash v0.2.0
github.com/onsi/ginkgo/v2 v2.5.1
github.com/onsi/gomega v1.24.1
github.com/pkg/errors v0.9.1
github.com/rakyll/statik v0.1.7
github.com/regen-network/cosmos-proto v0.3.1
github.com/rs/cors v1.8.2
github.com/spf13/cast v1.5.0
github.com/spf13/cobra v1.5.0
github.com/spf13/viper v1.13.0
github.com/spf13/cobra v1.6.1
github.com/spf13/viper v1.14.0
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969
github.com/stretchr/testify v1.8.1
github.com/tendermint/tendermint v0.34.22
github.com/tendermint/tendermint v0.34.24
github.com/tendermint/tm-db v0.6.7
github.com/tyler-smith/go-bip39 v1.1.0
github.com/vektah/gqlparser/v2 v2.5.1
golang.org/x/net v0.3.0
golang.org/x/net v0.4.0
golang.org/x/text v0.5.0
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c
google.golang.org/grpc v1.51.0
google.golang.org/protobuf v1.28.1
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8
gopkg.in/yaml.v3 v3.0.1
sigs.k8s.io/yaml v1.3.0
)
@ -57,7 +59,6 @@ require (
cloud.google.com/go/compute/metadata v0.2.1 // indirect
cloud.google.com/go/iam v0.8.0 // indirect
cloud.google.com/go/storage v1.27.0 // indirect
cosmossdk.io/errors v1.0.0-beta.7 // indirect
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/99designs/keyring v1.2.1 // indirect
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
@ -69,7 +70,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
@ -77,13 +78,11 @@ require (
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/cockroachdb/apd/v2 v2.0.2 // indirect
github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect
github.com/confio/ics23/go v0.7.0 // indirect
github.com/cosmos/btcutil v1.0.4 // indirect
github.com/cosmos/cosmos-proto v1.0.0-alpha7 // indirect
github.com/confio/ics23/go v0.9.0 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/gorocksdb v1.2.0 // indirect
github.com/cosmos/iavl v0.19.3 // indirect
github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect
github.com/cosmos/ledger-go v0.9.2 // indirect
github.com/cosmos/iavl v0.19.4 // indirect
github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect
github.com/creachadair/taskgroup v0.3.2 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
@ -97,11 +96,12 @@ require (
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/go-stack/stack v1.8.0 // indirect
@ -139,7 +139,7 @@ require (
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/compress v1.15.11 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/lib/pq v1.10.6 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
@ -170,9 +170,10 @@ require (
github.com/prometheus/client_golang v1.12.2 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.34.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/prometheus/tsdb v0.7.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/regen-network/cosmos-proto v0.3.1 // indirect
github.com/rjeczalik/notify v0.9.1 // indirect
github.com/rs/zerolog v1.27.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
@ -191,7 +192,8 @@ require (
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/ulikunitz/xz v0.5.8 // indirect
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 // indirect
github.com/zondax/hid v0.9.1-0.20220302062450-5552068d2266 // indirect
github.com/zondax/hid v0.9.1 // indirect
github.com/zondax/ledger-go v0.14.0 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.4.0 // indirect
@ -211,10 +213,13 @@ require (
)
replace (
// use cosmos keyring
github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76
// ics23 patch for dragonberry
github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0
// Fix upstream GHSA-h395-qcrw-5vmq vulnerability.
// TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0
// use cosmos flavored protobufs
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
)

135
go.sum
View File

@ -52,15 +52,15 @@ cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w=
cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE=
cosmossdk.io/math v1.0.0-beta.3 h1:TbZxSopz2LqjJ7aXYfn7nJSb8vNaBklW6BLpcei1qwM=
cosmossdk.io/math v1.0.0-beta.3/go.mod h1:3LYasri3Zna4XpbrTNdKsWmD5fHHkaNAod/mNT9XdE4=
cosmossdk.io/math v1.0.0-beta.4 h1:JtKedVLGzA0vv84xjYmZ75RKG35Kf2WwcFu8IjRkIIw=
cosmossdk.io/math v1.0.0-beta.4/go.mod h1:An0MllWJY6PxibUpnwGk8jOm+a/qIxlKmL5Zyp9NnaM=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
git.sr.ht/~sircmpwn/getopt v0.0.0-20191230200459-23622cc906b3/go.mod h1:wMEGFFFNuPos7vHmWXfszqImLppbc0wEhh6JBfJIUgw=
git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9/go.mod h1:BVJwbDfVjCjoFiKrhkei6NdGcZYpkDkdyCdg1ukytRA=
github.com/99designs/gqlgen v0.17.20 h1:O7WzccIhKB1dm+7g6dhQcULINftfiLSBg2l/mwbpJMw=
github.com/99designs/gqlgen v0.17.20/go.mod h1:Mja2HI23kWT1VRH09hvWshFgOzKswpO20o4ScpJIES4=
github.com/99designs/gqlgen v0.17.22 h1:TOcrF8t0T3I0za9JD3CB6ehq7dDEMjR9Onikf8Lc/04=
github.com/99designs/gqlgen v0.17.22/go.mod h1:BMhYIhe4bp7OlCo5I2PnowSK/Wimpv/YlxfNkqZGwLo=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM=
@ -87,7 +87,7 @@ github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@ -157,7 +157,6 @@ github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQ
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0=
github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=
@ -165,13 +164,12 @@ github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401/go.mod h1:Sv
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
@ -222,8 +220,6 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE
github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI=
github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZr9ZvoCcA=
github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M=
github.com/confio/ics23/go v0.7.0 h1:00d2kukk7sPoHWL4zZBZwzxnpA2pec1NPdwbSokJ5w8=
github.com/confio/ics23/go v0.7.0/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ=
github.com/consensys/bavard v0.1.8-0.20210915155054-088da2f7f54a/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=
@ -235,30 +231,34 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44=
github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU=
github.com/cosmos/cosmos-proto v1.0.0-alpha7 h1:yqYUOHF2jopwZh4dVQp3xgqwftE5/2hkrwIV6vkUbO0=
github.com/cosmos/cosmos-proto v1.0.0-alpha7/go.mod h1:dosO4pSAbJF8zWCzCoTWP7nNsjcvSUBQmniFxDg5daw=
github.com/cosmos/cosmos-sdk v0.46.3 h1:2jdJYcSwh4AtFJKGoNGvmEy2mKDWtGaVZphGpvedljQ=
github.com/cosmos/cosmos-sdk v0.46.3/go.mod h1:AynIAjXwtS3T/ApdhNCz/7/KGMbZSUBbKRTcbukb2ic=
github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk=
github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis=
github.com/cosmos/cosmos-proto v1.0.0-beta.1 h1:iDL5qh++NoXxG8hSy93FdYJut4XfgbShIocllGaXx/0=
github.com/cosmos/cosmos-proto v1.0.0-beta.1/go.mod h1:8k2GNZghi5sDRFw/scPL8gMSowT1vDA+5ouxL8GjaUE=
github.com/cosmos/cosmos-sdk v0.46.7 h1:dkGy9y2ewgqvawrUOuWb2oz3MdotVduokyreXC4bS0s=
github.com/cosmos/cosmos-sdk v0.46.7/go.mod h1:fqKqz39U5IlEFb4nbQ72951myztsDzFKKDtffYJ63nk=
github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 h1:iKclrn3YEOwk4jQHT2ulgzuXyxmzmPczUalMwW4XH9k=
github.com/cosmos/cosmos-sdk/ics23/go v0.8.0/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpFP3wWDPgdHPargtyw30=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
github.com/cosmos/gogoproto v1.4.3 h1:RP3yyVREh9snv/lsOvmsAPQt8f44LgL281X0IOIhhcI=
github.com/cosmos/gogoproto v1.4.3/go.mod h1:0hLIG5TR7IvV1fme1HCFKjfzW9X2x0Mo+RooWXCnOWU=
github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y=
github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw=
github.com/cosmos/iavl v0.19.3 h1:cESO0OwTTxQm5rmyESKW+zESheDUYI7CcZDWWDwnuxg=
github.com/cosmos/iavl v0.19.3/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw=
github.com/cosmos/ibc-go/v5 v5.0.1 h1:ZI5xCi6RDOL+hyu6Wx/w6JoAYFlOoK5hijsRTVWo+RA=
github.com/cosmos/ibc-go/v5 v5.0.1/go.mod h1:LX0DHLW3dfi/1e4BJzi8MGLWmQ4DSraPEgVjyo3VzAo=
github.com/cosmos/iavl v0.19.4 h1:t82sN+Y0WeqxDLJRSpNd8YFX5URIrT+p8n6oJbJ2Dok=
github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw=
github.com/cosmos/ibc-go/v5 v5.2.0 h1:LxwttRQqdUJpQ3/Gc3XPg5lkRo3pcbzx65dxFIY6ONE=
github.com/cosmos/ibc-go/v5 v5.2.0/go.mod h1:MhDUMDVSboK5JW2pEWHNcw0wJHaHqKV/vwwP7awGhzI=
github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76 h1:DdzS1m6o/pCqeZ8VOAit/gyATedRgjvkVI+UCrLpyuU=
github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76/go.mod h1:0mkLWIoZuQ7uBoospo5Q9zIpqq6rYCPJDSUdeCJvPM8=
github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4=
github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY=
github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI=
github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI=
github.com/cosmos/ledger-cosmos-go v0.12.1 h1:sMBxza5p/rNK/06nBSNmsI/WDqI0pVJFVNihy1Y984w=
github.com/cosmos/ledger-cosmos-go v0.12.1/go.mod h1:dhO6kj+Y+AHIOgAe4L9HL/6NDdyyth4q238I9yFpD2g=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM=
github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk=
@ -306,7 +306,7 @@ github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ=
@ -333,8 +333,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethereum/go-ethereum v1.10.4/go.mod h1:nEE0TP5MtxGzOMd7egIrbPJMQBnhVU3ELNxhBglIzhg=
github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0=
github.com/ethereum/go-ethereum v1.10.19 h1:EOR5JbL4MD5yeOqv8W2iC1s4NximrTjqFccUz8lyBRA=
github.com/ethereum/go-ethereum v1.10.19/go.mod h1:IJBNMtzKcNHPtllYihy6BL2IgK1u+32JriaTbdt4v+w=
github.com/ethereum/go-ethereum v1.10.26 h1:i/7d9RBBwiXCEuyduBQzJw/mKmnvzsN14jqBmytw72s=
github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg=
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0=
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk=
@ -351,8 +351,8 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
@ -384,6 +384,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@ -477,7 +479,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
@ -687,8 +688,8 @@ github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
@ -784,7 +785,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@ -816,8 +816,8 @@ github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPw
github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs=
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108=
github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
github.com/multiformats/go-multihash v0.2.0 h1:oytJb9ZA1OUW0r0f9ea18GiaPOo4SXyc7p2movyUuo4=
github.com/multiformats/go-multihash v0.2.0/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@ -848,17 +848,17 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/onsi/ginkgo/v2 v2.5.1 h1:auzK7OI497k6x4OvWq+TKAcpcSAlod0doAH72oIN0Jw=
github.com/onsi/ginkgo/v2 v2.5.1/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.20.2 h1:8uQq0zMgLEfa0vRrrBgaJF2gyW9Da9BmfGV+OyUzfkY=
github.com/onsi/gomega v1.20.2/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034=
github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@ -939,8 +939,9 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ=
@ -958,15 +959,17 @@ github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRr
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs=
github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
@ -1005,8 +1008,8 @@ github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@ -1015,8 +1018,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU=
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU=
github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 h1:Oo2KZNP70KE0+IUJSidPj/BFS/RXNHmKIJOdckzml2E=
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
@ -1051,8 +1054,8 @@ github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RM
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk=
github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
github.com/tendermint/tendermint v0.34.22 h1:XMhtC8s8QqJO4l/dn+TkQvevTRSow3Vixjclr41o+2Q=
github.com/tendermint/tendermint v0.34.22/go.mod h1:YpP5vBEAKUT4g6oyfjKgFeZmdB/GjkJAxfF+cgmJg6Y=
github.com/tendermint/tendermint v0.34.24 h1:879MKKJWYYPJEMMKME+DWUTY4V9f/FBpnZDI82ky+4k=
github.com/tendermint/tendermint v0.34.24/go.mod h1:rXVrl4OYzmIa1I91av3iLv2HS0fGSiucyW9J4aMTpKI=
github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8=
github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I=
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@ -1083,9 +1086,11 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY
github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/urfave/cli/v2 v2.8.1/go.mod h1:Z41J9TPoffeoqP0Iza0YbAhGvymRdZAd2uPmZ5JxRdY=
github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
@ -1101,6 +1106,7 @@ github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -1110,9 +1116,10 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
github.com/zondax/hid v0.9.1-0.20220302062450-5552068d2266 h1:O9XLFXGkVswDFmH9LaYpqu+r/AAFWqr0DL6V00KEVFg=
github.com/zondax/hid v0.9.1-0.20220302062450-5552068d2266/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
github.com/zondax/hid v0.9.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo=
github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
github.com/zondax/ledger-go v0.14.0 h1:dlMC7aO8Wss1CxBq2I96kZ69Nh1ligzbs8UWOtq/AsA=
github.com/zondax/ledger-go v0.14.0/go.mod h1:fZ3Dqg6qcdXWSOJFKMG8GCTnD7slO/RL2feOQv8K320=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
@ -1206,6 +1213,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1263,8 +1271,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1375,11 +1383,11 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@ -1396,6 +1404,7 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -1404,7 +1413,7 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -1466,6 +1475,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1553,8 +1563,8 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY=
google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c h1:S34D59DS2GWOEwWNt4fYmTcFrtlOgukG2k9WsomZ7tg=
google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@ -1593,10 +1603,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 h1:KR8+MyP7/qOlV+8Af01LtjL04bu7on42eVsxT4EyBQk=
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -1617,7 +1626,6 @@ gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJ
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
@ -1648,8 +1656,7 @@ lukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c=
lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g=
pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
pgregory.net/rapid v0.5.3 h1:163N50IHFqr1phZens4FQOdPgfJscR7a562mjQqeo4M=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=

16
gometalinter.json Normal file
View File

@ -0,0 +1,16 @@
{
"Linters": {
"vet": "go tool vet -composites=false :PATH:LINE:MESSAGE"
},
"Enable": [
"golint",
"vet",
"ineffassign",
"unparam",
"unconvert",
"misspell"
],
"Deadline": "500s",
"Vendor": true,
"Cyclo": 11
}

View File

@ -2,26 +2,32 @@ schema = 3
[mod]
[mod."cloud.google.com/go"]
version = "v0.102.1"
hash = "sha256-rv3MHFvIrN6AcrmWcWGSQwgaZLbjJMmJFi3bsfHoiO4="
version = "v0.105.0"
hash = "sha256-2nYtHjuN9ghGcM6aPlOxyNNarHebHtj0Xec48sWwdaI="
[mod."cloud.google.com/go/compute"]
version = "v1.7.0"
hash = "sha256-g+n7L36LC+NP4KaiEu9fCMn6S9fkxjp4PCLOp/oXV38="
version = "v1.12.1"
hash = "sha256-mMsdL+6R1KuFeAFqEJv8oq/cmRc9hSluEisCpGP0GTc="
[mod."cloud.google.com/go/compute/metadata"]
version = "v0.2.1"
hash = "sha256-gqjkb6y5POkTWXGQtCvgygvXqoLkESB+cykKp7Mp3jI="
[mod."cloud.google.com/go/iam"]
version = "v0.4.0"
hash = "sha256-sPtj6QPPC/QrkDXJW4Y7rMIHk5l1y9XV/DgM47eEtvg="
version = "v0.7.0"
hash = "sha256-2UTJ/BbZ+YMGJhyo3HRPUYVDXW6+B5znFdqiutboYtA="
[mod."cloud.google.com/go/storage"]
version = "v1.22.1"
hash = "sha256-YZt05wru0kacyi6moTgvocavActKpXx7FlLh+o0HGDs="
version = "v1.27.0"
hash = "sha256-V4B6A1Ms8cemB5Cs6nAtUe1N1ldaI9oqTdzGU2FUhrc="
[mod."cosmossdk.io/errors"]
version = "v1.0.0-beta.7"
hash = "sha256-XblGvIx6Wvvq6wggXjp+KbeJGXoe7AZH7hXEdauCezU="
[mod."cosmossdk.io/math"]
version = "v1.0.0-beta.3"
hash = "sha256-lTQ27ZlL+kWlc+S//sJmyiOwaf9qS+YLv61I4OXi9XE="
version = "v1.0.0-beta.4"
hash = "sha256-UYdq/46EubyjxkldGike8FlwJLWGCB576VB7th285ao="
[mod."filippo.io/edwards25519"]
version = "v1.0.0-rc.1"
hash = "sha256-3DboBqby2ejRU33FG96Z8JF5AJ8HP2rC/v++VyoQ2LQ="
[mod."github.com/99designs/gqlgen"]
version = "v0.17.22"
hash = "sha256-Cu3nAqFbsV7DH+4UZvX83ScxJtPlvOyD7ptUPXnwGng="
[mod."github.com/99designs/keyring"]
version = "v1.1.7-0.20210622111912-ef00f8ac3d76"
hash = "sha256-oCalyOZWegRgKHZ1GvYHNkrMKh51j8cOE/K4yBPM5Oc="
@ -38,6 +44,9 @@ schema = 3
[mod."github.com/Workiva/go-datastructures"]
version = "v1.0.53"
hash = "sha256-W6qOvqu8sokMlZrpOF1SWG138H0/BotywKNLlDF8Zug="
[mod."github.com/agnivade/levenshtein"]
version = "v1.1.1"
hash = "sha256-tgv2s8XIcWjscv1pP87TOIUV4vADT2px1Lo/MQCTBjM="
[mod."github.com/armon/go-metrics"]
version = "v0.4.1"
hash = "sha256-usxTUHA0QQMdM6sHi2z51nmnEKMbA0qUilxJFpWHlYE="
@ -57,8 +66,8 @@ schema = 3
version = "v0.22.1"
hash = "sha256-hBU+roIELcmbW2Gz7eGZzL9qNA1bakq5wNxqCgs4TKc="
[mod."github.com/btcsuite/btcd/btcec/v2"]
version = "v2.2.0"
hash = "sha256-cwoIqi0SiAaGEBtuQKip9OVirKIeJw5fUoWo7x/xfOc="
version = "v2.3.2"
hash = "sha256-natWs+yIAuD1UI07iZtjPilroQLfXizFn3lNOiOT83U="
[mod."github.com/btcsuite/btcd/chaincfg/chainhash"]
version = "v1.0.1"
hash = "sha256-vix0j/KGNvoKjhlKgVeSLY6un2FHeIEoZWMC4z3yvZ4="
@ -84,35 +93,36 @@ schema = 3
version = "v0.7.9"
hash = "sha256-ZWIXIXcHGjeCNgMrpXymry8/8esDDauGFfF/+gEoO1Y="
[mod."github.com/confio/ics23/go"]
version = "v0.7.0"
hash = "sha256-FjUQfDKtX+/13+UjJzbYPAkgM4GPZ0vk+dKz7/iRetw="
version = "v0.8.0"
hash = "sha256-mFKxFHp7RaE1L5NdtH9H9px2Cy6I5uOZVnFOgE8Nrew="
replaced = "github.com/cosmos/cosmos-sdk/ics23/go"
[mod."github.com/cosmos/btcutil"]
version = "v1.0.4"
hash = "sha256-JvcBXBdjdmnaW/nyf/tw/uaOAGn1b78yxrtl2/Rs3kA="
version = "v1.0.5"
hash = "sha256-t572Sr5iiHcuMKLMWa2i+LBAt192oa+G1oA371tG/eI="
[mod."github.com/cosmos/cosmos-proto"]
version = "v1.0.0-alpha7"
hash = "sha256-2wCH+toTF2A6MfFjOa13muEH5oBCcxAhZEqirNOrBA0="
version = "v1.0.0-beta.1"
hash = "sha256-oATkuj+fM5eBn+ywO+w/tL0AFSIEkx0J3Yz+VhVe0QA="
[mod."github.com/cosmos/cosmos-sdk"]
version = "v0.46.2-0.20220920160224-9454b97ccb77"
hash = "sha256-zwOsdcoPbEzn+q/UmW6/CauW65V6a4z/7k8DXPCvKb0="
version = "v0.46.7"
hash = "sha256-54DCF8lrnA1oUmBJlbUlWXOP5UbenRInUROn5P5I9qI="
[mod."github.com/cosmos/go-bip39"]
version = "v1.0.0"
hash = "sha256-Qm2aC2vaS8tjtMUbHmlBSagOSqbduEEDwc51qvQaBmA="
[mod."github.com/cosmos/gogoproto"]
version = "v1.4.3"
hash = "sha256-Y/NL76ay/oAl8mS3skkK5ula0/xudqbwW1o22lZjKRg="
[mod."github.com/cosmos/gorocksdb"]
version = "v1.2.0"
hash = "sha256-209TcVuXc5s/TcOvNlaQ1HEJAUDTEK3nxPhs+d8TEcY="
[mod."github.com/cosmos/iavl"]
version = "v0.19.2-0.20220916140702-9b6be3095313"
hash = "sha256-49xr/7/4L1wZ45eW5lE7C4SlcbGf4gBY+662SfJiWPQ="
version = "v0.19.4"
hash = "sha256-EmpRZ48pjPFq/fIHneut9Vyo5QJATfb3ZO7KzWnqs9g="
[mod."github.com/cosmos/ibc-go/v5"]
version = "v5.0.0"
hash = "sha256-sDZdmuGohaaBF7bxrjo9PWJnmoF+VOkjySYhsFixPz4="
version = "v5.2.0"
hash = "sha256-Gfqhdz9ZKEgb7LCkHiXCwYZYUYluQ+vMew/GkssfVj8="
[mod."github.com/cosmos/ledger-cosmos-go"]
version = "v0.11.1"
hash = "sha256-yli+VvVtZmHo2LPvCY6lYVUfcCDn3sBLDL+a8KIlqDA="
[mod."github.com/cosmos/ledger-go"]
version = "v0.9.2"
hash = "sha256-0YI+0A6wFBjiebBwzWOQjkgXkTakCrf7Gjg2xEaQdoM="
version = "v0.12.1"
hash = "sha256-9+nr+/r4MyiogddS0JcXOuriPqXP4nxln8ts+mYQRcg="
[mod."github.com/creachadair/taskgroup"]
version = "v0.3.2"
hash = "sha256-Y261IO/d9xjV0UScqHvo31broxvnKn4IQQC9Mu6jNkE="
@ -156,17 +166,20 @@ schema = 3
version = "v1.0.0"
hash = "sha256-k1DYvCqO3BKNcGEve/nMW0RxzMkK2tGfXbUbycqcVSo="
[mod."github.com/ethereum/go-ethereum"]
version = "v1.10.19"
hash = "sha256-7FPnTGcCb8Xd1QVR+6PmGTaHdTY1mm/8osFTW1JLuG8="
version = "v1.10.26"
hash = "sha256-gkMEwJ4rOgn12amD4QpZ4th/10uyTTeoFmpseuKDQPs="
[mod."github.com/felixge/httpsnoop"]
version = "v1.0.1"
hash = "sha256-TNXnnC/ZGNY9lInAcES1cBGqIdEljKuh5LH/khVFjVk="
[mod."github.com/fsnotify/fsnotify"]
version = "v1.5.4"
hash = "sha256-iPuInpDAJvDeSTr6to713J/fTOWdQIWlLXWAuWIs2Bw="
version = "v1.6.0"
hash = "sha256-DQesOCweQPEwmAn6s7DCP/Dwy8IypC+osbpfsvpkdP0="
[mod."github.com/gballet/go-libpcsclite"]
version = "v0.0.0-20190607065134-2772fd86a8ff"
hash = "sha256-Nr5ocU9s1F2Lhx/Zq6/nIo+KkKEqMjDYOEs3yWRC48g="
[mod."github.com/gibson042/canonicaljson-go"]
version = "v1.0.3"
hash = "sha256-CZc2lBZ5ivP0o7K+Cz3ermWOahY6C27rVrI+UI+XCS4="
[mod."github.com/go-kit/kit"]
version = "v0.12.0"
hash = "sha256-5RkXo6s0oye8etgD5qy+AvkkkNsQ6jc0kWJj6flA4GM="
@ -176,6 +189,9 @@ schema = 3
[mod."github.com/go-logfmt/logfmt"]
version = "v0.5.1"
hash = "sha256-t50m9ffvW8PiGvO+2svnLI+N/XaWaBS+ZlhwrEQn2gU="
[mod."github.com/go-logr/logr"]
version = "v1.2.3"
hash = "sha256-2L7k6GfrcW3GXXYr1FYIu20aZBjIF0cTKdte6D4riH8="
[mod."github.com/go-ole/go-ole"]
version = "v1.2.6"
hash = "sha256-+oxitLeJxYF19Z6g+6CgmCHJ1Y5D8raMi2Cb3M6nXCs="
@ -211,8 +227,8 @@ schema = 3
version = "v1.0.1"
hash = "sha256-1PIeFGgUL4BK/StL/D12pg9bEQ5HfMT/fMLdus4pZTs="
[mod."github.com/google/go-cmp"]
version = "v0.5.8"
hash = "sha256-8zkIo+Sr1NXMnj3PNmvjX2sZKnAKWXOFvmnX7D9bwxQ="
version = "v0.5.9"
hash = "sha256-lQc4O00R3QSMGs9LP8Sy7A9kj0cqV5rrUdpnGeipIyg="
[mod."github.com/google/orderedcode"]
version = "v0.0.1"
hash = "sha256-KrExYovtUQrHGI1mPQf57jGw8soz7eWOC2xqEaV0uGk="
@ -220,14 +236,11 @@ schema = 3
version = "v1.3.0"
hash = "sha256-QoR55eBtA94T2tBszyxfDtO7/pjZZSGb5vm7U0Xhs0Y="
[mod."github.com/googleapis/enterprise-certificate-proxy"]
version = "v0.1.0"
hash = "sha256-fxaElfiGGh1mLmltkFpVFdiuaagrLZLTW9btVpK13wg="
version = "v0.2.0"
hash = "sha256-5gxsS5kDLqNFBkQ4eK6GS/sNn+aFknm6jjfteO+6jl4="
[mod."github.com/googleapis/gax-go/v2"]
version = "v2.4.0"
hash = "sha256-zzat4+3iF2XBTQ6RZAUgsCbfK0HgO0nYhM4utA5dqz0="
[mod."github.com/googleapis/go-type-adapters"]
version = "v1.0.0"
hash = "sha256-u3ajruRV/EN2E1WKet/zoe3zmRrAy4C5F2Dx8bpQwoc="
version = "v2.6.0"
hash = "sha256-sSsncbJmv0n5jB3G7tHY1Zr2ucCusIeTrXZH4A8QqYI="
[mod."github.com/gorilla/handlers"]
version = "v1.5.1"
hash = "sha256-GnBAARgOx1E+hDMQ63SI17hdhGtLQxb31lZOmn5j/pU="
@ -289,8 +302,26 @@ schema = 3
version = "v0.15.0"
hash = "sha256-9oqKb5Y3hjleOFE2BczbEzLH6q2Jg7kUTP/M8Yk4Ne4="
[mod."github.com/inconshreveable/mousetrap"]
version = "v1.0.0"
hash = "sha256-ogTuLrV40FwS4ueo4hh6hi1wPywOI+LyIqfNjsibwNY="
version = "v1.0.1"
hash = "sha256-ZTP9pLgwAAvHYK5A4PqwWCHGt00x5zMSOpCPoomQ3Sg="
[mod."github.com/ipfs/go-block-format"]
version = "v0.0.2"
hash = "sha256-bgYso07OxWcHQx0ZxjE/G80798DnhywUSvqBb0jK48g="
[mod."github.com/ipfs/go-cid"]
version = "v0.3.2"
hash = "sha256-S7iT1bGU84EgKvScz4uJL+3o1hJ17nP5ANha1B6MVfg="
[mod."github.com/ipfs/go-ipfs-util"]
version = "v0.0.1"
hash = "sha256-Wht/WTcDwoPEwzyZZm1XoFhn3h8fWmg3xuUqBDvmB8k="
[mod."github.com/ipfs/go-ipld-cbor"]
version = "v0.0.6"
hash = "sha256-bb7jO2s1Wy0V9Uu9U3jON9E1BJh6IKYbEEfB/oglvpU="
[mod."github.com/ipfs/go-ipld-format"]
version = "v0.0.1"
hash = "sha256-LZjVFuwSwHzwxl7ZTskSFQr3kXD/qUWAmVVRCcblZFE="
[mod."github.com/ipld/go-ipld-prime"]
version = "v0.18.0"
hash = "sha256-wHkeWxIwyaKku0J8bzQ2gggWJls1ORHhHewY092BA3c="
[mod."github.com/jackpal/go-nat-pmp"]
version = "v1.0.2"
hash = "sha256-L1D4Yoxnzihs795GZ+Q3AZsFP5c4iqyjTeyrudzPXtw="
@ -304,8 +335,11 @@ schema = 3
version = "v0.0.0-20190712205309-48d3d31d256d"
hash = "sha256-bn04wkDnhQ0tb/YzmPf7MNJlApOl+z6+EAbUqH7Ti5Q="
[mod."github.com/klauspost/compress"]
version = "v1.15.9"
hash = "sha256-ctPxlVq0c/SoNPVsP66RjxUjTHys3diW2Apxjyc9WdE="
version = "v1.15.11"
hash = "sha256-9MXm0TObg6DyqnYMIw3IChrorHc2ILf5djZYoM0e1J0="
[mod."github.com/klauspost/cpuid/v2"]
version = "v2.0.9"
hash = "sha256-0rHlHzEVaDdkVbRJDhnAJjfJUmAHOYjXN5u7VoCi5uk="
[mod."github.com/lib/pq"]
version = "v1.10.6"
hash = "sha256-8EhFwY/9YH5L/fd6l2beOnC3VvpegRAmCCsnDVJBqBM="
@ -319,8 +353,8 @@ schema = 3
version = "v0.9.0"
hash = "sha256-Fe2OPoyRExZejwtUBivKhfJAJW7o9b1eyYpgDlWQ1No="
[mod."github.com/mattn/go-colorable"]
version = "v0.1.12"
hash = "sha256-Y1vCt0ShrCz4wSmwsppCfeLPLKrWusc2zM2lUFwDMyI="
version = "v0.1.13"
hash = "sha256-qb3Qbo0CELGRIzvw7NVM1g/aayaz4Tguppk9MD2/OI8="
[mod."github.com/mattn/go-isatty"]
version = "v0.0.16"
hash = "sha256-YMaPZvShDfA98vqw1+zWWl7M1IT4nHPGBrAt7kHo8Iw="
@ -334,11 +368,14 @@ schema = 3
version = "v0.1.1"
hash = "sha256-SoKy4Mwkbm0J2yQLDcIcBbo/J6auTNdlZslTvJrSknM="
[mod."github.com/mimoo/StrobeGo"]
version = "v0.0.0-20181016162300-f8f6d4d2b643"
hash = "sha256-ih5WfC48IniPuAHUpC6upOabZA1/DssTAcxhZe6A/dE="
version = "v0.0.0-20210601165009-122bf33a46e0"
hash = "sha256-rmw70RHsbeOnema++aFCPdswADMVKtb7KGF3msOI7ak="
[mod."github.com/minio/highwayhash"]
version = "v1.0.2"
hash = "sha256-UeHeepKtToyA5e/w3KdmpbCn+4medesZG0cAcU6P2cY="
[mod."github.com/minio/sha256-simd"]
version = "v1.0.0"
hash = "sha256-oEo/BoMqSLdwSjrhHTiFjl5Om4MVLNQXDJINk6Z110Y="
[mod."github.com/mitchellh/go-homedir"]
version = "v1.1.0"
hash = "sha256-oduBKXHAQG8X6aqLEpqZHs5DOKe84u6WkBwi4W6cv3k="
@ -348,18 +385,36 @@ schema = 3
[mod."github.com/mitchellh/mapstructure"]
version = "v1.5.0"
hash = "sha256-ztVhGQXs67MF8UadVvG72G3ly0ypQW0IRDdOOkjYwoE="
[mod."github.com/mr-tron/base58"]
version = "v1.2.0"
hash = "sha256-8FzMu3kHUbBX10pUdtGf59Ag7BNupx8ZHeUaodR1/Vk="
[mod."github.com/mtibben/percent"]
version = "v0.2.1"
hash = "sha256-Zj1lpCP6mKQ0UUTMs2By4LC414ou+iJzKkK+eBHfEcc="
[mod."github.com/multiformats/go-base32"]
version = "v0.0.3"
hash = "sha256-L18a2v2c5XenmJcwB1BmN0XzDFY45H0ougcZwrGVl7g="
[mod."github.com/multiformats/go-base36"]
version = "v0.1.0"
hash = "sha256-QGoZm4HrdKWwmbJNbaTW0PvDdvPYrhx10znwhIFnFNM="
[mod."github.com/multiformats/go-multibase"]
version = "v0.0.3"
hash = "sha256-yH1bl+jSJlAvPSqg9Z7xF4JS2fpoNUqH8wCDbU87ZDA="
[mod."github.com/multiformats/go-multihash"]
version = "v0.2.0"
hash = "sha256-4pBq4HNCgos2Ic0FDw2WhoPOL5VL1FHLbiHvnO8oZSc="
[mod."github.com/multiformats/go-varint"]
version = "v0.0.6"
hash = "sha256-QlY6AzrSB/8IrlINPi8J8uw1J0SOa2UMTtlo79fg9gM="
[mod."github.com/olekukonko/tablewriter"]
version = "v0.0.5"
hash = "sha256-/5i70IkH/qSW5KjGzv8aQNKh9tHoz98tqtL0K2DMFn4="
[mod."github.com/onsi/ginkgo/v2"]
version = "v2.2.0"
hash = "sha256-+VzAN6pB5DwEqT/KHdhgfPnWBtyIIcHi1J4HQkqCvvU="
version = "v2.5.1"
hash = "sha256-VB29+H9k7l6il63oXJvsjamSUhsw/e99iI/BeTCderA="
[mod."github.com/onsi/gomega"]
version = "v1.20.2"
hash = "sha256-3SGyvhWVlR3tYojnRSDr2SRToontAtw4hbZX+agn/Hs="
version = "v1.24.1"
hash = "sha256-REfxQTDRcO23GnmJfOW8/MmPJf9oE2grVvvGiC1eSbo="
[mod."github.com/pelletier/go-toml"]
version = "v1.9.5"
hash = "sha256-RJ9K1BTId0Mled7S66iGgxHkZ5JKEIsrrNaEfM8aImc="
@ -375,6 +430,9 @@ schema = 3
[mod."github.com/pmezard/go-difflib"]
version = "v1.0.0"
hash = "sha256-/FtmHnaGjdvEIKAJtrUfEhV7EVo5A/eYrtdnUkuxLDA="
[mod."github.com/polydawn/refmt"]
version = "v0.0.0-20201211092308-30ac6d18308e"
hash = "sha256-oicfIWyK51U0LaNW0qgg5enH866TM6vsJExw98whjio="
[mod."github.com/prometheus/client_golang"]
version = "v1.12.2"
hash = "sha256-d8xHyML/FImuPmFOy7UGW/y85NPLzJYL6IFhR3s7XzE="
@ -385,8 +443,8 @@ schema = 3
version = "v0.34.0"
hash = "sha256-M+v+7DntUBmiQNzfNmG3aLLufbl0XBQOubtYoNTzJDA="
[mod."github.com/prometheus/procfs"]
version = "v0.7.3"
hash = "sha256-ik0WpnpSjMwifPYfQTfu/eb5ilNj+eLJF0d5Dftp8A8="
version = "v0.8.0"
hash = "sha256-hgrilokQsXCOCCvwgOSfuErxoFAQpXM/+zNJKcMVHyM="
[mod."github.com/prometheus/tsdb"]
version = "v0.7.1"
hash = "sha256-BPz7YJbfMZgeR+u9YaeWeipVzHIS73EdgXD7VSJSLbA="
@ -394,8 +452,8 @@ schema = 3
version = "v0.1.7"
hash = "sha256-/bfnXHBmN8vviPL7D85IzcEVXCaWyjbPPNyauzEcQ8Q="
[mod."github.com/rcrowley/go-metrics"]
version = "v0.0.0-20200313005456-10cdbea86bc0"
hash = "sha256-xHqWWd4/RyAxqb80zjnrqHnHtWPfVTyByE+vDfbT52E="
version = "v0.0.0-20201227073835-cf1acfcdf475"
hash = "sha256-10ytHQ1SpMKYTiKuOPdEMuOVa8HVvv9ryYSIF9BHEBI="
[mod."github.com/regen-network/cosmos-proto"]
version = "v0.3.1"
hash = "sha256-Bchbq/Hg72EA7Hevs8+PNuENuQaZAzk3qeVjMqFMUxc="
@ -409,20 +467,23 @@ schema = 3
version = "v1.27.0"
hash = "sha256-BxQtP2TROeSSpj9l1irocuSfxn55UL4ugzB/og7r8eE="
[mod."github.com/sasha-s/go-deadlock"]
version = "v0.2.1-0.20190427202633-1595213edefa"
hash = "sha256-BBOohTR+ktgJHAoYWh39/ui8MczcJECloc7tvxVBE50="
version = "v0.3.1"
hash = "sha256-2CBEi9/iN/OMt7wEIG+hRjgDH6CRWIgibGGGy1dQ78I="
[mod."github.com/shirou/gopsutil"]
version = "v3.21.4-0.20210419000835-c7a38de76ee5+incompatible"
hash = "sha256-oqIqyFquWabIE6DID6uTEc8oFEmM1rVu2ATn3toiCEg="
[mod."github.com/spaolacci/murmur3"]
version = "v1.1.0"
hash = "sha256-RWD4PPrlAsZZ8Xy356MBxpj+/NZI7w2XOU14Ob7/Y9M="
[mod."github.com/spf13/afero"]
version = "v1.8.2"
hash = "sha256-ERuG4GK1LOn72DRbT9URpo1QoVIm2A3mPtlf+xSPgx8="
version = "v1.9.2"
hash = "sha256-R1mir7Fu95QK+YL99U14RGbLJzxqWRH5rSFpssgJvzA="
[mod."github.com/spf13/cast"]
version = "v1.5.0"
hash = "sha256-Pdp+wC5FWqyJKzyYHb7JCcV9BoJk/sxQw6nLyuLJvuQ="
[mod."github.com/spf13/cobra"]
version = "v1.5.0"
hash = "sha256-rcyHWrxshA5DVpxrSba5X4NjppqOGrJ64QkUKKnfW2E="
version = "v1.6.1"
hash = "sha256-80B5HcYdFisz6QLYkTyka7f9Dr6AfcVyPwp3QChoXwU="
[mod."github.com/spf13/jwalterweatherman"]
version = "v1.1.0"
hash = "sha256-62BQtqTLF/eVrTOr7pUXE7AiHRjOVC8jQs3/Ehmflfs="
@ -430,17 +491,17 @@ schema = 3
version = "v1.0.5"
hash = "sha256-w9LLYzxxP74WHT4ouBspH/iQZXjuAh2WQCHsuvyEjAw="
[mod."github.com/spf13/viper"]
version = "v1.13.0"
hash = "sha256-yHviS3lMo1hB6jwyiU3zpyGtxP6v9AsyZUKiLeCVz+k="
version = "v1.14.0"
hash = "sha256-qn3VzD339HZIub5QP4aWVciSufAfVb9llbmQZ8pfDEs="
[mod."github.com/status-im/keycard-go"]
version = "v0.0.0-20200402102358-957c09536969"
hash = "sha256-yddXXuu6mEFEO2/K6c1tWymeBKzOcvLQnNsFGRjtfXk="
[mod."github.com/stretchr/objx"]
version = "v0.4.0"
hash = "sha256-W6ycaeD/okr4udpCAGDsByr3OmiR0fuBzJUXHaHEFC0="
version = "v0.5.0"
hash = "sha256-nY4mvP0f0Ry1IKMKQAYNuioA5h4red4mmQqeGZw6EF0="
[mod."github.com/stretchr/testify"]
version = "v1.8.0"
hash = "sha256-LDxBAebK+A06y4vbH7cd1sVBOameIY81Xm8/9OPZh7o="
version = "v1.8.1"
hash = "sha256-3e0vOJLgCMAan+GfaGN8RGZdarh5iCavM6flf6YMNPk="
[mod."github.com/subosito/gotenv"]
version = "v1.4.1"
hash = "sha256-aHAUs8Gh+BREUulljWr7vBZQg1BLu/M/8UfNK8CWSn8="
@ -457,8 +518,8 @@ schema = 3
version = "v0.16.0"
hash = "sha256-JW4zO/0vMzf1dXLePOqaMtiLUZgNbuIseh9GV+jQlf0="
[mod."github.com/tendermint/tendermint"]
version = "v0.34.21"
hash = "sha256-C1KW6Wd4TwsFC09IHt8Jo3dozEk/Q2ZVdTapM8btEJ0="
version = "v0.34.24"
hash = "sha256-3HFTv4XgN535RDaJ5OwUS+fnJHgkmLTwU7CNU2ilxEQ="
[mod."github.com/tendermint/tm-db"]
version = "v0.6.7"
hash = "sha256-hl/3RrBrpkk2zA6dmrNlIYKs1/GfqegSscDSkA5Pjlo="
@ -474,9 +535,18 @@ schema = 3
[mod."github.com/ulikunitz/xz"]
version = "v0.5.8"
hash = "sha256-bfG3dssBUn+mSOAuKL+a/DTGGLUA+eASgLoGv/Gkqs0="
[mod."github.com/vektah/gqlparser/v2"]
version = "v2.5.1"
hash = "sha256-sfwSSafdEXEv/ca/EOjgaPEdezewuqdE+5AuwhsHxYU="
[mod."github.com/whyrusleeping/cbor-gen"]
version = "v0.0.0-20200123233031-1cdf64d27158"
hash = "sha256-E+9b4eXoLe95J6/n2Y12z15tMnxPoxdJtHe9B4mLFDA="
[mod."github.com/zondax/hid"]
version = "v0.9.1-0.20220302062450-5552068d2266"
hash = "sha256-IZea8SHuLQxlltm1avieRVI054TWZg2jEoplodvNtwk="
version = "v0.9.1"
hash = "sha256-hSVmN/f/lQHFhF60o6ej78ELC0MMoqQgqIX2hHjdTXg="
[mod."github.com/zondax/ledger-go"]
version = "v0.14.0"
hash = "sha256-RozTPSNs4RerZ4DQMBcGmvREjoRtH1G69xjhccYjIOk="
[mod."go.etcd.io/bbolt"]
version = "v1.3.6"
hash = "sha256-DenVAmyN22xUiivk6fdJp4C9ZnUJXCMDUf8E0goRRV4="
@ -484,47 +554,47 @@ schema = 3
version = "v0.23.0"
hash = "sha256-R3O9GyNtv6j0ic7s+2xkLLaLzbJEop0Otj1nJDFBjsg="
[mod."golang.org/x/crypto"]
version = "v0.0.0-20220622213112-05595931fe9d"
hash = "sha256-2c4wvwiQ0DJSJsApfmNoxCxx1siRCiJvW9hhrGlcvds="
version = "v0.3.0"
hash = "sha256-Un9wPqz8u/xpV98T4IqE6RMXIPhGCIm2prsNkHP3cjg="
[mod."golang.org/x/exp"]
version = "v0.0.0-20220722155223-a9213eeb770e"
hash = "sha256-kNgzydWRpjm0sZl4uXEs3LX5L0xjJtJRAFf/CTlYUN4="
[mod."golang.org/x/net"]
version = "v0.0.0-20220726230323-06994584191e"
hash = "sha256-VFJB2BjvFZnp0zoJLX4iinV/P6Cn7XUlsKwBGCdVjlU="
version = "v0.4.0"
hash = "sha256-7IwGZh/xg4mQz88cJio2Ov5d3jGRXKj1itlAja/EAbQ="
[mod."golang.org/x/oauth2"]
version = "v0.0.0-20220622183110-fd043fe589d2"
hash = "sha256-VLffpTpx3DlUzXB8mKiJfFzm4ZmgnLSUuLB5Ir0WQUg="
version = "v0.0.0-20221014153046-6fdb5e3db783"
hash = "sha256-IoygidVNqyAZmN+3macDeIefK8hhJToygpcqlwehdYQ="
[mod."golang.org/x/sync"]
version = "v0.0.0-20220722155255-886fb9371eb4"
hash = "sha256-ZZyIlxh+nqsOiWHstW7eHXN7RhHnbSL2eDIzcve07Q0="
version = "v0.1.0"
hash = "sha256-Hygjq9euZ0qz6TvHYQwOZEjNiTbTh1nSLRAWZ6KFGR8="
[mod."golang.org/x/sys"]
version = "v0.0.0-20220811171246-fbc7d0a398ab"
hash = "sha256-acnc9aKY/SyebObLasV+gowfB0S+6ehz3hnUgAmQmSU="
version = "v0.3.0"
hash = "sha256-TIHhfYbZ99sCU1ZMikxwomXH5AEtD/lA1VMMW+UAhbU="
[mod."golang.org/x/term"]
version = "v0.0.0-20220722155259-a9ba230a4035"
hash = "sha256-9uM1OONzbsa6bz2iKk767hAaCuafi58bdTF7at03fWY="
version = "v0.3.0"
hash = "sha256-NKv2o8wz8DB/2W2h/muGEIHb+S06mBXZxhG254RpQ5s="
[mod."golang.org/x/text"]
version = "v0.3.7"
hash = "sha256-XH2pUzzQx95O0rak00grQvfACfL+EmZiV7ZzJBkX+XY="
version = "v0.5.0"
hash = "sha256-ztH+xQyM/clOcQl+y/UEPcfNKbc3xApMbEPDDZ9up0o="
[mod."golang.org/x/xerrors"]
version = "v0.0.0-20220609144429-65e65417b02f"
hash = "sha256-tl8pv3oddbz2+KoIp7PFDKsxjQF8ocjPF8XPsY3sw38="
version = "v0.0.0-20220907171357-04be3eba64a2"
hash = "sha256-6+zueutgefIYmgXinOflz8qGDDDj0Zhv+2OkGhBTKno="
[mod."google.golang.org/api"]
version = "v0.93.0"
hash = "sha256-W17B79osAhObMbrCHlgywEPg9yIPx0ZISDhp9JwFE5A="
version = "v0.102.0"
hash = "sha256-q8t08Wu0qzOQOmhY4GSoUrhqLTW/TeXiKhio+5ONfe4="
[mod."google.golang.org/appengine"]
version = "v1.6.7"
hash = "sha256-zIxGRHiq4QBvRqkrhMGMGCaVL4iM4TtlYpAi/hrivS4="
[mod."google.golang.org/genproto"]
version = "v0.0.0-20220815135757-37a418bb8959"
hash = "sha256-uS60VVZDdn6kNV24bmOmSTuwz4lBqVM+9XK176GGL2s="
version = "v0.0.0-20221116193143-41c2ba794472"
hash = "sha256-uQuxuOvWRsdMii5M5QresisVd1E+Ss8s2WfR2n7QSXk="
[mod."google.golang.org/grpc"]
version = "v1.49.0"
hash = "sha256-x4+/XjxI2HY8fZYMiEV7Kv+2SrnlmaTJX3tBl+dPUoI="
version = "v1.51.0"
hash = "sha256-RzH5DU13D/ulxxOouIKpdNt8eHdff7mrEnB+JUupbLU="
[mod."google.golang.org/protobuf"]
version = "v1.28.1"
hash = "sha256-sTJYgvlv5is7vHNxcuigF2lNASp0QonhUgnrguhfHSU="
version = "v1.28.2-0.20220831092852-f930b1dc76e8"
hash = "sha256-li5hXlXwTJ5LIZ8bVki1AZ6UFI2gXHl33JwdX1dOrtM="
[mod."gopkg.in/ini.v1"]
version = "v1.67.0"
hash = "sha256-V10ahGNGT+NLRdKUyRg1dos5RxLBXBk1xutcnquc/+4="
@ -537,6 +607,9 @@ schema = 3
[mod."gopkg.in/yaml.v3"]
version = "v3.0.1"
hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU="
[mod."lukechampine.com/blake3"]
version = "v1.1.6"
hash = "sha256-pKVTpuCcqGSn8s11Jq33yrXewQLvycuAoxKJEdbZ7rA="
[mod."nhooyr.io/websocket"]
version = "v1.8.6"
hash = "sha256-DyaiCc/1iELrl6JSpz6WYMtFwUiSCOSoNF8IhSyP1ag="

View File

@ -3,11 +3,11 @@ package indexer
import (
"fmt"
errorsmod "cosmossdk.io/errors"
rpctypes "github.com/cerc-io/laconicd/rpc/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/ethereum/go-ethereum/common"
abci "github.com/tendermint/tendermint/abci/types"
@ -110,12 +110,12 @@ func (kv *KVIndexer) IndexBlock(block *tmtypes.Block, txResults []*abci.Response
ethTxIndex++
if err := saveTxResult(kv.clientCtx.Codec, batch, txHash, &txResult); err != nil {
return sdkerrors.Wrapf(err, "IndexBlock %d", height)
return errorsmod.Wrapf(err, "IndexBlock %d", height)
}
}
}
if err := batch.Write(); err != nil {
return sdkerrors.Wrapf(err, "IndexBlock %d, write batch", block.Height)
return errorsmod.Wrapf(err, "IndexBlock %d, write batch", block.Height)
}
return nil
}
@ -134,14 +134,14 @@ func (kv *KVIndexer) FirstIndexedBlock() (int64, error) {
func (kv *KVIndexer) GetByTxHash(hash common.Hash) (*ethermint.TxResult, error) {
bz, err := kv.db.Get(TxHashKey(hash))
if err != nil {
return nil, sdkerrors.Wrapf(err, "GetByTxHash %s", hash.Hex())
return nil, errorsmod.Wrapf(err, "GetByTxHash %s", hash.Hex())
}
if len(bz) == 0 {
return nil, fmt.Errorf("tx not found, hash: %s", hash.Hex())
}
var txKey ethermint.TxResult
if err := kv.clientCtx.Codec.Unmarshal(bz, &txKey); err != nil {
return nil, sdkerrors.Wrapf(err, "GetByTxHash %s", hash.Hex())
return nil, errorsmod.Wrapf(err, "GetByTxHash %s", hash.Hex())
}
return &txKey, nil
}
@ -150,7 +150,7 @@ func (kv *KVIndexer) GetByTxHash(hash common.Hash) (*ethermint.TxResult, error)
func (kv *KVIndexer) GetByBlockAndIndex(blockNumber int64, txIndex int32) (*ethermint.TxResult, error) {
bz, err := kv.db.Get(TxIndexKey(blockNumber, txIndex))
if err != nil {
return nil, sdkerrors.Wrapf(err, "GetByBlockAndIndex %d %d", blockNumber, txIndex)
return nil, errorsmod.Wrapf(err, "GetByBlockAndIndex %d %d", blockNumber, txIndex)
}
if len(bz) == 0 {
return nil, fmt.Errorf("tx not found, block: %d, eth-index: %d", blockNumber, txIndex)
@ -174,7 +174,7 @@ func TxIndexKey(blockNumber int64, txIndex int32) []byte {
func LoadLastBlock(db dbm.DB) (int64, error) {
it, err := db.ReverseIterator([]byte{KeyPrefixTxIndex}, []byte{KeyPrefixTxIndex + 1})
if err != nil {
return 0, sdkerrors.Wrap(err, "LoadLastBlock")
return 0, errorsmod.Wrap(err, "LoadLastBlock")
}
defer it.Close()
if !it.Valid() {
@ -187,7 +187,7 @@ func LoadLastBlock(db dbm.DB) (int64, error) {
func LoadFirstBlock(db dbm.DB) (int64, error) {
it, err := db.Iterator([]byte{KeyPrefixTxIndex}, []byte{KeyPrefixTxIndex + 1})
if err != nil {
return 0, sdkerrors.Wrap(err, "LoadFirstBlock")
return 0, errorsmod.Wrap(err, "LoadFirstBlock")
}
defer it.Close()
if !it.Valid() {
@ -213,10 +213,10 @@ func isEthTx(tx sdk.Tx) bool {
func saveTxResult(codec codec.Codec, batch dbm.Batch, txHash common.Hash, txResult *ethermint.TxResult) error {
bz := codec.MustMarshal(txResult)
if err := batch.Set(TxHashKey(txHash), bz); err != nil {
return sdkerrors.Wrap(err, "set tx-hash key")
return errorsmod.Wrap(err, "set tx-hash key")
}
if err := batch.Set(TxIndexKey(txResult.Height, txResult.EthTxIndex), txHash.Bytes()); err != nil {
return sdkerrors.Wrap(err, "set tx-index key")
return errorsmod.Wrap(err, "set tx-index key")
}
return nil
}

View File

@ -1,12 +1,12 @@
#!/bin/bash
KEY="mykey"
CHAINID="ethermint_9000-1"
CHAINID="laconic_2345678-1"
MONIKER="localtestnet"
KEYRING="test"
KEYALGO="eth_secp256k1"
LOGLEVEL="info"
# to trace evm
# trace evm
TRACE="--trace"
# TRACE=""

5
mlc_config.json Normal file
View File

@ -0,0 +1,5 @@
{
"retryOn429": true,
"retryCount": 3,
"fallbackRetryDelay": "20s"
}

View File

@ -15,7 +15,7 @@ COPY . .
RUN make build-linux
# Final image
FROM golang:1.18 as final
FROM golang:1.19 as final
WORKDIR /

View File

@ -27,7 +27,7 @@ import sources.nixpkgs {
dotenv = builtins.path { name = "dotenv"; path = ../scripts/.env; };
};
})
(_: pkgs: { test-env = import ./testenv.nix { inherit pkgs; }; })
(_: pkgs: { test-env = pkgs.callPackage ./testenv.nix { }; })
(_: pkgs: {
cosmovisor = pkgs.buildGo118Module rec {
name = "cosmovisor";

View File

@ -1,4 +1,4 @@
{ lib, stdenv, buildGoModule, fetchFromGitHub, libobjc, IOKit }:
{ lib, stdenv, buildGoModule, fetchFromGitHub, libobjc, IOKit, nixosTests }:
let
# A list of binaries to put into separate outputs
@ -7,19 +7,18 @@ let
"clef"
];
in
buildGoModule rec {
in buildGoModule rec {
pname = "go-ethereum";
version = "1.10.19";
version = "1.10.25";
src = fetchFromGitHub {
owner = "ethereum";
repo = pname;
rev = "v${version}";
sha256 = "0f6n9rg42ph47mvykc9f0lf99yzwqy4jm7mlzyks4l6i6fl1g3q1";
sha256 = "sha256-mnf0kMfQEEQMricZJfyF7ZB/2F1dyPBx9iT2v/rGh1U=";
};
vendorSha256 = "1s5yfpk2yn7f3zwjl2fdrh6c63ki2b8rlmnlss27yxibsidaj0yd";
vendorSha256 = "sha256-Dj+xN8lr98LJyYr2FwJ7yUIJkUeUrr1fkcbj4hShJI0=";
doCheck = false;
@ -47,14 +46,19 @@ buildGoModule rec {
"cmd/utils"
];
# Following upstream: https://github.com/ethereum/go-ethereum/blob/v1.10.25/build/ci.go#L218
tags = [ "urfave_cli_no_docs" ];
# Fix for usb-related segmentation faults on darwin
propagatedBuildInputs =
lib.optionals stdenv.isDarwin [ libobjc IOKit ];
passthru.tests = { inherit (nixosTests) geth; };
meta = with lib; {
homepage = "https://geth.ethereum.org/";
description = "Official golang implementation of the Ethereum protocol";
license = with licenses; [ lgpl3Plus gpl3Plus ];
maintainers = with maintainers; [ adisbladis lionello RaghavSood ];
maintainers = with maintainers; [ adisbladis RaghavSood ];
};
}

50
nix/sources.json Normal file
View File

@ -0,0 +1,50 @@
{
"cosmos-sdk": {
"branch": "main",
"description": ":chains: A Framework for Building High Value Public Blockchains :sparkles:",
"homepage": "https://cosmos.network/",
"owner": "cosmos",
"repo": "cosmos-sdk",
"rev": "b6c77e6c819f8a51166649eaef125d1bfb276f04",
"sha256": "09ns4yfxyfi7c7n5g69zv32m1rdssdl48c1akmv1y2vz6ayz4v02",
"type": "tarball",
"url": "https://github.com/cosmos/cosmos-sdk/archive/b6c77e6c819f8a51166649eaef125d1bfb276f04.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"gomod2nix": {
"branch": "master",
"description": "Convert applications using Go modules to Nix expressions",
"homepage": null,
"owner": "tweag",
"repo": "gomod2nix",
"rev": "40d32f82fc60d66402eb0972e6e368aeab3faf58",
"sha256": "0li17ynbg2wg0xqy655m5rmcw905sbv7d4ir35z7s5pg1yhhzxkp",
"type": "tarball",
"url": "https://github.com/tweag/gomod2nix/archive/40d32f82fc60d66402eb0972e6e368aeab3faf58.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"niv": {
"branch": "master",
"description": "Easy dependency management for Nix projects",
"homepage": "https://github.com/nmattia/niv",
"owner": "nmattia",
"repo": "niv",
"rev": "e0ca65c81a2d7a4d82a189f1e23a48d59ad42070",
"sha256": "1pq9nh1d8nn3xvbdny8fafzw87mj7gsmp6pxkdl65w2g18rmcmzx",
"type": "tarball",
"url": "https://github.com/nmattia/niv/archive/e0ca65c81a2d7a4d82a189f1e23a48d59ad42070.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs": {
"branch": "master",
"description": "Nix Packages collection",
"homepage": "",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ea2c6a6dda1aa35a80139a512a9dee375b0946e7",
"sha256": "0nd4nn9ryqa80ssw3j2kmr8wa73p2xz1hyxp280cdzqlmdfgw1lm",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/ea2c6a6dda1aa35a80139a512a9dee375b0946e7.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
}

View File

@ -1,18 +1,38 @@
{ pkgs }:
pkgs.poetry2nix.mkPoetryEnv {
{ poetry2nix, lib, python310 }:
poetry2nix.mkPoetryEnv {
projectDir = ../tests/integration_tests;
python = pkgs.python39;
overrides = pkgs.poetry2nix.overrides.withDefaults (self: super: {
python = python310;
overrides = poetry2nix.overrides.withDefaults (lib.composeManyExtensions [
(self: super:
let
buildSystems = {
eth-bloom = [ "setuptools" ];
pystarport = [ "poetry" ];
durations = [ "setuptools" ];
multitail2 = [ "setuptools" ];
pytest-github-actions-annotate-failures = [ "setuptools" ];
flake8-black = [ "setuptools" ];
multiaddr = [ "setuptools" ];
};
in
lib.mapAttrs
(attr: systems: super.${attr}.overridePythonAttrs
(old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ map (a: self.${a}) systems;
}))
buildSystems
)
(self: super: {
eth-bloom = super.eth-bloom.overridePythonAttrs {
preConfigure = ''
substituteInPlace setup.py --replace \'setuptools-markdown\' ""
'';
};
pystarport = super.pystarport.overridePythonAttrs (
old: {
nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ self.poetry ];
}
);
});
pyyaml-include = super.pyyaml-include.overridePythonAttrs {
preConfigure = ''
substituteInPlace setup.py --replace "setup()" "setup(version=\"1.3\")"
'';
};
})
]);
}

8
proto/buf.gen.gogo.yaml Normal file
View File

@ -0,0 +1,8 @@
version: v1
plugins:
- name: gocosmos
out: .
opt: plugins=grpc,google/protobuf/duration.proto=google/protobuf/duration.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types,Mcosmos/orm/v1alpha1/orm.proto=github.com/cosmos/cosmos-sdk/api/cosmos/orm/v1alpha1
- name: grpc-gateway
out: .
opt: logtostderr=true,allow_colon_final_segments=true

View File

@ -0,0 +1,15 @@
version: v1
plugins:
- name: gocosmos
out: .
opt: plugins=grpc,google/protobuf/duration.proto=google/protobuf/duration.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types,Mcosmos/orm/v1alpha1/orm.proto=github.com/cosmos/cosmos-sdk/api/cosmos/orm/v1alpha1
- name: grpc-gateway
out: .
opt: logtostderr=true
- name: swagger
out: ./tmp-swagger-gen
opt:
- logtostderr=true
- fqn_for_swagger_name=true
- simple_operation_ids=true
strategy: all

19
proto/buf.lock Normal file
View File

@ -0,0 +1,19 @@
# Generated by buf. DO NOT EDIT.
version: v1
deps:
- remote: buf.build
owner: cosmos
repository: cosmos-proto
commit: 1935555c206d4afb9e94615dfd0fad31
- remote: buf.build
owner: cosmos
repository: cosmos-sdk
commit: 508e19f5f37549e3a471a2a59b903c00
- remote: buf.build
owner: cosmos
repository: gogo-proto
commit: 34d970b699f84aa382f3c29773a60836
- remote: buf.build
owner: googleapis
repository: googleapis
commit: 783e4b5374fa488ab068d08af9658438

View File

@ -1,4 +1,10 @@
version: v1
name: buf.build/cerc-io/laconicd
deps:
- buf.build/cosmos/cosmos-sdk
- buf.build/cosmos/cosmos-proto
- buf.build/cosmos/gogo-proto
- buf.build/googleapis/googleapis
lint:
use:
- DEFAULT

View File

@ -11,11 +11,13 @@ option go_package = "github.com/cerc-io/laconicd/crypto/ethsecp256k1";
message PubKey {
option (gogoproto.goproto_stringer) = false;
// key is the public key in byte form
bytes key = 1;
}
// PrivKey defines a type alias for an ecdsa.PrivateKey that implements
// Tendermint's PrivateKey interface.
message PrivKey {
// key is the private key in byte form
bytes key = 1;
}

View File

@ -7,18 +7,18 @@ option go_package = "github.com/cerc-io/laconicd/x/evm/types";
// Params defines the EVM module parameters
message Params {
// evm denom represents the token denomination used to run the EVM state
// evm_denom represents the token denomination used to run the EVM state
// transitions.
string evm_denom = 1 [(gogoproto.moretags) = "yaml:\"evm_denom\""];
// enable create toggles state transitions that use the vm.Create function
// enable_create toggles state transitions that use the vm.Create function
bool enable_create = 2 [(gogoproto.moretags) = "yaml:\"enable_create\""];
// enable call toggles state transitions that use the vm.Call function
// enable_call toggles state transitions that use the vm.Call function
bool enable_call = 3 [(gogoproto.moretags) = "yaml:\"enable_call\""];
// extra eips defines the additional EIPs for the vm.Config
// extra_eips defines the additional EIPs for the vm.Config
repeated int64 extra_eips = 4 [(gogoproto.customname) = "ExtraEIPs", (gogoproto.moretags) = "yaml:\"extra_eips\""];
// chain config defines the EVM chain configuration parameters
// chain_config defines the EVM chain configuration parameters
ChainConfig chain_config = 5 [(gogoproto.moretags) = "yaml:\"chain_config\"", (gogoproto.nullable) = false];
// Allow unprotected transactions defines if replay-protected (i.e non EIP155
// allow_unprotected_txs defines if replay-protected (i.e non EIP155
// signed) transactions can be executed on the state machine.
bool allow_unprotected_txs = 6;
}
@ -26,67 +26,67 @@ message Params {
// ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int values
// instead of *big.Int.
message ChainConfig {
// Homestead switch block (nil no fork, 0 = already homestead)
// homestead_block switch (nil no fork, 0 = already homestead)
string homestead_block = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"homestead_block\""
];
// TheDAO hard-fork switch block (nil no fork)
// dao_fork_block corresponds to TheDAO hard-fork switch block (nil no fork)
string dao_fork_block = 2 [
(gogoproto.customname) = "DAOForkBlock",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"dao_fork_block\""
];
// Whether the nodes supports or opposes the DAO hard-fork
// dao_fork_support defines whether the nodes supports or opposes the DAO hard-fork
bool dao_fork_support = 3
[(gogoproto.customname) = "DAOForkSupport", (gogoproto.moretags) = "yaml:\"dao_fork_support\""];
// EIP150 implements the Gas price changes
// eip150_block: EIP150 implements the Gas price changes
// (https://github.com/ethereum/EIPs/issues/150) EIP150 HF block (nil no fork)
string eip150_block = 4 [
(gogoproto.customname) = "EIP150Block",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"eip150_block\""
];
// EIP150 HF hash (needed for header only clients as only gas pricing changed)
// eip150_hash: EIP150 HF hash (needed for header only clients as only gas pricing changed)
string eip150_hash = 5 [(gogoproto.customname) = "EIP150Hash", (gogoproto.moretags) = "yaml:\"byzantium_block\""];
// EIP155Block HF block
// eip155_block: EIP155Block HF block
string eip155_block = 6 [
(gogoproto.customname) = "EIP155Block",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"eip155_block\""
];
// EIP158 HF block
// eip158_block: EIP158 HF block
string eip158_block = 7 [
(gogoproto.customname) = "EIP158Block",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"eip158_block\""
];
// Byzantium switch block (nil no fork, 0 = already on byzantium)
// byzantium_block: Byzantium switch block (nil no fork, 0 = already on byzantium)
string byzantium_block = 8 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"byzantium_block\""
];
// Constantinople switch block (nil no fork, 0 = already activated)
// constantinople_block: Constantinople switch block (nil no fork, 0 = already activated)
string constantinople_block = 9 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"constantinople_block\""
];
// Petersburg switch block (nil same as Constantinople)
// petersburg_block: Petersburg switch block (nil same as Constantinople)
string petersburg_block = 10 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"petersburg_block\""
];
// Istanbul switch block (nil no fork, 0 = already on istanbul)
// istanbul_block: Istanbul switch block (nil no fork, 0 = already on istanbul)
string istanbul_block = 11 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"istanbul_block\""
];
// Eip-2384 (bomb delay) switch block (nil no fork, 0 = already activated)
// muir_glacier_block: Eip-2384 (bomb delay) switch block (nil no fork, 0 = already activated)
string muir_glacier_block = 12 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"muir_glacier_block\""
];
// Berlin switch block (nil = no fork, 0 = already on berlin)
// berlin_block: Berlin switch block (nil = no fork, 0 = already on berlin)
string berlin_block = 13 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"berlin_block\""
@ -94,12 +94,12 @@ message ChainConfig {
// DEPRECATED: EWASM, YOLOV3 and Catalyst block have been deprecated
reserved 14, 15, 16;
reserved "yolo_v3_block", "ewasm_block", "catalyst_block";
// London switch block (nil = no fork, 0 = already on london)
// london_block: London switch block (nil = no fork, 0 = already on london)
string london_block = 17 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"london_block\""
];
// Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated)
// arrow_glacier_block: Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated)
string arrow_glacier_block = 18 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"arrow_glacier_block\""
@ -107,21 +107,34 @@ message ChainConfig {
// DEPRECATED: merge fork block was deprecated: https://github.com/ethereum/go-ethereum/pull/24904
reserved 19;
reserved "merge_fork_block";
// EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already activated)
// gray_glacier_block: EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already activated)
string gray_glacier_block = 20 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"gray_glacier_block\""
];
// Virtual fork after The Merge to use as a network splitter
// merge_netsplit_block: Virtual fork after The Merge to use as a network splitter
string merge_netsplit_block = 21 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"merge_netsplit_block\""
];
// shanghai_block switch block (nil = no fork, 0 = already on shanghai)
string shanghai_block = 22 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"shanghai_block\""
];
// cancun_block switch block (nil = no fork, 0 = already on cancun)
string cancun_block = 23 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.moretags) = "yaml:\"cancun_block\""
];
}
// State represents a single Storage key value pair item.
message State {
// key is the stored key
string key = 1;
// value is the stored value for the given key
string value = 2;
}
@ -129,38 +142,38 @@ message State {
// with a given hash. It it used for import/export data as transactions are not
// persisted on blockchain state after an upgrade.
message TransactionLogs {
// hash of the transaction
string hash = 1;
// logs is an array of Logs for the given transaction hash
repeated Log logs = 2;
}
// Log represents an protobuf compatible Ethereum Log that defines a contract
// log event. These events are generated by the LOG opcode and stored/indexed by
// the node.
//
// NOTE: address, topics and data are consensus fields. The rest of the fields
// are derived, i.e. filled in by the nodes, but not secured by consensus.
message Log {
// Consensus fields:
// address of the contract that generated the event
string address = 1;
// list of topics provided by the contract.
// topics is a list of topics provided by the contract.
repeated string topics = 2;
// supplied by the contract, usually ABI-encoded
// data which is supplied by the contract, usually ABI-encoded
bytes data = 3;
// Derived fields. These fields are filled in by the node
// but not secured by consensus.
// block in which the transaction was included
// block_number of the block in which the transaction was included
uint64 block_number = 4 [(gogoproto.jsontag) = "blockNumber"];
// hash of the transaction
// tx_hash is the transaction hash
string tx_hash = 5 [(gogoproto.jsontag) = "transactionHash"];
// index of the transaction in the block
// tx_index of the transaction in the block
uint64 tx_index = 6 [(gogoproto.jsontag) = "transactionIndex"];
// hash of the block in which the transaction was included
// block_hash of the block in which the transaction was included
string block_hash = 7 [(gogoproto.jsontag) = "blockHash"];
// index of the log in the block
uint64 index = 8 [(gogoproto.jsontag) = "logIndex"];
// The Removed field is true if this log was reverted due to a chain
// removed is true if this log was reverted due to a chain
// reorganisation. You must pay attention to this field if you receive logs
// through a filter query.
bool removed = 9;
@ -191,9 +204,9 @@ message TxResult {
message AccessTuple {
option (gogoproto.goproto_getters) = false;
// hex formatted ethereum address
// address is a hex formatted ethereum address
string address = 1;
// hex formatted hashes of the storage keys
// storage_keys are hex formatted hashes of the storage keys
repeated string storage_keys = 2 [(gogoproto.jsontag) = "storageKeys"];
}
@ -204,25 +217,27 @@ message TraceConfig {
reserved 4, 7;
reserved "disable_memory", "disable_return_data";
// custom javascript tracer
// tracer is a custom javascript tracer
string tracer = 1;
// overrides the default timeout of 5 seconds for JavaScript-based tracing
// timeout overrides the default timeout of 5 seconds for JavaScript-based tracing
// calls
string timeout = 2;
// number of blocks the tracer is willing to go back
// reexec defines the number of blocks the tracer is willing to go back
uint64 reexec = 3;
// disable stack capture
// disable_stack switches stack capture
bool disable_stack = 5 [(gogoproto.jsontag) = "disableStack"];
// disable storage capture
// disable_storage switches storage capture
bool disable_storage = 6 [(gogoproto.jsontag) = "disableStorage"];
// print output during capture end
// debug can be used to print output during capture end
bool debug = 8;
// maximum length of output, but zero means unlimited
// limit defines the maximum length of output, but zero means unlimited
int32 limit = 9;
// Chain overrides, can be used to execute a trace using future fork rules
// overrides can be used to execute a trace using future fork rules
ChainConfig overrides = 10;
// enable memory capture
// enable_memory switches memory capture
bool enable_memory = 11 [(gogoproto.jsontag) = "enableMemory"];
// enable return data capture
// enable_return_data switches the capture of return data
bool enable_return_data = 12 [(gogoproto.jsontag) = "enableReturnData"];
// tracer_json_config configures the tracer using a JSON string
string tracer_json_config = 13 [(gogoproto.jsontag) = "tracerConfig"];
}

View File

@ -1,8 +1,8 @@
syntax = "proto3";
package ethermint.evm.v1;
import "gogoproto/gogo.proto";
import "ethermint/evm/v1/evm.proto";
import "gogoproto/gogo.proto";
option go_package = "github.com/cerc-io/laconicd/x/evm/types";

View File

@ -1,11 +1,11 @@
syntax = "proto3";
package ethermint.evm.v1;
import "gogoproto/gogo.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "google/api/annotations.proto";
import "ethermint/evm/v1/evm.proto";
import "ethermint/evm/v1/tx.proto";
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "google/protobuf/timestamp.proto";
option go_package = "github.com/cerc-io/laconicd/x/evm/types";
@ -89,7 +89,7 @@ message QueryAccountRequest {
message QueryAccountResponse {
// balance is the balance of the EVM denomination.
string balance = 1;
// code hash is the hex-formatted code bytes from the EOA.
// code_hash is the hex-formatted code bytes from the EOA.
string code_hash = 2;
// nonce is the account's sequence number.
uint64 nonce = 3;
@ -112,7 +112,7 @@ message QueryCosmosAccountResponse {
string cosmos_address = 1;
// sequence is the account's sequence number.
uint64 sequence = 2;
// account_number is the account numbert
// account_number is the account number
uint64 account_number = 3;
}
@ -157,7 +157,7 @@ message QueryStorageRequest {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
/// address is the ethereum hex address to query the storage state for.
// address is the ethereum hex address to query the storage state for.
string address = 1;
// key defines the key of the storage state
@ -167,7 +167,7 @@ message QueryStorageRequest {
// QueryStorageResponse is the response type for the Query/Storage RPC
// method.
message QueryStorageResponse {
// key defines the storage state value hash associated with the given key.
// value defines the storage state value hash associated with the given key.
string value = 1;
}
@ -198,7 +198,7 @@ message QueryTxLogsRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}
// QueryTxLogs is the response type for the Query/TxLogs RPC method.
// QueryTxLogsResponse is the response type for the Query/TxLogs RPC method.
message QueryTxLogsResponse {
// logs represents the ethereum logs generated from the given transaction.
repeated Log logs = 1;
@ -217,60 +217,73 @@ message QueryParamsResponse {
// EthCallRequest defines EthCall request
message EthCallRequest {
// same json format as the json rpc api.
// args uses the same json format as the json rpc api.
bytes args = 1;
// the default gas cap to be used
// gas_cap defines the default gas cap to be used
uint64 gas_cap = 2;
// proposer_address of the requested block in hex format
bytes proposer_address = 3 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress"];
// chain_id is the eip155 chain id parsed from the requested block header
int64 chain_id = 4;
}
// EstimateGasResponse defines EstimateGas response
message EstimateGasResponse {
// the estimated gas
// gas returns the estimated gas
uint64 gas = 1;
}
// QueryTraceTxRequest defines TraceTx request
message QueryTraceTxRequest {
// msgEthereumTx for the requested transaction
// msg is the MsgEthereumTx for the requested transaction
MsgEthereumTx msg = 1;
// tx_index is not necessary anymore
reserved 2;
reserved "tx_index";
// TraceConfig holds extra parameters to trace functions.
// trace_config holds extra parameters to trace functions.
TraceConfig trace_config = 3;
// the predecessor transactions included in the same block
// predecessors is an array of transactions included in the same block
// need to be replayed first to get correct context for tracing.
repeated MsgEthereumTx predecessors = 4;
// block number of requested transaction
// block_number of requested transaction
int64 block_number = 5;
// block hex hash of requested transaction
// block_hash of requested transaction
string block_hash = 6;
// block time of requested transaction
// block_time of requested transaction
google.protobuf.Timestamp block_time = 7 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
// proposer_address is the proposer of the requested block
bytes proposer_address = 8 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress"];
// chain_id is the the eip155 chain id parsed from the requested block header
int64 chain_id = 9;
}
// QueryTraceTxResponse defines TraceTx response
message QueryTraceTxResponse {
// response serialized in bytes
// data is the response serialized in bytes
bytes data = 1;
}
// QueryTraceBlockRequest defines TraceTx request
message QueryTraceBlockRequest {
// txs messages in the block
// txs is an array of messages in the block
repeated MsgEthereumTx txs = 1;
// TraceConfig holds extra parameters to trace functions.
// trace_config holds extra parameters to trace functions.
TraceConfig trace_config = 3;
// block number
// block_number of the traced block
int64 block_number = 5;
// block hex hash
// block_hash (hex) of the traced block
string block_hash = 6;
// block time
// block_time of the traced block
google.protobuf.Timestamp block_time = 7 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
// proposer_address is the address of the requested block
bytes proposer_address = 8 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.ConsAddress"];
// chain_id is the eip155 chain id parsed from the requested block header
int64 chain_id = 9;
}
// QueryTraceBlockResponse defines TraceBlock response
message QueryTraceBlockResponse {
// data is the response serialized in bytes
bytes data = 1;
}
@ -278,7 +291,8 @@ message QueryTraceBlockResponse {
// fee.
message QueryBaseFeeRequest {}
// BaseFeeResponse returns the EIP1559 base fee.
// QueryBaseFeeResponse returns the EIP1559 base fee.
message QueryBaseFeeResponse {
// base_fee is the EIP1559 base fee
string base_fee = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
}

View File

@ -1,11 +1,11 @@
syntax = "proto3";
package ethermint.evm.v1;
import "cosmos_proto/cosmos.proto";
import "ethermint/evm/v1/evm.proto";
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "google/protobuf/any.proto";
import "cosmos_proto/cosmos.proto";
import "ethermint/evm/v1/evm.proto";
option go_package = "github.com/cerc-io/laconicd/x/evm/types";
@ -21,15 +21,14 @@ service Msg {
message MsgEthereumTx {
option (gogoproto.goproto_getters) = false;
// inner transaction data
// data is inner transaction data of the Ethereum transaction
google.protobuf.Any data = 1;
// caches
// DEPRECATED: encoded storage size of the transaction
// size is the encoded storage size of the transaction (DEPRECATED)
double size = 2 [(gogoproto.jsontag) = "-"];
// transaction hash in hex format
// hash of the transaction in hex format
string hash = 3 [(gogoproto.moretags) = "rlp:\"-\""];
// ethereum signer address in hex format. This address value is checked
// from is the ethereum signer address in hex format. This address value is checked
// against the address derived from the signature (V, R, S) using the
// secp256k1 elliptic curve
string from = 4;
@ -44,16 +43,16 @@ message LegacyTx {
// nonce corresponds to the account nonce (transaction sequence).
uint64 nonce = 1;
// gas price defines the value for each gas unit
// gas_price defines the value for each gas unit
string gas_price = 2 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
// gas defines the gas limit defined for the transaction.
uint64 gas = 3 [(gogoproto.customname) = "GasLimit"];
// hex formatted address of the recipient
// to is the hex formatted address of the recipient
string to = 4;
// value defines the unsigned integer value of the transaction amount.
string value = 5
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.customname) = "Amount"];
// input defines the data payload bytes of the transaction.
// data is the data payload bytes of the transaction.
bytes data = 6;
// v defines the signature value
bytes v = 7;
@ -68,7 +67,7 @@ message AccessListTx {
option (gogoproto.goproto_getters) = false;
option (cosmos_proto.implements_interface) = "TxData";
// destination EVM chain ID
// chain_id of the destination EVM chain
string chain_id = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.customname) = "ChainID",
@ -76,17 +75,18 @@ message AccessListTx {
];
// nonce corresponds to the account nonce (transaction sequence).
uint64 nonce = 2;
// gas price defines the value for each gas unit
// gas_price defines the value for each gas unit
string gas_price = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
// gas defines the gas limit defined for the transaction.
uint64 gas = 4 [(gogoproto.customname) = "GasLimit"];
// hex formatted address of the recipient
// to is the recipient address in hex format
string to = 5;
// value defines the unsigned integer value of the transaction amount.
string value = 6
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.customname) = "Amount"];
// input defines the data payload bytes of the transaction.
// data is the data payload bytes of the transaction.
bytes data = 7;
// accesses is an array of access tuples
repeated AccessTuple accesses = 8
[(gogoproto.castrepeated) = "AccessList", (gogoproto.jsontag) = "accessList", (gogoproto.nullable) = false];
// v defines the signature value
@ -102,7 +102,7 @@ message DynamicFeeTx {
option (gogoproto.goproto_getters) = false;
option (cosmos_proto.implements_interface) = "TxData";
// destination EVM chain ID
// chain_id of the destination EVM chain
string chain_id = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.customname) = "ChainID",
@ -110,19 +110,20 @@ message DynamicFeeTx {
];
// nonce corresponds to the account nonce (transaction sequence).
uint64 nonce = 2;
// gas tip cap defines the max value for the gas tip
// gas_tip_cap defines the max value for the gas tip
string gas_tip_cap = 3 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
// gas fee cap defines the max value for the gas fee
// gas_fee_cap defines the max value for the gas fee
string gas_fee_cap = 4 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
// gas defines the gas limit defined for the transaction.
uint64 gas = 5 [(gogoproto.customname) = "GasLimit"];
// hex formatted address of the recipient
// to is the hex formatted address of the recipient
string to = 6;
// value defines the the transaction amount.
string value = 7
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.customname) = "Amount"];
// input defines the data payload bytes of the transaction.
// data is the data payload bytes of the transaction.
bytes data = 8;
// accesses is an array of access tuples
repeated AccessTuple accesses = 9
[(gogoproto.castrepeated) = "AccessList", (gogoproto.jsontag) = "accessList", (gogoproto.nullable) = false];
// v defines the signature value
@ -133,6 +134,7 @@ message DynamicFeeTx {
bytes s = 12;
}
// ExtensionOptionsEthereumTx is an extension option for ethereum transactions
message ExtensionOptionsEthereumTx {
option (gogoproto.goproto_getters) = false;
}
@ -141,18 +143,18 @@ message ExtensionOptionsEthereumTx {
message MsgEthereumTxResponse {
option (gogoproto.goproto_getters) = false;
// ethereum transaction hash in hex format. This hash differs from the
// hash of the ethereum transaction in hex format. This hash differs from the
// Tendermint sha256 hash of the transaction bytes. See
// https://github.com/tendermint/tendermint/issues/6539 for reference
string hash = 1;
// logs contains the transaction hash and the proto-compatible ethereum
// logs.
repeated Log logs = 2;
// returned data from evm function (result or data supplied with revert
// ret is the returned data from evm function (result or data supplied with revert
// opcode)
bytes ret = 3;
// vm error is the error returned by vm execution
// vm_error is the error returned by vm execution
string vm_error = 4;
// gas consumed by the transaction
// gas_used specifies how much gas was consumed by the transaction
uint64 gas_used = 5;
}

View File

@ -7,26 +7,26 @@ option go_package = "github.com/cerc-io/laconicd/x/feemarket/types";
// Params defines the EVM module parameters
message Params {
// no base fee forces the EIP-1559 base fee to 0 (needed for 0 price calls)
// no_base_fee forces the EIP-1559 base fee to 0 (needed for 0 price calls)
bool no_base_fee = 1;
// base fee change denominator bounds the amount the base fee can change
// base_fee_change_denominator bounds the amount the base fee can change
// between blocks.
uint32 base_fee_change_denominator = 2;
// elasticity multiplier bounds the maximum gas limit an EIP-1559 block may
// elasticity_multiplier bounds the maximum gas limit an EIP-1559 block may
// have.
uint32 elasticity_multiplier = 3;
// DEPRECATED: initial base fee for EIP-1559 blocks.
reserved 4;
reserved "initial_base_fee";
// height at which the base fee calculation is enabled.
// enable_height defines at which block height the base fee calculation is enabled.
int64 enable_height = 5;
// base fee for EIP-1559 blocks.
// base_fee for EIP-1559 blocks.
string base_fee = 6 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", (gogoproto.nullable) = false];
// min_gas_price defines the minimum gas price value for cosmos and eth transactions
string min_gas_price = 7
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
// min gas denominator bounds the minimum gasUsed to be charged
// to senders based on GasLimit
// min_gas_multiplier bounds the minimum gas used to be charged
// to senders based on gas limit
string min_gas_multiplier = 8
[(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

View File

@ -1,8 +1,8 @@
syntax = "proto3";
package ethermint.feemarket.v1;
import "gogoproto/gogo.proto";
import "ethermint/feemarket/v1/feemarket.proto";
import "gogoproto/gogo.proto";
option go_package = "github.com/cerc-io/laconicd/x/feemarket/types";
@ -14,7 +14,7 @@ message GenesisState {
// Zero by default.
reserved 2;
reserved "base_fee";
// block gas is the amount of gas wanted on the last block before the upgrade.
// block_gas is the amount of gas wanted on the last block before the upgrade.
// Zero by default.
uint64 block_gas = 3;
}

View File

@ -3,8 +3,8 @@ package ethermint.feemarket.v1;
import "gogoproto/gogo.proto";
// import "cosmos/base/query/v1beta1/pagination.proto";
import "google/api/annotations.proto";
import "ethermint/feemarket/v1/feemarket.proto";
import "google/api/annotations.proto";
option go_package = "github.com/cerc-io/laconicd/x/feemarket/types";
@ -39,8 +39,9 @@ message QueryParamsResponse {
// fee.
message QueryBaseFeeRequest {}
// BaseFeeResponse returns the EIP1559 base fee.
// QueryBaseFeeResponse returns the EIP1559 base fee.
message QueryBaseFeeResponse {
// base_fee is the EIP1559 base fee
string base_fee = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int"];
}
@ -50,5 +51,6 @@ message QueryBlockGasRequest {}
// QueryBlockGasResponse returns block gas used for a given height.
message QueryBlockGasResponse {
// gas is the returned block gas
int64 gas = 1;
}

View File

@ -16,7 +16,10 @@ message EthAccount {
option (cosmos_proto.implements_interface) = "github.com/cosmos/cosmos-sdk/x/auth/types.AccountI";
// base_account is an authtypes.BaseAccount
cosmos.auth.v1beta1.BaseAccount base_account = 1
[(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"base_account\""];
// code_hash is the hash calculated from the code contents
string code_hash = 2 [(gogoproto.moretags) = "yaml:\"code_hash\""];
}

View File

@ -9,21 +9,22 @@ option go_package = "github.com/cerc-io/laconicd/types";
message TxResult {
option (gogoproto.goproto_getters) = false;
// the block height
// height of the blockchain
int64 height = 1;
// cosmos tx index
// tx_index of the cosmos transaction
uint32 tx_index = 2;
// the msg index in a batch tx
// msg_index in a batch transaction
uint32 msg_index = 3;
// eth tx index, the index in the list of valid eth tx in the block,
// eth_tx_index is the index in the list of valid eth tx in the block,
// aka. the transaction list returned by eth_getBlock api.
int32 eth_tx_index = 4;
// if the eth tx is failed
// failed is true if the eth transaction did not go succeed
bool failed = 5;
// gas used by tx, if exceeds block gas limit,
// it's set to gas limit which is what's actually deducted by ante handler.
// gas_used by the transaction. If it exceeds the block gas limit,
// it's set to gas limit, which is what's actually deducted by ante handler.
uint64 gas_used = 6;
// the cumulative gas used within current batch tx
// cumulative_gas_used specifies the cumulated amount of gas used for all
// processed messages within the current batch transaction.
uint64 cumulative_gas_used = 7;
}

View File

@ -5,19 +5,21 @@ import "gogoproto/gogo.proto";
option go_package = "github.com/cerc-io/laconicd/types";
// ExtensionOptionsWeb3Tx is an extension option that specifies the typed chain id,
// the fee payer as well as its signature data.
message ExtensionOptionsWeb3Tx {
option (gogoproto.goproto_getters) = false;
// typed data chain id used only in EIP712 Domain and should match
// typed_data_chain_id is used only in EIP712 Domain and should match
// Ethereum network ID in a Web3 provider (e.g. Metamask).
uint64 typed_data_chain_id = 1
[(gogoproto.jsontag) = "typedDataChainID,omitempty", (gogoproto.customname) = "TypedDataChainID"];
// fee payer is an account address for the fee payer. It will be validated
// fee_payer is an account address for the fee payer. It will be validated
// during EIP712 signature checking.
string fee_payer = 2 [(gogoproto.jsontag) = "feePayer,omitempty"];
// fee payer sig is a signature data from the fee paying account,
// fee_payer_sig is a signature data from the fee paying account,
// allows to perform fee delegation when using EIP712 Domain.
bytes fee_payer_sig = 3 [(gogoproto.jsontag) = "feePayerSig,omitempty"];
}

View File

@ -75,16 +75,10 @@ func (b *Backend) GetProof(address common.Address, storageKeys []string, blockNr
return nil, err
}
// check for proof
var proofStr string
if proof != nil {
proofStr = proof.String()
}
storageProofs[i] = rpctypes.StorageResult{
Key: key,
Value: (*hexutil.Big)(new(big.Int).SetBytes(valueBz)),
Proof: []string{proofStr},
Proof: GetHexProofs(proof),
}
}
@ -105,12 +99,6 @@ func (b *Backend) GetProof(address common.Address, storageKeys []string, blockNr
return nil, err
}
// check for proof
var accProofStr string
if proof != nil {
accProofStr = proof.String()
}
balance, ok := sdkmath.NewIntFromString(res.Balance)
if !ok {
return nil, errors.New("invalid balance")
@ -118,7 +106,7 @@ func (b *Backend) GetProof(address common.Address, storageKeys []string, blockNr
return &rpctypes.AccountResult{
Address: address,
AccountProof: []string{accProofStr},
AccountProof: GetHexProofs(proof),
Balance: (*hexutil.Big)(balance.BigInt()),
CodeHash: common.HexToHash(res.CodeHash),
Nonce: hexutil.Uint64(res.Nonce),

View File

@ -0,0 +1,408 @@
package backend
import (
"fmt"
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
tmrpcclient "github.com/tendermint/tendermint/rpc/client"
"github.com/cerc-io/laconicd/rpc/backend/mocks"
rpctypes "github.com/cerc-io/laconicd/rpc/types"
"github.com/cerc-io/laconicd/tests"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
)
func (suite *BackendTestSuite) TestGetCode() {
blockNr := rpctypes.NewBlockNumber(big.NewInt(1))
contractCode := []byte("0xef616c92f3cfc9e92dc270d6acff9cea213cecc7020a76ee4395af09bdceb4837a1ebdb5735e11e7d3adb6104e0c3ac55180b4ddf5e54d022cc5e8837f6a4f971b")
testCases := []struct {
name string
addr common.Address
blockNrOrHash rpctypes.BlockNumberOrHash
registerMock func(common.Address)
expPass bool
expCode hexutil.Bytes
}{
{
"fail - BlockHash and BlockNumber are both nil ",
tests.GenerateAddress(),
rpctypes.BlockNumberOrHash{},
func(addr common.Address) {},
false,
nil,
},
{
"fail - query client errors on getting Code",
tests.GenerateAddress(),
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(addr common.Address) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterCodeError(queryClient, addr)
},
false,
nil,
},
{
"pass",
tests.GenerateAddress(),
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(addr common.Address) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterCode(queryClient, addr, contractCode)
},
true,
contractCode,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.SetupTest() // reset
tc.registerMock(tc.addr)
code, err := suite.backend.GetCode(tc.addr, tc.blockNrOrHash)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expCode, code)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetProof() {
blockNrInvalid := rpctypes.NewBlockNumber(big.NewInt(1))
blockNr := rpctypes.NewBlockNumber(big.NewInt(4))
address1 := tests.GenerateAddress()
testCases := []struct {
name string
addr common.Address
storageKeys []string
blockNrOrHash rpctypes.BlockNumberOrHash
registerMock func(rpctypes.BlockNumber, common.Address)
expPass bool
expAccRes *rpctypes.AccountResult
}{
{
"fail - BlockNumeber = 1 (invalidBlockNumber)",
address1,
[]string{},
rpctypes.BlockNumberOrHash{BlockNumber: &blockNrInvalid},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlock(client, bn.Int64(), nil)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterAccount(queryClient, addr, blockNrInvalid.Int64())
},
false,
&rpctypes.AccountResult{},
},
{
"fail - Block doesn't exist)",
address1,
[]string{},
rpctypes.BlockNumberOrHash{BlockNumber: &blockNrInvalid},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockError(client, bn.Int64())
},
false,
&rpctypes.AccountResult{},
},
{
"pass",
address1,
[]string{"0x0"},
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
suite.backend.ctx = rpctypes.ContextWithHeight(bn.Int64())
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlock(client, bn.Int64(), nil)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterAccount(queryClient, addr, bn.Int64())
// Use the IAVL height if a valid tendermint height is passed in.
ivalHeight := bn.Int64() - 1
RegisterABCIQueryWithOptions(
client,
bn.Int64(),
"store/evm/key",
evmtypes.StateKey(address1, common.HexToHash("0x0").Bytes()),
tmrpcclient.ABCIQueryOptions{Height: ivalHeight, Prove: true},
)
RegisterABCIQueryWithOptions(
client,
bn.Int64(),
"store/acc/key",
authtypes.AddressStoreKey(sdk.AccAddress(address1.Bytes())),
tmrpcclient.ABCIQueryOptions{Height: ivalHeight, Prove: true},
)
},
true,
&rpctypes.AccountResult{
Address: address1,
AccountProof: []string{""},
Balance: (*hexutil.Big)(big.NewInt(0)),
CodeHash: common.HexToHash(""),
Nonce: 0x0,
StorageHash: common.Hash{},
StorageProof: []rpctypes.StorageResult{
{
Key: "0x0",
Value: (*hexutil.Big)(big.NewInt(2)),
Proof: []string{""},
},
},
},
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.SetupTest()
tc.registerMock(*tc.blockNrOrHash.BlockNumber, tc.addr)
accRes, err := suite.backend.GetProof(tc.addr, tc.storageKeys, tc.blockNrOrHash)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expAccRes, accRes)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetStorageAt() {
blockNr := rpctypes.NewBlockNumber(big.NewInt(1))
testCases := []struct {
name string
addr common.Address
key string
blockNrOrHash rpctypes.BlockNumberOrHash
registerMock func(common.Address, string, string)
expPass bool
expStorage hexutil.Bytes
}{
{
"fail - BlockHash and BlockNumber are both nil",
tests.GenerateAddress(),
"0x0",
rpctypes.BlockNumberOrHash{},
func(addr common.Address, key string, storage string) {},
false,
nil,
},
{
"fail - query client errors on getting Storage",
tests.GenerateAddress(),
"0x0",
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(addr common.Address, key string, storage string) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterStorageAtError(queryClient, addr, key)
},
false,
nil,
},
{
"pass",
tests.GenerateAddress(),
"0x0",
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(addr common.Address, key string, storage string) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterStorageAt(queryClient, addr, key, storage)
},
true,
hexutil.Bytes{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.SetupTest()
tc.registerMock(tc.addr, tc.key, tc.expStorage.String())
storage, err := suite.backend.GetStorageAt(tc.addr, tc.key, tc.blockNrOrHash)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expStorage, storage)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetBalance() {
blockNr := rpctypes.NewBlockNumber(big.NewInt(1))
testCases := []struct {
name string
addr common.Address
blockNrOrHash rpctypes.BlockNumberOrHash
registerMock func(rpctypes.BlockNumber, common.Address)
expPass bool
expBalance *hexutil.Big
}{
{
"fail - BlockHash and BlockNumber are both nil",
tests.GenerateAddress(),
rpctypes.BlockNumberOrHash{},
func(bn rpctypes.BlockNumber, addr common.Address) {
},
false,
nil,
},
{
"fail - tendermint client failed to get block",
tests.GenerateAddress(),
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlockError(client, bn.Int64())
},
false,
nil,
},
{
"fail - query client failed to get balance",
tests.GenerateAddress(),
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlock(client, bn.Int64(), nil)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBalanceError(queryClient, addr, bn.Int64())
},
false,
nil,
},
{
"fail - invalid balance",
tests.GenerateAddress(),
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlock(client, bn.Int64(), nil)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBalanceInvalid(queryClient, addr, bn.Int64())
},
false,
nil,
},
{
"fail - pruned node state",
tests.GenerateAddress(),
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlock(client, bn.Int64(), nil)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBalanceNegative(queryClient, addr, bn.Int64())
},
false,
nil,
},
{
"pass",
tests.GenerateAddress(),
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := suite.backend.clientCtx.Client.(*mocks.Client)
RegisterBlock(client, bn.Int64(), nil)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBalance(queryClient, addr, bn.Int64())
},
true,
(*hexutil.Big)(big.NewInt(1)),
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.SetupTest()
// avoid nil pointer reference
if tc.blockNrOrHash.BlockNumber != nil {
tc.registerMock(*tc.blockNrOrHash.BlockNumber, tc.addr)
}
balance, err := suite.backend.GetBalance(tc.addr, tc.blockNrOrHash)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expBalance, balance)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGetTransactionCount() {
testCases := []struct {
name string
accExists bool
blockNum rpctypes.BlockNumber
registerMock func(common.Address, rpctypes.BlockNumber)
expPass bool
expTxCount hexutil.Uint64
}{
{
"pass - account doesn't exist",
false,
rpctypes.NewBlockNumber(big.NewInt(1)),
func(addr common.Address, bn rpctypes.BlockNumber) {},
true,
hexutil.Uint64(0),
},
// TODO: Error mocking the GetAccount call - problem with Any type
//{
// "pass - returns the number of transactions at the given address up to the given block number",
// true,
// rpctypes.NewBlockNumber(big.NewInt(1)),
// func(addr common.Address, bn rpctypes.BlockNumber) {
// client := suite.backend.clientCtx.Client.(*mocks.Client)
// account, err := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, suite.acc)
// suite.Require().NoError(err)
// request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(suite.acc.Bytes()).String()}
// requestMarshal, _ := request.Marshal()
// RegisterABCIQueryAccount(
// client,
// requestMarshal,
// tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false},
// account,
// )
// },
// true,
// hexutil.Uint64(0),
//},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
suite.SetupTest()
addr := tests.GenerateAddress()
if tc.accExists {
addr = common.BytesToAddress(suite.acc.Bytes())
}
tc.registerMock(addr, tc.blockNum)
txCount, err := suite.backend.GetTransactionCount(addr, tc.blockNum)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(tc.expTxCount, *txCount)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -5,13 +5,11 @@ import (
"math/big"
"time"
"github.com/cerc-io/laconicd/crypto/hd"
rpctypes "github.com/cerc-io/laconicd/rpc/types"
"github.com/cerc-io/laconicd/server/config"
ethermint "github.com/cerc-io/laconicd/types"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -21,7 +19,6 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/log"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
)
@ -162,23 +159,6 @@ func NewBackend(
panic(err)
}
algos, _ := clientCtx.Keyring.SupportedAlgorithms()
if !algos.Contains(hd.EthSecp256k1) {
kr, err := keyring.New(
sdk.KeyringServiceName(),
viper.GetString(flags.FlagKeyringBackend),
clientCtx.KeyringDir,
clientCtx.Input,
clientCtx.Codec,
hd.EthSecp256k1Option(),
)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithKeyring(kr)
}
return &Backend{
ctx: context.Background(),
clientCtx: clientCtx,

View File

@ -2,12 +2,13 @@ package backend
import (
"bufio"
"fmt"
"math/big"
"os"
"path/filepath"
"testing"
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/client"
@ -25,52 +26,76 @@ import (
"github.com/cerc-io/laconicd/indexer"
"github.com/cerc-io/laconicd/rpc/backend/mocks"
rpctypes "github.com/cerc-io/laconicd/rpc/types"
"github.com/cerc-io/laconicd/tests"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
)
type BackendTestSuite struct {
suite.Suite
backend *Backend
acc sdk.AccAddress
signer keyring.Signer
}
func TestBackendTestSuite(t *testing.T) {
suite.Run(t, new(BackendTestSuite))
}
const ChainID = "ethermint_9000-1"
// SetupTest is executed before every BackendTestSuite test
func (suite *BackendTestSuite) SetupTest() {
ctx := server.NewDefaultContext()
ctx.Viper.Set("telemetry.global-labels", []interface{}{})
baseDir := suite.T().TempDir()
nodeDirName := fmt.Sprintf("node")
nodeDirName := "node"
clientDir := filepath.Join(baseDir, nodeDirName, "evmoscli")
keyRing, err := suite.generateTestKeyring(clientDir)
if err != nil {
panic(err)
}
// Create Account with set sequence
suite.acc = sdk.AccAddress(tests.GenerateAddress().Bytes())
accounts := map[string]client.TestAccount{}
accounts[suite.acc.String()] = client.TestAccount{
Address: suite.acc,
Num: uint64(1),
Seq: uint64(1),
}
priv, err := ethsecp256k1.GenerateKey()
suite.signer = tests.NewSigner(priv)
suite.Require().NoError(err)
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
clientCtx := client.Context{}.WithChainID("ethermint_9000-1").
clientCtx := client.Context{}.WithChainID(ChainID).
WithHeight(1).
WithTxConfig(encodingConfig.TxConfig).
WithKeyringDir(clientDir).
WithKeyring(keyRing)
WithKeyring(keyRing).
WithAccountRetriever(client.TestAccountRetriever{Accounts: accounts})
allowUnprotectedTxs := false
idxer := indexer.NewKVIndexer(dbm.NewMemDB(), ctx.Logger, clientCtx)
suite.backend = NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, idxer)
suite.backend.queryClient.QueryClient = mocks.NewQueryClient(suite.T())
suite.backend.queryClient.QueryClient = mocks.NewEVMQueryClient(suite.T())
suite.backend.clientCtx.Client = mocks.NewClient(suite.T())
suite.backend.queryClient.FeeMarket = mocks.NewFeeMarketQueryClient(suite.T())
suite.backend.ctx = rpctypes.ContextWithHeight(1)
// Add codec
encCfg := encoding.MakeConfig(app.ModuleBasics)
suite.backend.clientCtx.Codec = encCfg.Codec
}
// buildEthereumTx returns an example legacy Ethereum transaction
func (suite *BackendTestSuite) buildEthereumTx() (*evmtypes.MsgEthereumTx, []byte) {
msgEthereumTx := evmtypes.NewTx(
big.NewInt(1),
suite.backend.chainID,
uint64(0),
&common.Address{},
big.NewInt(0),
@ -120,6 +145,7 @@ func (suite *BackendTestSuite) buildFormattedBlock(
uint64(header.Height),
uint64(0),
baseFee,
suite.backend.chainID,
)
suite.Require().NoError(err)
ethRPCTxs = []interface{}{rpcTx}
@ -145,3 +171,25 @@ func (suite *BackendTestSuite) generateTestKeyring(clientDir string) (keyring.Ke
encCfg := encoding.MakeConfig(app.ModuleBasics)
return keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, encCfg.Codec, []keyring.Option{hd.EthSecp256k1Option()}...)
}
func (suite *BackendTestSuite) signAndEncodeEthTx(msgEthereumTx *evmtypes.MsgEthereumTx) []byte {
from, priv := tests.NewAddrKey()
signer := tests.NewSigner(priv)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsWithoutHeader(queryClient, 1)
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
msgEthereumTx.From = from.String()
err := msgEthereumTx.Sign(ethSigner, signer)
suite.Require().NoError(err)
tx, err := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
suite.Require().NoError(err)
txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
txBz, err := txEncoder(tx)
suite.Require().NoError(err)
return txBz
}

View File

@ -376,6 +376,7 @@ func (b *Backend) RPCBlockFromTendermintBlock(
uint64(block.Height),
uint64(txIndex),
baseFee,
b.chainID,
)
if err != nil {
b.logger.Debug("NewTransactionFromData for receipt failed", "hash", tx.Hash().Hex(), "error", err.Error())

View File

@ -30,9 +30,9 @@ func (suite *BackendTestSuite) TestBlockNumber() {
{
"fail - invalid block header height",
func() {
height := int64(1)
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
height := int64(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsInvalidHeight(queryClient, &header, int64(height))
},
0x0,
@ -41,9 +41,9 @@ func (suite *BackendTestSuite) TestBlockNumber() {
{
"fail - invalid block header",
func() {
height := int64(1)
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
height := int64(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsInvalidHeader(queryClient, &header, int64(height))
},
0x0,
@ -52,9 +52,9 @@ func (suite *BackendTestSuite) TestBlockNumber() {
{
"pass - app state header height 1",
func() {
height := int64(1)
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
height := int64(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, int64(height))
},
0x1,
@ -161,7 +161,7 @@ func (suite *BackendTestSuite) TestGetBlockByNumber() {
blockRes, _ = RegisterBlockResults(client, blockNum.Int64())
RegisterConsensusParams(client, height)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccount(queryClient, validator)
},
@ -183,7 +183,7 @@ func (suite *BackendTestSuite) TestGetBlockByNumber() {
blockRes, _ = RegisterBlockResults(client, blockNum.Int64())
RegisterConsensusParams(client, height)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccount(queryClient, validator)
},
@ -306,7 +306,7 @@ func (suite *BackendTestSuite) TestGetBlockByHash() {
blockRes, _ = RegisterBlockResults(client, height)
RegisterConsensusParams(client, height)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccount(queryClient, validator)
},
@ -329,7 +329,7 @@ func (suite *BackendTestSuite) TestGetBlockByHash() {
blockRes, _ = RegisterBlockResults(client, height)
RegisterConsensusParams(client, height)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccount(queryClient, validator)
},
@ -552,9 +552,9 @@ func (suite *BackendTestSuite) TestTendermintBlockByNumber() {
"fail - blockNum < 0 with app state height error",
ethrpc.BlockNumber(-1),
func(_ ethrpc.BlockNumber) {
appHeight := int64(1)
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
appHeight := int64(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParamsError(queryClient, &header, appHeight)
},
false,
@ -564,9 +564,9 @@ func (suite *BackendTestSuite) TestTendermintBlockByNumber() {
"pass - blockNum < 0 with app state height >= 1",
ethrpc.BlockNumber(-1),
func(blockNum ethrpc.BlockNumber) {
appHeight := int64(1)
var header metadata.MD
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
appHeight := int64(1)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, appHeight)
tmHeight := appHeight
@ -901,7 +901,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() {
},
false,
func(baseFee sdk.Int, validator sdk.AccAddress, height int64) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccount(queryClient, validator)
@ -925,7 +925,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() {
},
true,
func(baseFee sdk.Int, validator sdk.AccAddress, height int64) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFeeError(queryClient)
RegisterValidatorAccount(queryClient, validator)
@ -949,7 +949,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() {
},
true,
func(baseFee sdk.Int, validator sdk.AccAddress, height int64) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccountError(queryClient)
@ -973,7 +973,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() {
},
true,
func(baseFee sdk.Int, validator sdk.AccAddress, height int64) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccount(queryClient, validator)
@ -1003,7 +1003,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() {
},
true,
func(baseFee sdk.Int, validator sdk.AccAddress, height int64) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccount(queryClient, validator)
@ -1027,7 +1027,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() {
},
false,
func(baseFee sdk.Int, validator sdk.AccAddress, height int64) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccount(queryClient, validator)
@ -1051,7 +1051,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() {
},
true,
func(baseFee sdk.Int, validator sdk.AccAddress, height int64) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
RegisterValidatorAccount(queryClient, validator)
@ -1088,6 +1088,7 @@ func (suite *BackendTestSuite) TestGetEthBlockFromTendermint() {
uint64(header.Height),
uint64(0),
tc.baseFee,
suite.backend.chainID,
)
suite.Require().NoError(err)
ethRPCTxs = []interface{}{rpcTx}
@ -1237,7 +1238,7 @@ func (suite *BackendTestSuite) TestHeaderByNumber() {
expResultBlock, _ = RegisterBlock(client, height, nil)
RegisterBlockResults(client, height)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFeeError(queryClient)
},
true,
@ -1252,7 +1253,7 @@ func (suite *BackendTestSuite) TestHeaderByNumber() {
expResultBlock, _ = RegisterBlock(client, height, nil)
RegisterBlockResults(client, height)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
},
true,
@ -1267,7 +1268,7 @@ func (suite *BackendTestSuite) TestHeaderByNumber() {
expResultBlock, _ = RegisterBlock(client, height, bz)
RegisterBlockResults(client, height)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
},
true,
@ -1347,7 +1348,7 @@ func (suite *BackendTestSuite) TestHeaderByHash() {
expResultBlock, _ = RegisterBlockByHash(client, hash, bz)
RegisterBlockResults(client, height)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFeeError(queryClient)
},
true,
@ -1362,7 +1363,7 @@ func (suite *BackendTestSuite) TestHeaderByHash() {
expResultBlock, _ = RegisterBlockByHash(client, hash, nil)
RegisterBlockResults(client, height)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
},
true,
@ -1377,7 +1378,7 @@ func (suite *BackendTestSuite) TestHeaderByHash() {
expResultBlock, _ = RegisterBlockByHash(client, hash, bz)
RegisterBlockResults(client, height)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
},
true,
@ -1444,7 +1445,7 @@ func (suite *BackendTestSuite) TestEthBlockByNumber() {
RegisterBlock(client, height, nil)
RegisterBlockResults(client, blockNum.Int64())
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
baseFee := sdk.NewInt(1)
RegisterBaseFee(queryClient, baseFee)
},
@ -1470,7 +1471,7 @@ func (suite *BackendTestSuite) TestEthBlockByNumber() {
RegisterBlock(client, height, bz)
RegisterBlockResults(client, blockNum.Int64())
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
baseFee := sdk.NewInt(1)
RegisterBaseFee(queryClient, baseFee)
},
@ -1535,7 +1536,7 @@ func (suite *BackendTestSuite) TestEthBlockFromTendermintBlock() {
TxsResults: []*types.ResponseDeliverTx{{Code: 0, GasUsed: 0}},
},
func(baseFee sdk.Int, blockNum int64) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
},
ethtypes.NewBlock(
@ -1570,7 +1571,7 @@ func (suite *BackendTestSuite) TestEthBlockFromTendermintBlock() {
},
},
func(baseFee sdk.Int, blockNum int64) {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.QueryClient)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBaseFee(queryClient, baseFee)
},
ethtypes.NewBlock(

View File

@ -7,11 +7,12 @@ import (
"fmt"
"math/big"
errorsmod "cosmossdk.io/errors"
rpctypes "github.com/cerc-io/laconicd/rpc/types"
ethermint "github.com/cerc-io/laconicd/types"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
"github.com/cosmos/cosmos-sdk/client/flags"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
@ -68,7 +69,7 @@ func (b *Backend) Resend(args evmtypes.TransactionArgs, gasPrice *hexutil.Big, g
}
for _, tx := range pending {
// FIXME does Resend api possible at all? https://github.com/cerc-io/laconicd/issues/905
// FIXME does Resend api possible at all? https://github.com/evmos/ethermint/issues/905
p, err := evmtypes.UnwrapEthereumMsg(tx, common.Hash{})
if err != nil {
// not valid ethereum tx
@ -150,7 +151,7 @@ func (b *Backend) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) {
syncCtx := b.clientCtx.WithBroadcastMode(flags.BroadcastSync)
rsp, err := syncCtx.BroadcastTx(txBytes)
if rsp != nil && rsp.Code != 0 {
err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog)
err = errorsmod.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog)
}
if err != nil {
b.logger.Error("failed to broadcast tx", "error", err.Error())
@ -268,6 +269,8 @@ func (b *Backend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Transac
Value: args.Value,
Data: input,
AccessList: args.AccessList,
ChainID: args.ChainID,
Nonce: args.Nonce,
}
blockNr := rpctypes.NewBlockNumber(big.NewInt(0))
@ -298,17 +301,19 @@ func (b *Backend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *rp
return 0, err
}
req := evmtypes.EthCallRequest{
Args: bz,
GasCap: b.RPCGasCap(),
}
_, err = b.TendermintBlockByNumber(blockNr)
header, err := b.TendermintBlockByNumber(blockNr)
if err != nil {
// the error message imitates geth behavior
return 0, errors.New("header not found")
}
req := evmtypes.EthCallRequest{
Args: bz,
GasCap: b.RPCGasCap(),
ProposerAddress: sdk.ConsAddress(header.Block.ProposerAddress),
ChainId: b.chainID.Int64(),
}
// From ContextWithHeight: if the provided height is 0,
// it will return an empty context and the gRPC query will use
// the latest block height for querying.
@ -328,10 +333,17 @@ func (b *Backend) DoCall(
if err != nil {
return nil, err
}
header, err := b.TendermintBlockByNumber(blockNr)
if err != nil {
// the error message imitates geth behavior
return nil, errors.New("header not found")
}
req := evmtypes.EthCallRequest{
Args: bz,
GasCap: b.RPCGasCap(),
ProposerAddress: sdk.ConsAddress(header.Block.ProposerAddress),
ChainId: b.chainID.Int64(),
}
// From ContextWithHeight: if the provided height is 0,

493
rpc/backend/call_tx_test.go Normal file
View File

@ -0,0 +1,493 @@
package backend
import (
"encoding/json"
"fmt"
"math/big"
"github.com/cerc-io/laconicd/rpc/backend/mocks"
rpctypes "github.com/cerc-io/laconicd/rpc/types"
"github.com/cerc-io/laconicd/tests"
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
"google.golang.org/grpc/metadata"
)
func (suite *BackendTestSuite) TestResend() {
txNonce := (hexutil.Uint64)(1)
baseFee := sdk.NewInt(1)
gasPrice := new(hexutil.Big)
toAddr := tests.GenerateAddress()
chainID := (*hexutil.Big)(suite.backend.chainID)
callArgs := evmtypes.TransactionArgs{
From: nil,
To: &toAddr,
Gas: nil,
GasPrice: nil,
MaxFeePerGas: gasPrice,
MaxPriorityFeePerGas: gasPrice,
Value: gasPrice,
Nonce: &txNonce,
Input: nil,
Data: nil,
AccessList: nil,
ChainID: chainID,
}
testCases := []struct {
name string
registerMock func()
args evmtypes.TransactionArgs
gasPrice *hexutil.Big
gasLimit *hexutil.Uint64
expHash common.Hash
expPass bool
}{
{
"fail - Missing transaction nonce ",
func() {},
evmtypes.TransactionArgs{
Nonce: nil,
},
nil,
nil,
common.Hash{},
false,
},
{
"pass - Can't set Tx defaults BaseFee disabled",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFeeDisabled(queryClient)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
ChainID: callArgs.ChainID,
},
nil,
nil,
common.Hash{},
true,
},
{
"pass - Can't set Tx defaults ",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterFeeMarketParams(feeMarketClient, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
},
nil,
nil,
common.Hash{},
true,
},
{
"pass - MaxFeePerGas is nil",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFeeDisabled(queryClient)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
MaxPriorityFeePerGas: nil,
GasPrice: nil,
MaxFeePerGas: nil,
},
nil,
nil,
common.Hash{},
true,
},
{
"fail - GasPrice and (MaxFeePerGas or MaxPriorityPerGas specified",
func() {},
evmtypes.TransactionArgs{
Nonce: &txNonce,
MaxPriorityFeePerGas: nil,
GasPrice: gasPrice,
MaxFeePerGas: gasPrice,
},
nil,
nil,
common.Hash{},
false,
},
{
"fail - Block error",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterBlockError(client, 1)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
},
nil,
nil,
common.Hash{},
false,
},
{
"pass - MaxFeePerGas is nil",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
GasPrice: nil,
MaxPriorityFeePerGas: gasPrice,
MaxFeePerGas: gasPrice,
ChainID: callArgs.ChainID,
},
nil,
nil,
common.Hash{},
true,
},
{
"pass - Chain Id is nil",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
MaxPriorityFeePerGas: gasPrice,
ChainID: nil,
},
nil,
nil,
common.Hash{},
true,
},
{
"fail - Pending transactions error",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
RegisterEstimateGas(queryClient, callArgs)
RegisterParams(queryClient, &header, 1)
RegisterParamsWithoutHeader(queryClient, 1)
RegisterUnconfirmedTxsError(client, nil)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
To: &toAddr,
MaxFeePerGas: gasPrice,
MaxPriorityFeePerGas: gasPrice,
Value: gasPrice,
Gas: nil,
ChainID: callArgs.ChainID,
},
gasPrice,
nil,
common.Hash{},
false,
},
{
"fail - Not Ethereum txs",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, baseFee)
RegisterEstimateGas(queryClient, callArgs)
RegisterParams(queryClient, &header, 1)
RegisterParamsWithoutHeader(queryClient, 1)
RegisterUnconfirmedTxsEmpty(client, nil)
},
evmtypes.TransactionArgs{
Nonce: &txNonce,
To: &toAddr,
MaxFeePerGas: gasPrice,
MaxPriorityFeePerGas: gasPrice,
Value: gasPrice,
Gas: nil,
ChainID: callArgs.ChainID,
},
gasPrice,
nil,
common.Hash{},
false,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
hash, err := suite.backend.Resend(tc.args, tc.gasPrice, tc.gasLimit)
if tc.expPass {
suite.Require().Equal(tc.expHash, hash)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestSendRawTransaction() {
ethTx, bz := suite.buildEthereumTx()
rlpEncodedBz, _ := rlp.EncodeToBytes(ethTx.AsTransaction())
cosmosTx, _ := ethTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
txBytes, _ := suite.backend.clientCtx.TxConfig.TxEncoder()(cosmosTx)
testCases := []struct {
name string
registerMock func()
rawTx []byte
expHash common.Hash
expPass bool
}{
{
"fail - empty bytes",
func() {},
[]byte{},
common.Hash{},
false,
},
{
"fail - no RLP encoded bytes",
func() {},
bz,
common.Hash{},
false,
},
{
"fail - unprotected transactions",
func() {
suite.backend.allowUnprotectedTxs = false
},
rlpEncodedBz,
common.Hash{},
false,
},
{
"fail - failed to get evm params",
func() {
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
suite.backend.allowUnprotectedTxs = true
RegisterParamsWithoutHeaderError(queryClient, 1)
},
rlpEncodedBz,
common.Hash{},
false,
},
{
"fail - failed to broadcast transaction",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
suite.backend.allowUnprotectedTxs = true
RegisterParamsWithoutHeader(queryClient, 1)
RegisterBroadcastTxError(client, txBytes)
},
rlpEncodedBz,
common.HexToHash(ethTx.Hash),
false,
},
{
"pass - Gets the correct transaction hash of the eth transaction",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
suite.backend.allowUnprotectedTxs = true
RegisterParamsWithoutHeader(queryClient, 1)
RegisterBroadcastTx(client, txBytes)
},
rlpEncodedBz,
common.HexToHash(ethTx.Hash),
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
hash, err := suite.backend.SendRawTransaction(tc.rawTx)
if tc.expPass {
suite.Require().Equal(tc.expHash, hash)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestDoCall() {
_, bz := suite.buildEthereumTx()
gasPrice := (*hexutil.Big)(big.NewInt(1))
toAddr := tests.GenerateAddress()
chainID := (*hexutil.Big)(suite.backend.chainID)
callArgs := evmtypes.TransactionArgs{
From: nil,
To: &toAddr,
Gas: nil,
GasPrice: nil,
MaxFeePerGas: gasPrice,
MaxPriorityFeePerGas: gasPrice,
Value: gasPrice,
Input: nil,
Data: nil,
AccessList: nil,
ChainID: chainID,
}
argsBz, err := json.Marshal(callArgs)
suite.Require().NoError(err)
testCases := []struct {
name string
registerMock func()
blockNum rpctypes.BlockNumber
callArgs evmtypes.TransactionArgs
expEthTx *evmtypes.MsgEthereumTxResponse
expPass bool
}{
{
"fail - Invalid request",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, bz)
RegisterEthCallError(queryClient, &evmtypes.EthCallRequest{Args: argsBz, ChainId: suite.backend.chainID.Int64()})
},
rpctypes.BlockNumber(1),
callArgs,
&evmtypes.MsgEthereumTxResponse{},
false,
},
{
"pass - Returned transaction response",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, bz)
RegisterEthCall(queryClient, &evmtypes.EthCallRequest{Args: argsBz, ChainId: suite.backend.chainID.Int64()})
},
rpctypes.BlockNumber(1),
callArgs,
&evmtypes.MsgEthereumTxResponse{},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
msgEthTx, err := suite.backend.DoCall(tc.callArgs, tc.blockNum)
if tc.expPass {
suite.Require().Equal(tc.expEthTx, msgEthTx)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *BackendTestSuite) TestGasPrice() {
defaultGasPrice := (*hexutil.Big)(big.NewInt(1))
testCases := []struct {
name string
registerMock func()
expGas *hexutil.Big
expPass bool
}{
{
"pass - get the default gas price",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
RegisterFeeMarketParams(feeMarketClient, 1)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, sdk.NewInt(1))
},
defaultGasPrice,
true,
},
{
"fail - can't get gasFee, FeeMarketParams error",
func() {
var header metadata.MD
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
RegisterFeeMarketParamsError(feeMarketClient, 1)
RegisterParams(queryClient, &header, 1)
RegisterBlock(client, 1, nil)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, sdk.NewInt(1))
},
defaultGasPrice,
false,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
suite.SetupTest() // reset test and queries
tc.registerMock()
gasPrice, err := suite.backend.GasPrice()
if tc.expPass {
suite.Require().Equal(tc.expGas, gasPrice)
} else {
suite.Require().Error(err)
}
})
}
}

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